1. 程式人生 > 遊戲 >《怪物獵人物語2:毀滅之翼》PC版新演示 戰鬥刺激

《怪物獵人物語2:毀滅之翼》PC版新演示 戰鬥刺激

java.lang.Object類 類Object是類層次結構的根(最頂層)類。每一類都是用Object作為超(父)類。所有物件(包括陣列)都實現這個類的方法。 String toString() 返回這個類的方法,列印物件的資訊。重寫前列印的是包名類名@地址值;重寫後列印的是物件中的屬性值。 直接列印物件名字其實就是呼叫物件的toString()方法p=p.toString(); 看一個類是否重寫了toString方法,直接列印這個類對應物件的名字即可,如果沒有重寫toString方法,那麼列印的就是物件的地址值(預設) 如果重寫toString方法,那麼就按照重寫的方法列印。 boolean equals(Object obj)指示其他某個物件是否與此物件"相等"。重寫前比較物件的地址值;重寫後比較的是物件中的屬性值。 Object類 equals方法的原始碼: public boolean equals(Object obj){ return (this == obj); } 引數:Object obj:可以傳遞任意的物件 方法體: ==:比較運算子,返回的就是一個布林值 true,false 基本型別比較值,引用型別比較物件的地址值 this是呼叫equals方法的那個物件,obj是傳過來的引數 Objects類的equals方法:對兩個物件進行比較,防止空指標異常。比較兩個物件是否相同,但是加了一些健壯性的判斷。
public static boolean equals(Object a, Object b) {return (a == b) || (a != null && a.equals(b));} java.util.Date:表示日期和時間的類 類Date表示特定的瞬間,精確到毫秒。 毫秒:千分之一秒 1000毫秒=1秒; 特定的瞬間:一個時間點,一剎那時間。 毫秒的作用:可以對時間和日期進行計算。 2099-01-03到2088-01-01中間一共多少天 可以日期轉換為毫秒進行計算,計算完畢,再把毫秒轉換成日期。 把日期轉換成毫秒: 當前的日期:2088-01-01 時間原點(0毫秒):1970年1月1日00:00:00(英國格林威治) 就是計算當前日期到時間原點之間一共經歷了多少毫秒(374267540068L) 注意: 中國屬於東八區,會把時間增加8個小時1970年1月1日08:00:00 把毫秒轉換成日期: 1天=24*60*60=68400秒=68400*1000=68400000毫秒 System.out.println(System.currentTimeMillis());//獲取當前系統時間到1970年1月1日00:00:00經歷了多少毫秒 Date類的空引數構造方法: Date()獲取的就是當前系統的日期和時間 Date類的帶引數構造方法: Date(long date)傳遞毫秒值(long型別值),把毫秒值轉化為Date日期。(從1970起) long getTime() 把日期轉換為毫秒(相當於System.CurrentTimeMillis()) 返回自1970年1月1日00:00:00GMT以來此Date物件表示的毫秒數。 String toLocalString(); 根據本地格式轉化日期物件。 不僅僅是Java,幾乎所有的語言的時間都是從這一刻開始算起的。原因:java起源於UNIX系統,而UNIX認為1970年1月1日0點是時間紀元。
java.text.DateFormat:是時間/日期格式化子類的抽象類 作用: 格式化(也就是日期->文字)、解析(文字->時間) 構造方法: SimpleDateFormat(String s); 根據指定模板傳進日期格式化物件。 成員方法: String format(Date date)按照指定的模式,把Date日期,格式化為符合模式的字串。 1.建立SimpleDateFormat物件,構造方法中傳遞的模式。 2.呼叫SimpleDateFormat物件中的format,按照構造方法中指定的模式,把Date日期格式化為符合模式的字串(文字) Date parse(String source)把符合模式的字串,解析為Date日期 1.建立SimpleDateFormat物件,構造方法中傳遞的模式。 2.呼叫SimpleDateFormat物件中的parse,把符合構造方法中模式的字串,解析為日期。 DateFormat類是一個抽象類,無法直接建立物件使用,但可以使用Dateformat的子類 java.text.SimpleDateFormat extends DateFormat 構造方法: SimpleDateFormat(String pattern) 用給定的模式和預設語言環境的日期格式符號構造SimpleDateFormat。 引數: String pattern:傳遞指定的模式 模式: 區分大小寫 y年 M月 d天 H時 m分 s秒 寫對應的模式,會把模式替換為對應的日期和時間"yyyy-MM-dd HH-mm-ss" "yyyy年MM月dd日 HH時mm分ss秒" 注意:模式中的字母不能更改,連線模式的符號可以更改。 java.util.Calendar類:日曆類 Calendar類是一個抽象類,裡面提供了很多操作日曆欄位的方法(YEAR、MONTH、DAY_OF_MONTH、HOUR) Calendar類無法直接建立物件使用,裡面有一個靜態方法叫getInstance(),該方法返回了Calendar類的子類物件 static Calendar getInstance() 使用預設時區和語言環境獲得一個日曆。 java.util.Calendar類的成員方法:
public int get(int field):返回給定日曆欄位的值。 public void set(int field,int value):將給定的日曆欄位設定為給定的值。(set有一個過載方法可以同時設定年月日) public abstract void add(int field,int amount):根據日曆的規則,為給定的日曆欄位新增或者減去指定的時間量。 int field:傳遞指定的日曆欄位 int amount:增加/減少的值(正、負) public Date getTime():返回一個表示此Calendar時間值(從曆元到現在的毫秒偏移量)的Date物件;將日曆物件轉換為日期物件。 java.lang.System類提供了大量的靜態方法,可以獲取與系統相關的資訊或系統級操作,在System類的API文件中,常用的方法有: public static long currenTimeMIllis():返回以毫秒為單位的當前時間。(返回的時間值可以當時間戳或者檔名進行使用) public static void arrayCopy(Object src,int srcPos,Object edst,int desPos,int length):將陣列中指定的 資料拷貝到另一個數組中。 java.lang.StringBuffer類 字串緩衝區,可以提高字串的操作效率(看成一個長度可以變化的字串) 底層也是一個數組,但是沒有被final修飾,可以改變長度: byte[] value=new byte[16]; StringBuilder在記憶體中始終是一個數組,佔用空間少,效率高。如果超出了StringBuilder的容量,會自動地擴容。 構造方法: public StringBuilder():構造一個空的StringBuiler容器; public StringBuilder(String str):構造一個StringBuiler容器,並將字串新增進去。 成員方法: public StringBuilder append(...):新增任意型別的字串形式,並返回當前物件自身。使用append方法無需接收返回值 引數:可以是任意型別。可以鏈式程式設計 StringBuilder reverse();反轉內容,使用reverse方法無需接收返回值 String toString();將快取區內容轉換為字串。 StringBuiler和String可以相互轉換: String-》StringBuilder :可以使用StringBuilder的構造方法StringBuilder(String str)構造一個字串生成器, 並初始化為指定的字串內容。 StringBuilder-》String:可以使用StringBuilder中的toString 方法 public String toString():當前StringBuilder物件轉換為String物件。 包裝類:基本資料型別的資料,使用起來非常地方便,但是沒有對應的方法來操作這些資料,所以我們可以使用一個類,把基本型別資料包裝起來, 這個類叫包裝類,在包裝類中可以定義一些方法,用來操作基本型別的資料。 裝箱:把基本型別的資料,包裝到包裝類中(基本型別的資料-》包裝類) 構造方法: Interger(int value) 構造一個新分配的Integer物件,它表示指定的int值 Integer(String s) 它表示String引數所指的int值; 傳遞的字串,必須是基本型別的字串否則會丟擲異常 靜態方法: static Integer valueOf(int i)返回一個表示指定的 int值的Integer例項 static String valueOf(String s) 返回儲存指定的String 的值的Integer物件。 拆箱:在包裝類中取出基本型別的資料(包裝類-》基本資料型別) 成員方法:int intValue() 以int型別返回該Integer的值。 自動裝箱與拆箱: 基本型別的資料和包裝類之間可以自動的相互轉換。JDK1.5之後出現的新特性。 自動裝箱:直接把int型別的整數賦值給包裝類: Integer in=1;就相當於 Integer in=new Integer(1); 自動拆箱:in是包裝類無法直接參與暈眩,可以自動轉換為基本型別的資料,再參與運算in+2;相當於in.inValue() +2=3; in=in+2;就相當於in=new Integer(3)自動裝箱 ArrayList集合無法直接儲存整數,可以儲存Integer包裝類 ArrayList<Integer> list=new ArrayList<>(); list.add(1);//自動裝箱相當於list.add(new Integer(1)); int a=list.get(0);//自動拆箱相當於 list.get(0).intValue(); 基本型別轉換為String: 方法一: 基本型別直接與""相連線即可;如:34+"" 方法二: 使用包裝類中的靜態方法 static String toString(int i)返回一個指定整數的String物件。 方法三:使用String類中的靜態方法: 使用包裝類中的靜態方法static String valueOf(int i)返回int引數的字串表示形式 String轉換成對應的基本型別:除了Character類之外,其他所有包裝類都具有parseXxx 靜態方法可以將字串引數轉換為對應的基本型別: Integer類: static int parseInt(String s)
集合和陣列的區別: 集合是java提供的一種容器,可以用來儲存多個數據。陣列的長度是固定的,集合的長度是可變的。 陣列中儲存的是同一種類型的元素,可以儲存基本資料型別值。集合儲存的都是物件。而物件的型別可以是不一致的。在開發中一般當物件多的時候,使用集合進行儲存。 集合框架的學習方式: 1.學習頂層介面/抽象類中共性的方法,所有子類都可以使用。 2.使用底層:頂層不是介面就是抽象類,無法建立物件使用底層的子類建立物件使用。 Collection介面 定義的是所有單列集合中共性的方法;所有的單列集合都可以使用共性的方法,沒有帶索引的方法。有兩個子介面List和Set List介面: 1.有序的集合(儲存和取出元素順序相同) 2.允許儲存重複的元素 3.有索引,可以使用普通的for迴圈遍歷 List介面中帶索引的方法(特有): public void add(int index,E element):將指定的元素新增到該集合指定的位置上。 public E get(int index):返回集合中指定位置的元素。 public E remove(int index):移除列表中指定位置的元素。返回的是被移除的元素。 public E set(int index,E element):用指定元素替換集合中指定位置的元素,返回值是更新前的元素。 注意:操作的時候,一定要小心索引越界 list集合遍歷有3種方式: 1.使用普通的for迴圈和get()方法 2.使用迭代器 3.使用增強for迴圈 Vector集合:JDK1.0版本,底層也是陣列實現,同步,單執行緒,比較慢 ArrayList集合 :底層是陣列實現的,查詢快增刪慢 ;不同步,多執行緒 LinkedList集合:底層是連結串列實現的,查詢慢,增刪快;不同步,多執行緒 裡面含有大量操作首尾元素的方法,使用LinkedList集合特有的方法不能使用多型 : public void addFirst(E e):將指定元素插入到此列表的開頭。 public void addLast(E e):將指定元素插入到此列表的結尾。相當於add() public void push(E e):將元素推入此列表所表示的堆疊。相當於addFirst() public E getFirst():返回此列表的第一個元素。 public E getLast():返回此列表的最後一個元素。 public E removeFirst():移除並返回此列表的第一個元素。 public E removeLast():移除並返回此列表的最後一個元素。 public E pop():從此列表所在的堆疊處彈出第一個元素。相當於removeFirst() public boolean isEmpty():如果列表不包含元素,則返回true。 public void clear():清空集合中的元素,再獲取集合中的元素會丟擲NoSuchElementException Set介面 1.不允許儲存重複元素 2.沒有索引(不能使用普通的for迴圈遍歷) 3.無序的集合(儲存和取出元素的順序有可能不一致) 遍歷方式:1.使用迭代器遍歷set集合 2.使用增強for迴圈遍歷set集合 TreeSet集合:底層是二叉樹實現的,一般用於排序 HashSet集合:底層是雜湊表+(紅黑樹)實現的,無索引,不可以儲存重複元素,存取無序;底層是一個雜湊表結構(查詢的速度非常的快) LinkedHashSet集合:底層是雜湊表+連結串列實現的,無索引,不可以儲存重複元素、可以保證儲存順序。 boolean add(E e): 向集合中新增元素 boolean remove(E e); 刪除集合中的某個元素; void clear(); 清空集合所有的元素 boolean contains(E e):判斷集合中是否包含某個元素。 boolean isEmpty(); 判斷集合是否為空 int size() : 獲取集合的長度 Object [] toArray(); 將集合轉換成一個數組 java.util.Iterator介面:迭代器(對集合進行遍歷) 兩個常用的方法: boolean hasNext() 如果仍有元素可以迭代,則返回true 判斷集合中還有沒有下一個元素,有就返回true,沒有就返回false; E next() 返回迭代的下一個元素。 取出集合中的下一個元素。(沒有元素,則會丟擲NoSuchElementException沒有元素異常) 它做了兩件事:1.取處下一個元素2.會把指標向後移動一位。 Iterator迭代器是一個介面,無法直接使用,需要使用Iterator介面的實現類物件,獲取實現類的方法比較特殊。 Collection介面中有一個方法,叫iterator(),這個方法返回的就是迭代器的實現類物件。 Iterator<E> iterator() 返回在此 collection 的元素上進行迭代的迭代器。獲取迭代器的實現類物件,並且會把指標(索引)指向集合的-1索引 迭代器的使用步驟: 1.使用集合中方法iterator() 獲取迭代器的實現類物件,使用Iterator介面接收(多型)。 Collecyion<E> coll=new ArrayList<E>(); Iterator<E> it=coll.iterator(); 2.使用Iterator介面中的方法hasNext判斷還有沒有下一元素。 3.使用Iterator介面中的方法next出集合中的下一個元素。 增強for迴圈:底層使用的也是迭代器,使用for迴圈的格式,簡化了迭代器的書寫,是JDK1.5之後出現的新特性。 Collection<E> extends Iterable<E>:所有單列集合都可以使用增強for迴圈 public interface Iterable<T> 實現這個介面允許物件成為"foreach"語句的目標;增強for迴圈:用來遍歷集合和陣列 格式:for(集合/陣列的資料型別 變數名:集合名/陣列名){ System.out.print(變數名); } 泛型:是一種位置的資料型別,當我們不知到使用什麼資料了型別的時候,可以使用泛型; 泛型也可以看出是一種變數,用來接收資料型別: E e:Element 元素 T t:Type 元素 ArrayList集合在定義的時候,不知道集合都會儲存什麼型別的資料,所以型別使用泛型。(不寫<E>預設為Object型別) 建立集合物件,使用泛型: 好處:1.避免了型別轉換的麻煩,儲存的是什麼型別,取出的就是什麼型別; 2.把執行期異常(程式碼執行之後會丟擲的異常),提升到了編譯期(寫程式碼的時候會報錯) 弊端:泛型是什麼型別,只能儲存什麼型別的資料。 建立集合物件,不使用泛型: 好處:集合不使用泛型,預設的型別就是Object型別,可以儲存任意型別的資料。 弊端:不安全,會引發異常。 比如向下轉型,呼叫子類方法出錯:String str=(String)obj; System.out.println(str.length()); java.base/java.lang.Integer cannot be cast to java.base/java.lang.String 定義一個含有泛型的類:public class GenericClass<E>{ private E name;...} 定義含有泛型的方法:泛型定義在方法的修飾符和返回值型別之間。 格式: 修飾符 <泛型> 返回值型別 方法名(引數列表(使用泛型)){方法體} public <M> void method01(M m){System.out.println(m);} 含有泛型的介面定義格式: 修飾符 interface 介面名<代表泛型的變數>{ } 例如: public interface MyInterface<E>{ public abstract void add(E e);} 含有泛型的介面,第一種使用方式:定義介面的實現類,實現介面,指定介面的泛型。 Scanner類實現了Iterator介面,並指定介面的泛型為String,所以重寫的next方法泛型預設就是String public final class Scanner implements Iterator<String>{ public String next(){...}} 含有泛型的介面,第二種使用方式:介面使用什麼泛型,實現類就使用什麼泛型,類跟著介面走,就相當於定義了含有泛型的類,建立 物件的時候確定泛型的型別。 public interface list<E>{ boolean add(E e); E get(int index); } public class ArrayList<E> implements list<E>{ public boolean add(E e){} public E get(int index){} } 泛型萬用字元: 當使用泛型萬用字元或著介面時,傳遞的資料中,泛型型別不確定,可以通過萬用字元<?>表示,但是一旦使用泛型的萬用字元後,只能使用Object類中的共性方法,集合元素自身方法無法使用。 只能接受資料,不能往該集合中儲存資料;不能建立物件使用,只能作為方法的引數使用(泛型沒有繼承的概念) 定義一個方法,能遍歷所有型別的ArrayList集合,這時候我們不知道ArrayLilst集合使用什麼資料型別,可以泛型的萬用字元?來接收資料型別 泛型的上限限定: ?extends E 代表使用的泛型只能是E型別的子類/本身 泛型的下限限定: ?super E 代表使用的泛型只能是E型別的父類/本身
資料結構: 棧:先進後出,入口和出口在同一側; 佇列:先進先出; 陣列:查詢快:陣列的地址是連續的,我們可以通過陣列的首地址找到陣列,通過陣列的索引可以快速查詢到某一個元素。 增刪慢:陣列的長度是固定的,我們要增加/刪除一個元素必須建立一個新陣列,把原陣列的資料複製過來,原陣列會在記憶體中被銷燬 在堆記憶體中,頻繁的建立陣列,複製陣列中的元素,銷燬陣列,效率低下 連結串列:查詢慢:連結串列中的地址不是連續的,每一次查詢元素,都必須從頭開始查詢 增刪快:連結串列結構,增加/刪除一個元素,對連結串列的整體結構沒有影響,所以增刪快。 連結串列中的每一個元素也稱之為一個節點,一個節點包含了一個數據源(儲存陣列),兩個指標域(儲存地址) 單向連結串列:連結串列中只有一條鏈子。不能保證有元素的順序(儲存元素和取出元素的順序有可能不一致)。 雙向連結串列:連結串列中有兩條鏈子,有一條是專門記錄元素的順序,是一個有序的集合 二叉樹:分支不能超過兩個 排序樹/查詢樹:猜數字小遊戲1-100之間的數字,從50開始猜,一下減去一半,在二叉樹的基礎上,元素是有大小順序的,左子樹小,右子樹大 平衡樹:左孩子和右邊孩子數相等。 不平衡樹:左孩子!=右孩子 紅黑樹: 特點趨於平衡樹,查詢的速度非常快,查詢葉子節點最大次數和最小次數不能超過2倍。 約束: 1.節點可以是紅色的或者是任意黑色的 2.根節點是黑色的。 3.葉子節點(空節點)是黑色的 4.每一個紅色的節點的子節點都是黑色的 5.任何一個節點到其每一個葉子節點的所有路徑上黑色節點數相同。 雜湊值:是一個十進位制的整數,由系統隨機給出(就是物件的地址值,是一個邏輯地址,是模擬出來的地址,不是資料儲存的邏輯地址)在Object類有一個方法,可以獲取物件的雜湊碼值。 int hashCode() 返回該物件的雜湊碼值。 hashCode方法的原始碼: public native int hashCode(); native:代表該方法呼叫的是本地作業系統的方法 String類的雜湊值:String類重寫Object類的hashCode方法。 toString方法中也用到了hashcode()方法:return getClass().getName+"@"+Integer.toNextString(hashCode()); HashSet集合儲存資料的結構(雜湊表) jdk1.8版本之前:雜湊表=陣列+連結串列 jdk1.8版本之後:雜湊表=陣列+連結串列; 雜湊表=陣列+紅黑樹(提高查詢的速度) 雜湊表的特點:速度快 儲存資料到集合中,先計算元素的雜湊值。 資料結構:把元素進行分組(相同雜湊值的元素是一組) 連結串列/紅黑樹 把相同雜湊值的元素連線到一起。 如果連結串列的長度超過了8位,那麼就會把連結串列轉換為紅黑樹(提高查詢的速度 ) set集合儲存元素不重複的前提:儲存的元素必須重寫hashCode方法和equals方法;Set集合在呼叫add方法的時候,add方法會呼叫元素的hashCode方法和equals方法,判斷元素是否重複,如果重複就不會儲存到集合中。 java.util.Collections是集合的工具類,用來對集合進行操作,部分方法如下: public static <T> boolean addAll(Collection<T> c,T...elements):往集合中新增一些元素。 public static void shuffle(List<?> list)打亂集合順序 public static <T> void sort(List<T> list):將集合中元素按照預設規則排序。 注意:sort(List<T> list)使用前提:被排序的集合裡面儲存的元素必須實現Comparable,重寫介面中comparable定義排序的規則。 Comparable介面的排序規則:自己(this)- 引數:升序 public static <T> void sort(List<T> list,Comparator<? super T>):將集合中元素按照指定規則排序。 Comparator和ComParable的區別: Comparable:自己(this)和別人(引數)比較,自己需要實現Comparable介面,重寫比較的規則compareTo方法 Comparator:相當於找到了一個第三方的裁判,比較兩個 Collections.sort(arr, new Comparator<People>() { @Override public int compare(People o1, People o2) { int result=o1.getAge()-o2.getAge(); if(result==0){ return o1.getName().charAt(0)-o2.getName().charAt(0); } return o1.getAge()-o2.getAge(); } });
getClass()返回Class型別的物件。返回的是記憶體中實實在在存在的 這個類本身 建立物件: Person p = new Person(1,”劉德華”); 返回Class型別的物件: Class c = p.getClass(); 此時c是Class型別,Class提供了一系列的方法來獲取類的相關資訊,可以通過物件c來獲取Person的資訊。比如,獲取Person這個類的類名。 HashSet儲存自定義型別,set集合保證元素唯一:儲存的元素(String,Integer,Student,Person),必須重寫hashCode方法和equals方法 java.util.LinkedHashSet集合 extends HashSet集合 LinkedHashSet集合特點: 底層是一個雜湊表(陣列+連結串列/紅黑樹)+連結串列:多了一條連結串列(記錄了元素的儲存順序),保證元素有序。 可變引數:是JDK1.5之後出現的新特性。 使用前提:定義方法時使用,當方法的引數列表資料型別已經確定,但是引數的個數不確定,就可以使用可變引數,使用格式: 修飾符 返回值型別 方法名(資料型別...變數名){} 可變引數原理:可變引數底層就是一個數組,根據傳遞引數個數不同,會建立不同長度的陣列,來儲存這些引數傳遞的引數個數,可以是0個(不傳遞), 1,2...多個。 注意事項:1.方法的引數列表,只能有一個可變引數。 2.如果方法的引數有多個,那麼可變引數必須寫在引數列表的末尾。 java.util.Map<K,V>集合介面 Map集合的特點:1.Map集合是一個雙列集合,一個元素包含兩個值(一個Key,一個Value)。 2.Map集合中的元素,key和value的集合資料型別可以相同,可以不同。 3.Map集合中的元素,key是不允許重複的,value是允許重複的。 4.Map集合中的元素,key和value是一一對應的。 java.util.HashMap<k,v>集合 implements Map<k,v>介面 HashMap集合的特點: 1.HashMap集合底層是雜湊表:查詢速度特別快。JDK1.8之前:陣列+單向連結串列 JDK1.8之後:陣列+單向連結串列/紅黑樹(連結串列長度超過8):提高查詢效率 2.HashMap集合是一個無序集合,存取元素順序可能不一致, java.util.LinkedHashMap<k,v>集合 extends HashMap<k,v>集合 LinkedHashMap集合的特點L : 1.LinkedHashMap集合底層是雜湊表+連結串列(保證迭代的順序) 2.LinkedHashMap集合是一個有序的集合,儲存元素和取出元素的順序是一致的 Map集合的方法: public V put(Key k,V value):把指定的鍵和指定的值新增到Map集合中。 返回值:V 儲存鍵值對的時候,key不重複,返回值V是null。key重複,會使用新的value替換map中重複的value,返回被替換的value值 public V remove(Object key):把指定的鍵 所對應的鍵值元素在Map集合中刪除,返回被刪除元素的值。 返回值:V key存在,返回被刪除的元素,key不存在,返回null public V get(Object key):根據指定的鍵,在Map集合中獲取對應的值。 返回值:key存在返回對應的value;key不存在返回null boolean containsKey(Object key):判斷集合中是否包含指定的鍵。包含返回true,不包含返回false。 Map集合的第一種遍歷方式:通過鍵找值的方式 Map集合中的方法: Set<K> keySet() 返回此對映中包含的鍵的Set檢視。 實現步驟:1.使用Map集合中的方法keySet(),把Map集合中所有的key取出來,儲存到一個set集合中 2.遍歷set集合,獲取Map集合中的每一個key 3.使用迭代器/增強for,通過Map集合中的方法get(key),通過key找value Map.Entry<K,V>:在Map介面中有一個內部介面Entry 作用:當Map集合一建立,那麼就會在Map集合中建立一個Entry物件,用來記錄鍵與值(鍵值對物件,鍵與值的對映關係)--》結婚證 Set<Map.Entry<K,V>> entrySet()把Map集合內部的多個Entry物件取出來儲存到一個Set集合中。 遍歷Set集合獲取Set集合中的每一個Entry物件。 Entry物件中的方法:getKey()獲取key getValue()獲取value Set<Map.Entry<String,Integer>> set1=map.entrySet(); for (Map.Entry<String,Integer> entries: set1){ System.out.println(entries.getKey()); System.out.println(entries.getValue()); } Map集合遍歷的第二種方式:使用Entry物件遍歷: Map集合中的方法:Set<Map.Entry<K,V>> entrySet() 返回此對映中包含的對映關係的Set檢視。 實現步驟: 1.使用Map集合中的方法entrySet(),把Map集合中多個Entry物件取出來,儲存到一個Set集合中 2.遍歷Set集合,獲取每一個Entry物件。(用迭代器/增強for迴圈) 3.使用Entry物件中的方法getKey()和getValue()獲取鍵與值。 HashMap儲存自定義型別鍵值:Map集合保證key是唯一的:作為key的元素,必須重寫hashCode方法和equals方法,以保證key唯一。 java.util.HashTable<K,V>集合 implements Map<K,V>介面 Hashtable:底層也是一個雜湊表,是一個執行緒安全的集合,是單執行緒集合,速度慢。 HashMap:底層是一個雜湊表,是一個執行緒不安全的集合,是多執行緒集合,速度快。 HashMap集合(之前學的所有集合):可以儲存null值,null鍵 HashTable集合,不能儲存null值,null鍵 Hashtable和Vector集合一樣,在jdk1.2版本之後被更先進的集合(HashMap,ArrayList)取代了 HashTable 的子類Properties依然活躍在歷史舞臺; Properties集合是一個唯一和IO流相結合的集合。 JDK9.0的新特性: List介面,Set介面,Map介面:裡面增加了一個靜態方法of,可以給集合一次性新增多個元素。 static <E> List<E> of (E...elements) 使用前提:當前集合中儲存的元素的個數已經確定了,不在改變時使用。 注意: 1.of方法只適用於List介面,Set介面,Map介面,不適用於介面的實現類。 2.of方法的返回值是一個不能改變的集合,集合不能在使用add,put方法新增元素,會丟擲異常 UnsupportedOperationException:不支援操作異常 3.Set介面和Map介面在呼叫of方法的時候,不能有重複的元素,否則會丟擲IllegalArgumentException非法引數異常,有重複的元素。 Debug:除錯程式: 可以讓程式碼逐行執行,檢視程式碼執行的過程,除錯程式中出現的bug 使用方式: 在行號的右邊,滑鼠左鍵單擊,新增斷點(每個方法的第一行,哪裡有bug新增到哪裡) 右鍵,選擇Debug執行程式。 程式就會停留在新增的第一個斷點處 執行程式: f8:逐行執行程式 f7:進入到方法中 shift+f8:跳出方法 f9:跳到下一個斷點,如果沒有下一個斷點,如果沒有下一個斷點就結束程式。 Ctrl+f2:退出Debug模式,退出程式。 Console:切換到控制檯
【【異常】】 java.lang.Throwable:類是 Java語言中所有資料錯誤或異常的超類。 Exception:編譯器異常,進行編譯(寫程式碼)java程式出現錯誤 RuntimeExcepiton:執行期異常,java程式執行過程中出現的問題。 Error:錯誤 錯誤就相當於程式得到一個無法治癒的毛病,必須修改原始碼程式才能正常執行。 訪問陣列中的3索引,而陣列是沒有3索引的,這時候,JVM就會檢測程式 會出現異常。 (1)JVM會做兩件事: 1.JVM會提供異常產生的原因建立一個異常物件,這個異常物件包含了異常產生的(內容,原因,位置) 2.在方法中,沒有異常的處理邏輯(try...catch),那麼JVM就會把異常物件丟擲給方法的呼叫者main方法來處理異常。 (2)如果main方法接受到了這個異常物件,main方法也沒有異常的處理邏輯,則繼續會把物件丟擲main方法的呼叫者JVM處理。 (3)JVM接受到了這個異常物件,做了兩件事:1.把異常物件(內容,原因,位置)以紅色的字型列印在控制檯 2.JVM會終止當前正在執行的java程式--》中斷處理 throw關鍵字: 作用:可以用throw關鍵字在指定的方法中丟擲指定的異常。 使用格式:throw new xxxException("異常產生的原因"); 注意: 1.throw關鍵字必須寫在方法的內部。 2.throw關鍵字後邊new的物件必須是Exception或者Exception的子類物件。 3.throw關鍵字丟擲指定的異常物件,我們就必須處理這個物件。 throw關鍵字後邊建立的是RuntimeException或是 RuntimeException的子類物件,我們可以不處理,預設交給JVM處理(列印異 常物件,中斷程式) throw關鍵字後邊建立的是編譯異常(寫程式碼的時候報錯),我們就必須處理這個異常,要麼throws,要麼try...catch FileNotFoundException是編譯異常,就必須處理這個異常。 Objects類中的靜態方法 public static <T> T requireNonNull(T obj):檢視指定引用物件不是null。 原始碼: public static <T> T requireNonNull(T obj){ if(obj==null) thorw new NullPointerException(); return obj; } } throws關鍵字:異常處理的第一種方式,交給別人處理。 作用:當方法內部丟擲異常物件的時候(使用了throw),那麼我們就必須處理這個異常物件。 可以使用throws關鍵字處理異常物件,會把異常物件宣告丟擲給方法的呼叫者處理(自己不處理,給別人處理),最終交給JVM處理-->中斷處理 使用格式:在方法宣告時使用 修飾符 返回值型別 方法名(引數列表) throws AAAException,BBBException...{ throw new AAAException("產生原因"); throw new BBBException("產生原因"); ... } 注意: 1.throws關鍵字必須寫在方法的宣告處。 2.throws關鍵字後面宣告的異常必須是Exception或者是Exception的子類。 3.方法內部如果丟擲了多個異常物件,那麼throws後邊必須也宣告多個異常。如果丟擲的多個異常物件有子父類關係,那麼直接宣告父類異常即可 4.呼叫了一個宣告拋處異常的方法,我們就必須處理宣告的異常,要麼繼續使用throws宣告丟擲,交給方法的呼叫著處理,最終交給JVM;要麼用 try...catch自己處理異常。 try...catch:異常處理的第二種方式,自己捕獲處理異常。 格式: try{ 可能產生的異常的程式碼 }catch(異常類名 變數名){ ... } 注意: 1.try可能會丟擲多個異常物件,那麼就可以使用多個catch來處理這些異常物件 2.如果try中產生了異常,那麼就會執行catch中的異常處理邏輯,執行完畢catch中的處理邏輯,繼續執行try...catch之後的程式碼。 如果try中沒有產生異常,那麼就不會執行catch中異常的處理邏輯,執行完try中的程式碼,繼續執行try...catch之後的程式碼。 finally程式碼塊 格式: try{ 可能產生異常的程式碼 }catch(定義一個異常的變數,用來接收try中丟擲的異常物件){ 異常處理邏輯,異常物件之後,怎麼處理異常物件。 }finally{ 無論是否出現異常都會執行 } 注意:1.finally不能單獨使用,必須和try一塊使用 2.finally一般用於資源釋放(資源回收),無論程式是否出現異常,最後都要資源釋放(IO) 當返回值不是基本資料型別的時候,其是指向一段記憶體的,return將返回段指向一段記憶體,但是程式碼段的s依然是指向的同一段記憶體地址,所以當s修改它指向記憶體中的值的時候,其實也就修改了返回段指向記憶體中的值,所以最終的值改變了。 到底返回值變不變可以簡單的這麼記憶:當finally呼叫的任何可變API,會修改返回值;當finally呼叫任何的不可變API,對返回值沒有影響。 其實return與finally並沒有明顯的誰強誰弱。在執行時,是return語句先把返回值寫入記憶體中,然後停下來等待finally語句塊執行完,return再執行後面的一段。 如果finally有return語句,永遠返回finally中的結果,避免該情況。 Throwable類中定義了3個異常處理的方法(寫在catch的{}中) String getMessage() 返回此 throwable的簡短描述。 String toString() 返回此 throwable 的詳細訊息字串。 void printStackTrace() JVM列印異常物件,預設此方法,列印的異常資訊是最全面的。 多個異常使用捕獲又該如何處理? 1.多個異常分別處理 2.多個異常一次捕獲,多次處理 3.多個異常一次捕獲一次處理。 子父類異常: -如果父類方法丟擲了多個異常,子類重寫父類方法時,丟擲和父類相同的異常或者時父類異常的子類或者不丟擲異常。 -父類方法沒有丟擲異常,子類重寫父類該方法時也不可丟擲異常,此時子類產生該異常,只能捕獲處理,不能宣告丟擲。 注意: 父類異常時什麼樣,子類異常什麼樣 自定義型別異常: java提供的異常類,不夠我們使用,需要自己定義一些異常。 格式: public class XXXException extends Exception | RuntimeException{ 新增一個空引數的構造方法 public XXXException(){} 新增一個帶異常資訊的構造方法//檢視原始碼發現,所有的異常都會有一個帶異常資訊的構造方法,方法內部會呼叫父類帶異常資訊的構造方法,讓父類來處理這個異常資訊。 public XXXException(String message){super(message);} 注意:1.自定義異常類名字一般都是以Exception結尾,說明該類是一個異常類。 2.自定義異常類,必須繼承Exception或者RuntimeException 繼承Exception:那麼自定義的異常類就是一個編譯期異常,如果方法內部丟擲了編譯期異常,就必須處理這個異常,要麼throws,要麼try...catch 繼承RuntimeException:那麼自定義的異常類就是一個執行期異常,無需處理,交給虛擬機器處理(中斷處理) 併發:指兩個或多個事件在同一個時間段內發生。(交替執行) 並行:指兩個或多個事件同時刻發生。(同時執行) 硬碟永久儲存ROM,記憶體臨時儲存RAM 程序:進入到記憶體中的程式,所有的應用程式都要進入到記憶體中執行 線成:屬於程序,是程序中的一個執行單元,負責程式的執行。 cpu:中央處理器 對資料進行計算,指揮電腦中軟體和硬體幹活 分類: 單核 多核 8執行緒:同時執行8個任務 線成排程: 分時排程:所有執行緒輪流使用CPU的使用權,平均分配給每個執行緒佔用CPU的時間。 搶佔式排程:優先讓優先順序高的執行緒使用CPU,如果執行緒的優先順序相同,那麼會隨機選擇一個(線成隨機性),java使用的為搶佔式排程。 單執行緒程式:java程式中只有一個程式,執行從main方法開始,從上到下依次執行。 JVM執行main方法,main方法會進入到棧記憶體,JVM會找作業系統開闢一條main方法通向CUP的執行路徑,CPU就可以通過這個路徑來執行main方法,而這個路徑有一個名字叫main(主)執行緒。 Thread類 構造方法: public Thread():分配一個新的執行緒物件。 public Thread(String name):分配一個指定名字的新的執行緒物件。 常用方法: public void run():此執行緒要執行的任務在此處定義程式碼。 public static void sleep(long millis):使當前正在執行的執行緒以指定的毫秒數暫停(暫時停止執行)。(millis毫秒) 建立多執行緒程式的第一種方式:建立Thread類的子類 java.lang.Thread類:是描述執行緒的類,我們想要實現多執行緒程式,就必須繼承thread類 實現步驟: 1.建立一個Thread類的子類 2.在Thread類的子類中重寫Thread類中run方法,設定線成任務(開啟線成要做什麼) 3.建立Thread類的子類物件 4.呼叫Thread類中的方法start方法,開啟新的執行緒 ,執行run方法 public void start() 使該執行緒開始執行;java虛擬機器呼叫該執行緒的run方法,結果是兩個線成併發的執行;當前執行緒(main線成)和另一個線成(建立的新執行緒,執行其run方法)。多次啟動一個執行緒是非法的,特別是執行緒已經執行結束後,不能重新啟動。 守護執行緒
JVM執行main方法,開啟OS開闢一條main方法通向cpu的路徑,這個路徑叫main執行緒,主執行緒,cup通過這個執行緒,這個路徑可以執行main方法。 對於cpu而言,就有了兩條執行的路徑,cpu就有了選擇的權力,cpu喜歡誰,就會執行哪條路徑,我們控制不了cpu,所以就有了程式的隨即列印結果, 兩個執行緒搶奪cpu執行權(執行時間)誰搶到了誰執行對應的程式碼 建立一個執行緒物件就在記憶體中開闢了新的棧空間,執行run()方法;多執行緒的好處:多個執行緒之間互不應影響(在不同的棧空間) 獲取執行緒的名稱: 1.使用Thread類中方法 String getName() 返回該執行緒的名稱。 2.可以先獲取當前正在執行的執行緒,使用執行緒中的方法getName()獲取執行緒的名稱: 使用在Thread類中static Thread currentThread()返回當前正在執行的執行緒物件的引用。 設定執行緒的名稱:(瞭解) 1.使用Thread類中的方法setName(名字) void setName(String name):改變執行緒名稱,使之與引數 name 相同 2.建立一個帶引數的構造方法,引數傳遞執行緒的名稱;呼叫父類的帶參構造方法,把執行緒名稱傳遞給父類,讓父類(Thread)給子執行緒起一個名字。 建立多執行緒程式的第二種方式:實現Runnable介面 java.lang.Runnable Runnable介面應該由那些打算通過某一執行緒執行其例項的類來實現,類必須定義一個稱為run()無參方法。 java.lang.Thread類的構造方法 Thread(Runnable target): 分配新的Thread物件。 Thread(Runnable target,String name):分配新的物件。 實現步驟: 1.建立一個Runnable介面的實現類 2.在實現類中重寫Runnable介面的run方法,設定執行緒任務。 3.建立一個Runnable介面實現類的物件 4.建立Thread類物件,構造方法中傳遞Runnable介面的實現類物件。 5.呼叫Thread類中start方法,開啟新的執行緒執行run方法。 RunnableImpl r=new RunnableImpl(); Thread t=new Thread(r); t.start(); 實現Runnable介面建立多執行緒程式的好處: 1.避免單繼承的侷限性。 一個類只能有一個父類,類繼承了Thread類就不能繼承其他的類。如果實現Runnable介面,還可以繼承其他的類或介面。 2.增強了程式的擴充套件性,降低了程式的耦合性(解耦) 實現Runnable介面的方式,把設定執行緒任務和開啟新執行緒進行了分離(解耦),實現類中,重寫了run方法:用來設定執行緒任務。建立Thread類物件,呼叫start方法:用來開啟新執行緒。 匿名內部類方式實現執行緒的建立。 匿名:沒有名字 內部類:寫在其他類內部的類 匿名內部類的作用:簡化程式碼 把子類繼承父類,重寫父類的方法,建立子類物件合成一步完成。 把實現類 實現介面,重寫介面中的方法,建立實現類物件一步完成。 匿名內部類的最終產物:子類/實現類物件,而這個類沒有名字。 格式: new 父類/介面(){} new Thread() { @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println("黑馬"+i); } } }.start(); Runnable r=new Runnable() { @Override public void run(){ for (int i = 0; i < 20; i++) { System.out.println("傳智播客"+i); } } }; new Thread(r).start(); 單執行緒程式是不會出現執行緒安全問題的;多執行緒程式,沒有訪問共享資料,不會產生問題;多執行緒訪問了共享的資料,會產生執行緒安全問題。 執行緒安全問題是不能產生的,我們可以讓一個執行緒在訪問共享資料的時候,無論是否失去了cpu的執行權,其他的執行緒只能等待,等待當前執行緒用完共享資料,其他執行緒才能訪問共享資源。 解決執行緒安全問題的一種方案:使用同步程式碼塊 格式: synchronized(鎖物件){ 可能會出現執行緒安全問題的程式碼(訪問了共享資料的程式碼) } 注意: 1.通過程式碼塊中的鎖物件,可以使用任意的物件。 2.但必須保證多個執行緒使用的鎖物件是同一個 3.鎖物件的作用:把同步程式碼塊鎖住,只讓一個執行緒在同步程式碼塊中執行。 同步技術的原理:使用了一個鎖物件叫同步鎖,也叫物件鎖,也叫物件監視器。同步中的執行緒沒有執行完畢不會釋放鎖,同步外的執行緒沒有鎖進不去同步(進入阻塞狀態)。 同步保證了只能有一個執行緒在同步中執行共享資料,保證了安全,程式頻繁的判斷鎖,獲取鎖,釋放鎖,程式的效率會降低。 解決執行緒安全問題的第二種方案:使用同步方法: 使用步驟: 1.把訪問了共享資料的程式碼抽取出來,放到一個方法中 2.在方法上新增synchronized修飾符 格式:定義方法的格式 修飾符 synchronized 返回值型別 方法名(引數列表){ 可能會出現執行緒安全問題的程式碼(訪問共享資料的程式碼) } 定義一個同步方法:同步方法也會把方法內部的程式碼鎖住,只讓一個執行緒執行;同步方法的鎖物件就是 實現類物件,也就是this 靜態的同步方法:鎖物件不能是this,this是建立物件之後產生的,靜態方法優先於物件;靜態方法的鎖物件是本類的class屬性--》class檔案物件(反射) 方法被static修飾,synchronized在方法中或者方法中有synchronized同步程式碼塊。 解決執行緒安全問題的第三種方案:使用lock鎖 java.util.concurrent.locks.lock介面 Lock的實現類提供了比使用 synchronized方法和語句可獲得的更廣泛的鎖定操作。 Lock介面中的方法: void lock() 獲取鎖 void unlock 釋放鎖 java.util.concurrent.locks.Reentrantlock implements lock介面 使用步驟: 1.在成員位置建立一個Reentrantlock物件 2.在可能會出現安全問題的程式碼前呼叫lock介面中的方法lock獲取鎖。 3.在可能會出現安全問題的程式碼後呼叫lock介面中的方法unlock釋放鎖(儘量寫在finally{}裡面) 執行緒六種狀態: 新建狀態 NEW至今尚未啟動的執行緒處於這種狀態。 執行狀態 RUNNABLE 正在java虛擬機器中執行的執行緒處於這種狀態 阻塞狀態 BLOCKED受阻塞並等待某個監視器鎖的執行緒處於這種狀態。 無限(永久)等待狀態 WAITING 無線期地等待另一個執行緒來執行某一特定操作的執行緒處於這種狀態。 休眠(睡眠)狀態 TIMED_WAITING 等待另一個執行緒來執行,取決於指定等待時間的操作的 執行緒處於這種狀態, 死亡狀態 TERMINATED 已經退出的執行緒處於這種狀態。 阻塞狀態:具有cpu的執行資格,等待cpu空閒時執行; 休眠狀態:放棄cpu的執行資格,cpu空閒,也不執行
等待喚醒案例:執行緒之間的通訊 建立一個客戶執行緒(消費者),告訴老闆要的包子的種類和數量,呼叫wait方法,放棄cpu的執行,進入到WAITING狀態(無限等待)。 建立一個老闆執行緒(生產者),花費5秒做包子,做好包子之後,呼叫motify方法,喚醒顧客吃包子。 注意: 顧客和老闆執行緒必須使用同步程式碼塊包裹起來,保證等待和喚醒只能有一個在執行。 同步使用鎖物件必須保證唯一;只有鎖物件才能呼叫wait和notify方法。 Object類中的方法: void wait(): 在其他執行緒中用此物件的notify() 方法或 notifyAll() 方法前,導致當前執行緒等待。 void notify(): 喚醒在此物件監視器上等待的單個執行緒,會繼續執行wait()方法之後的程式碼。 進入到TimeWaiting(計時等待)有兩種方式: 1.使用sleep(long m)方法,在毫秒值結束之後,執行緒睡醒進入到Runnable/Blocked狀態。 2.使用wait(long m)方法,wait方法如果在毫秒值結束之後,還沒有被notify喚醒,就會自動醒來,執行緒睡醒進入到Runnable/Blocked狀態 喚醒的方法: void notify() 喚醒在此物件監視器上等待的單個執行緒。 void notifyAll() 喚醒在此物件監視器上等待的所有執行緒。 執行緒間的通訊:多個執行緒在處理同一個資源,但是處理的動作(執行緒的任務) 卻不相同。 為什麼要處理執行緒間的通訊: 多個執行緒併發執行時,在預設情況下CPU是隨機切換執行緒的,當我們需要多個執行緒來共同完成一件任務,並且我們希望他們有規律的執行,那麼多執行緒之間需要一些協調通訊,以此來幫助我們達到多執行緒共享操作一份資料。 如何保證執行緒間通訊有效利用資源: 多個執行緒處理同一個資源,並且任務不同時,需要執行緒通訊來幫助解決執行緒之間對同一個變數的使用或操作。就是多個執行緒在操作同一份資料時,避免對同一共享變數的爭奪。也就是我們需要通過一定的手段使各個執行緒能有效的利用資源。而這種手段即--“等待喚醒機制” wait/notify 就是一種協作機制,呼叫wait()和notify()方法需要注意的細節: 1.wait方法與notify方法必須要由同一個鎖物件呼叫。因為:對應的鎖物件可以通過notify喚醒使用同一個鎖物件呼叫的wait方法後的執行緒。 2.wait方法與notify方法是屬於Object類的方法的,因為:鎖物件可以是任意物件,而任意物件所屬類都是繼承了Object類的。 3.wait方法與notify方法必須要在同步程式碼塊或者是同步函式中使用。因為:必須要通過鎖物件呼叫這兩個方法。 如果併發的執行緒數量很多,並且每個執行緒都是執行一個時間很短的任務就結束了,這樣頻繁建立執行緒就會大大降低系統的效率,因為頻繁建立執行緒和銷燬執行緒需要時間。在JDK1.5之後,JDK內建了執行緒池,我們可以直接使用。 執行緒池:容納多個執行緒的容器,其中的執行緒可以反覆被使用,省去了頻繁建立執行緒物件的操作,無需反覆建立執行緒而消耗過多資源。 合理利用執行緒池能夠帶來三個好處: 1.降低資源消耗,減少了建立和銷燬執行緒的次數,每個工作執行緒都可以被重複利用,可執多個任務。 2.提高響應速度。當任務達到時,任務可以不需要的等到執行緒建立就能立即執行。 3.提高執行緒的可管理性。可以根據系統的承受能力,調整執行緒池中工作執行緒的數目,防止因為消耗過多的記憶體,而把服務期累趴下(每個執行緒需要大約1MB記憶體,執行緒開的越多,消耗的記憶體也就越大,最後宕機)。 執行緒池:JDK1.5之後提供的 java.util.concurrent.Executors:執行緒池的工廠類,用來生成執行緒池。 Executors類中的靜態方法: static ExecutorService newFixedThreadPool(int nThreads) 建立一個可重用固定執行緒數的執行緒池 引數: int nThreads:建立執行緒池中包含的執行緒數量。 返回值:ExecutorService介面,返回的是ExecutorsService介面的實現類物件,我們可以使用ExecutorService介面接收(面向介面程式設計) java.util.concurrent.ExecutorService:執行緒池介面 用來從執行緒池中獲取執行緒,呼叫start方法,執行執行緒任務 submit(Runnable task)提交一個Runnable 任務用於執行 關閉/撤銷執行緒池的方法: void shutdown() 執行緒池的使用步驟: 1.使用執行緒池的工廠類Executors裡邊提供的靜態方法newFixedThreadPool生產一個指定執行緒數量的執行緒池。 2.建立一個類,實現Runnable介面,重寫run方法,設定執行緒任務。 3.呼叫ExecutorService中的方法Submit,傳遞執行緒任務(實現類),開啟執行緒,執行run方法 4.呼叫ExecutorService中的方法shutdown銷燬執行緒池(不建議執行)
Lambda表示式函數語言程式設計思路 面向物件的思想:做一件事情,找一個能解決這個事情的物件,呼叫物件的方法,完成事情。 函數語言程式設計思想:只要能獲取到結果,誰去做,怎麼做的都不重要;重視的是結果,不重視過程。
new Thread(new Runnable(){
public void run(){
System.out.println(Thread.currentThread().getName());
}
}).start();
藉助Java8的全新語法,上述Runnable介面的匿名內部類寫法可以通過更簡單的Lambda表示式達到等效:
new Thread(
()->{
System.out.println(Thread.currentThread().getName());
}
).start();

Lambda表示式的標準格式(無參無返回值):
由三部分組成:
a.一些引數 b.一個箭頭 c.一段程式碼
格式: (引數列表) -> {一些重寫方法的程式碼};
解釋說明格式:
():介面中抽象方法的引數列表,沒有引數,就空著;有引數就寫出引數,多個引數使用逗號分隔;
->:傳遞的意思,把引數傳遞給方法體;
{}:重寫介面的抽象方法的方法體

有參有返回值:
 /*  Arrays.sort(arr, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge()-o2.getAge();
}
});*/
Arrays.sort(arr,(o1,o2)->{
return o1.getAge()-o2.getAge();
});

public static void main(String[] args) {
invockCal(20, 30, new Calculator() {
@Override
public int add(int a, int b) {
return a+b;
}
});
invockCal(30,50,(a,b)->{
return a+b;
});
}
public static void invockCal(int a,int b,Calculator c){
System.out.println(c.add(a,b));
}


Lambda表示式:是可推導,可以省略的。
凡是根據上下文推匯出來的內容,都可以省略不寫。
可以省略的內容:   1.(引數列表):括號中引數列表的資料型別,可以省略不寫。
               2.(引數列表):括號中的引數如果只有一個,那麼型別和()都可以省略。
               3.{一些程式碼}:如果{}中的程式碼只有一行,無論是否有返回值,都可以省略({},return,分號)。
            注意:要省略{},return,分號必須同時省略。
Lambda的語法非常的簡潔,完全沒有面向物件複雜的束縛,但是使用時有幾個問題需要特別注意:
  1.使用Lambda必須具有介面,且要求介面中有且僅有一個抽象方法。
     無論是JDK內建的Runnable、Comparator介面還是自定義的介面,只有當介面中的抽象方法存在且唯一時,才可以使用Lambda。
  2.使用lambda必須具有上下文推斷。
    也就是方法的引數或區域性變數型別必須為Lambda對應的介面型別,才能使用Lambda作為介面的例項。
    備註:僅有一個抽象方法的介面,稱為“函式式介面”


java.io.File類 :檔案和目錄路徑名的抽象表示形式。 java把電腦中的檔案和資料夾(目錄)封裝成為一個File類,我們可以使用File類對檔案和資料夾進行操作 我們可以使用File類的方法: 建立一個檔案/資料夾 刪除檔案/資料夾 獲取檔案/資料夾 判斷檔案/資料夾是否存在 對資料夾進行遍歷 獲取檔案的大小 File類是一個與系統無關的類,任何作業系統都可以使用這個類中的方法 File:檔案 directory:資料夾/目錄 path:路徑
staticString pathSeparator
與系統有關的路徑分隔符,為了方便,它被表示為一個字串。
staticchar pathSeparatorChar
與系統有關的路徑分隔符。
staticString separator
與系統有關的預設名稱分隔符,為了方便,它被表示為一個字串。
staticchar separatorChar
與系統有關的預設名稱分隔符。
路徑分隔符: windows:分號; Linux:冒號: 檔名稱分隔符: windows:反斜槓\ Linux:正斜槓/ 操作路徑路徑不能寫死 C:\develop\a\a.txt windows C:/develop/a/a.txt Linux "C:"+File.separator+"develop"+File.separator+a+File.separator+"a.txt" 路徑: 絕對路徑:是一個完整的路徑 以碟符(c:,D;)開始的路徑 c:\\a.txt C:\\User\itcast\\IdeaProjects\\shungyuan\\123.txt D:\\demo\\b.txt 相對路徑:是一個簡化的路徑 相對是指相對於當前專案的根目錄(C:\\User\itcast\\IdeaProjects\\shungyuan) 如果使用當前專案的根目錄,路徑可以簡化書寫 C:\\User\itcast\\IdeaProjects\\shungyuan\\123.txt-->簡化為:123.txt(可以省略專案的根目錄) 注意: 1.路徑是不區分大小寫的。 2.路徑長得檔名稱分隔符windows使用反斜槓,反斜槓是轉義字元,兩個反斜槓代表一個普通的反斜槓 File(Stringpathname)通過將給定路徑名字串轉換為抽象路徑名來建立一個新File例項。 引數: String pathname:字串的路徑名稱 路徑可以是以檔案結尾,也可以是以資料夾結尾;路徑可以是相對路徑也可以是絕對路徑 路徑可以是存在的也可以是不存在的;建立File物件,只是把字串路徑封裝為File物件,不考慮路徑的真假情況。 File(Stringparent,Stringchild)
根據 parent 路徑名字串和 child 路徑名字串建立一個新File例項。 引數: 把路徑拆分成兩個部分 String parent:父路徑 String child:子路徑 好處:父路徑和子路徑單獨書寫,使用起來非常靈活;父路徑和子路徑都可以變化 File(Fileparent,Stringchild)
根據 parent 抽象路徑名和 child 路徑名字串建立一個新File例項。 引數: 把路徑拆分成兩個部分 File parent:父路徑 String child:子路徑 好處: 父路徑和子路徑,可以單獨書寫,使用起來非常靈活,父路徑和子路徑都可以變化 File(URIuri)
通過將給定的file:URI 轉換為一個抽象路徑名來建立一個新的File例項。 方法: public String getAbsolutePath() :返回此File的絕對路徑名字串。 獲取的構造方法中傳遞的路徑。 無論路徑是絕對路徑還是相對路徑,getAbsolutePath方法返回的都是絕對路徑。

public String getPath()
將此抽象路徑名轉換為一個路徑名字串。所得字串使用預設名稱分隔符分隔名稱序列中的名稱。

返回:此抽象路徑名的字串形式

toString方法呼叫的就是getPath方法 原始碼:public string tostring(){ return getPath(); }

public String getName():返回由此抽象路徑名錶示的檔案或目錄的名稱。該名稱是路徑名名稱序列中的最後一個名稱。如果路徑名名稱序列為空
則返回空字串。

返回:此抽象路徑名錶示的檔案或目錄的名稱;如果路徑名的名稱序列為空,則返回空字串

public long length()
返回由此抽象路徑名錶示的檔案的長度。注意資料夾沒有大小的概念,不能獲取資料夾的大小。如果構造方法給出的路徑不存在,那麼leng方法返回0
返回:
此抽象路徑名錶示的檔案的長度,以位元組為單位;如果檔案不存在,則返回0L。對於表示特定於系統的實體(比如裝置或管道)的路徑名,某些作業系統可能返回0 L
public boolean exists() :此File表示的檔案或目錄是否實際存在,用於判斷構造方法中的路徑是否存在: 存在:true 不存在:false public boolean isDirectory():此File表示的是否為目錄。用於判斷構造方法中給定的路徑是否以資料夾結尾。 public boolean isFile(): 此File表示的是否為檔案。用於判斷構造方法中給定的路徑是否以檔案結尾。 注意:電腦硬碟中只有檔案和資料夾,兩個方法是互斥的。這兩個方法使用的前提,路徑必須是存在的,否則都返回false。 public boolean createNewFile() :當且僅當具有該名稱的檔案尚不存在時,建立一個新的空檔案。 建立檔案的路徑和名稱在構造方法中給出(構造方法的引數)路徑相對和絕對都可以 返回值:布林值 true:檔案不存在,建立檔案,返回true false:檔案存在,不會建立,返回false 注意: 1.此方法只能建立檔案,不能建立資料夾 2.建立檔案的路徑必須存在,否則會丟擲異常。
public boolean createNewFile() throws IOException
createNewFile宣告丟擲了IOException。我們呼叫這個方法,就必須處理這個異常,要麼使用throws,要麼使用try...catch

public boolean mkdir(): 建立單級資料夾
public boolean mkdirs(): 既可以建立單級空資料夾,也可以建立多級資料夾,建立資料夾的路徑和名稱在構造方法中給出(構造方法的引數)
返回值:布林值
true: 資料夾不存在,建立資料夾,返回true
false:資料夾存在,不會建立,返回false;構造方法中給出的路徑不存在返回false
注意:此方法只能建立資料夾,不能建立檔案
public boolean delete():刪除由此File表示的檔案或目錄。此方法可以刪除構造方法路徑中給出的檔案/資料夾
返回值:布林值
檔案/資料夾刪除成功,返回true; 資料夾中有內容,不能刪除返回false; 構造方法中路徑不存在返回false
delete方法時直接在硬碟刪除檔案/資料夾,不能走回收站,刪除要謹慎。

file類遍歷(資料夾)目錄功能
public String[] list():返回一個String陣列,表示該File目錄中的所有子檔案或目錄。
遍歷構造方法給出的目錄,會獲取目錄中所有檔案/資料夾的名稱,把獲取到的多個名稱儲存到一個String型別的陣列中。
public File[] listFiles():返回一個File陣列,表示該File目錄中的所有的子檔案或目錄。
遍歷構造方法給出的目錄,會獲取目錄中所有檔案/資料夾,把檔案/資料夾封裝為File物件,多個File物件儲存到File陣列中。
注意:
list方法和listFiles方法遍歷的時構造方法中給出目錄。如果構造方法中給出的目錄的路徑不存在,會丟擲空指標異常;
如果構造方法中給出的路徑不是一個目錄,也會丟擲空指標異常。

recursion
遞迴的分類:
-遞迴分為兩種,直接遞迴和間接遞迴。直接遞迴稱為方法自身呼叫自身;間接遞迴可以A方法呼叫B方法,B方法呼叫C方法,C方法呼叫A方法。
注意事項:
遞迴一定要有條件限定,保證遞迴能夠停止下來,否則會發生棧記憶體溢位。
在遞迴中雖然有限定條件,但是遞迴次數不能太多,否則也會發生棧記憶體溢位。
構造方法,禁止遞迴,編譯錯誤:構造方法是建立物件使用的,一直遞迴會導致記憶體中有無數多個物件,直接編譯報錯。
遞迴的使用前提:當呼叫方法的時候,方法的主體不變,每次呼叫方法的引數不同,可以使用遞迴。
注意:當一個方法呼叫其他方法的時候,被呼叫的方法沒有執行完畢,當前方法會一直等待呼叫的方法執行完畢,才會繼續執行。

使用遞迴求和,main方法呼叫sum方法,sum方法會一直呼叫sum遞迴,導致在記憶體中有多個sum方法(頻繁的建立方法,呼叫發放,銷燬方法)效率低
使用遞迴必須明確:
1.遞迴的結束條件 2.遞迴的目的

//遞迴列印多級目錄
public static void getAllFile(File dir){
System.out.println(dir);//列印被遍歷的目錄名稱
File[] files=dir.listFiles();
for (File d:files) {
//對遍歷得到的File物件d進行判斷,判斷是否是資料夾
if(d.isDirectory()){
//d是一個資料夾,則繼續遍歷這個資料夾。
//我們發現getAllFile方法就是傳遞資料夾,遍歷資料夾的方法。
//所以直接使用getAllFile方法即可:遞迴(自己呼叫自己)
getAllFile(d);
}else{
System.out.println(d);
}
}
}

在File類中有兩個和ListFiles過載的方法,方法的引數傳遞的就是過濾器。
File[] listFiles(FileFilter filter)
java.io.FileFilter 介面:用於抽象路徑名(File物件)的過濾器。
作用:用來過濾檔案(File物件)
抽象方法:用來過濾檔案的方法
boolean accept(File pathname):測試只當抽象路徑名是否應該包含在某個路徑名列表中。
引數:
File pathname:使用ListFiles方法遍歷目錄,得到的每一個檔案物件

File[] listFiles(FilenameFilter filter)
java.io.FilenameFilter介面:實現此介面的類例項可用於過濾器檔名。
作用:用於過濾檔名稱
抽象方法:用於過濾檔案的方法
boolean accept(File dir,String name):測試指定檔案是否應該包含在某一檔案列表中。
引數: File dir:File構造方法中傳遞的被遍歷的目錄
String name:使用ListFiles方法遍歷目錄,獲取的每一個檔案/資料夾的名稱
注意:兩個過濾器介面是沒有實現類的,需要我們自己寫實現類,重寫過濾的方法accept,在方法中自己定義過濾的規則。

必須明確兩件事:1.過濾器中的accept方法是誰呼叫的 2.accept方法引數pathname是什麼?
accept方法返回值是一個布林值;true:就會把傳遞過去的File物件儲存到File陣列中;false:就不會把傳遞過去的File物件儲存到File陣列中
listFiles方法一共做了3件事:
1.listFiles方法對構造方法中傳遞的目錄進行遍歷,獲取目錄中每一個檔案/資料夾--》封裝成File物件
2.listFiles方法會呼叫引數傳遞的過濾器中的方法accept
3.listFiles方法會把遍歷得到的每一個File物件,傳遞給accept方法的引數pathname


【【流】】
java.io.OutputStream:位元組輸出流
此抽象類是表示輸出位元組流的所有類的超類。

定義了一些子類共性的成員方法:
-public void close():關閉此輸出流並釋放與此流相關聯的任何系統資源。
-public void flush():重新整理此輸出流並強制任何緩衝的輸出位元組被寫出。
-public void write(byte[] b):將b.length位元組從指定的位元組陣列寫入此輸出流。
一次寫多個位元組是正數(0~127),那麼顯示的時候會查詢ASCII表
如果第一個位元組是負數,那麼第一個位元組會和第二個位元組,兩個位元組組成一箇中文顯示,查詢系統預設碼錶。
-public void write(byte[] b,int off,int len):從指定的位元組陣列寫入len位元組,從偏移量off開始輸出到此輸出流。
-public abstract void write(int b):將指定的位元組輸出流。

java.io.FileOutputStream extends OutputStream
FileOutputStream:檔案位元組輸出流 作用:把記憶體中的資料寫入到硬碟的檔案中。

構造方法:
FileOutputStream(String name):創造一個向具有指定路徑名稱的檔案中寫入資料的輸出檔案流。
FileOutputStream(File file):建立一個向指定File物件表示的檔案中寫入資料的檔案輸出流。
引數:寫入資料的目的
String name:目的地是一個檔案的路徑。
File file:目的地是一個檔案。
構造方法的作用:
1.建立一個FileOutputStream物件
2.會根據構造方法中傳遞的檔案/檔案路徑,建立一個空的檔案。
3.會把FileOutputStream物件指向建立好的檔案。

寫入資料的原理(記憶體->硬碟)
java程式--》JVM(java虛擬機器)--》OS(作業系統)--》OS呼叫寫資料的方法--》把資料寫到檔案中
位元組輸出流的使用步驟:
1.建立一個FileOutputStream物件,構造方法中傳遞寫入資料的目的地。
2.呼叫FileOutputStream物件中的方法write,把資料寫入到檔案中。
3.釋放資源(流使用會佔用一定的記憶體,使用完畢要把記憶體清空,提高程式的效率)
FileNotFoundException異常是IOException異常的子類。

寫資料的時候,會把10進位制的整數轉化成二進位制的;硬碟中儲存的資料都是位元組 1個位元組=8個位元位
任意的文字編輯器(記事本,notepad++)在開啟檔案的時候,都會查詢編碼表,把位元組轉化為字元表示
0~127:查詢ASCII表 97-》a
其他值:查詢系統預設碼錶(中文系統GBK)
在檔案中寫100 寫三個位元組
UTF-8中三個位元組是一箇中文 GBK中兩個位元組表示一箇中文
寫入字元的方法:可以使用String類中的方法把字串轉換為位元組陣列 byte[] getBytes() 把字串轉換為位元組陣列

追加寫/續寫:使用兩個引數的構造方法
FileOutputStream(String name,boolean append):建立一個向具有指定name的檔案中寫入資料的輸出檔案流。
FileOutputStream(File file,boolean append):建立一個向指定File物件表示的檔案中寫入資料的檔案輸出流。
引數:
String name,File file:寫入資料的目的地
boolean append:追加寫開關
true:建立物件不會覆蓋原檔案,繼續在檔案的末尾追加寫資料。
false:建立一個新檔案,覆蓋原檔案。
寫換行:寫換行符號
windows:\r\n
linux:/n
mac:/r

java.io.InputStream:位元組輸入流 此抽象類是表示位元組輸入流的所有類的超類。
定義了所有子類共性的方法:
int read() 從輸入流中讀取資料的下一個位元組。讀到檔案的末尾返回-1。
int read(byte[] b):從輸入流中讀取一定數量的位元組,並將其儲存在緩衝區陣列b中。
void close() 關閉此輸入流並釋放與該流相關聯的所有系統資源。

java.io.FileInputStream extends InputStream
FileInputStream:檔案位元組輸入流 作用:把硬碟檔案中的資料,讀取到記憶體中使用。
構造方法:
FileInputStream(String name)
FileInputStream(File file)
引數:讀取檔案的資料來源
String name:檔案的路徑 File file : 檔案
構造方法的作用:
1.會建立一個FileInputStream物件
2.會把FileInputStream物件指向構造方法中要讀取的檔案。
讀取資料的原理(硬碟-->記憶體)
java程式-->JVM-->OS-->OS讀取資料的方法-->讀取檔案

位元組輸入流的使用步驟:
1.建立FileInputStream物件,構造方法中繫結要讀取的資料來源。
2.使用FileInputStream物件中的方法read,讀取檔案
3.釋放資源。
intlen=0;//記錄讀取到的位元組
while((len=fis.read())!=-1){
System.out.println((char)len);
}

位元組輸入流一次讀取多個位元組的方法:
int read(byte[] b) 從輸入流中讀取到一定數量的位元組,並將其儲存在緩衝區陣列b中。
明確兩件事情:
1.方法的引數byte[]的作用?
起到緩衝作用,儲存每次讀取到的多個位元組。陣列的長度一般定義為1024(1kb)或者1024的整倍數
2.方法的返回值int是每次讀取的有效位元組個數。
String(byte[] bytes):把位元組陣列轉化為字串
String(byte[] bytes,int offset,int length):把位元組陣列的一部分轉化為字串 offset:陣列的開始索引 length:轉換的位元組個數。
  
檔案複製的步驟:
1.建立一個位元組輸入流物件,構造方法中繫結要讀取的資料來源
2.建立一個位元組輸入流物件,構造方法中繫結要寫入的目的地。
3.使用位元組輸入流物件中的方法read讀取檔案。
4.使用位元組輸出流中方法write,把讀取到的位元組寫入到目的地的檔案中。
5.釋放資源。
FileInputStream fis = new FileInputStream("C:\\IdeaProjects\\com.itheima\\b.txt");
FileOutputStream fos = new FileOutputStream("C:\\IdeaProjects\\com.itheima\\c.txt");
byte[] b=new byte[1024];
int len = 0;
while ((len = fis.read(b)) != -1) {
fos.write(b,0,len);//讀多少寫多少
}
//釋放資源,(先關閉寫的,再關閉讀的,如果寫完了,肯定讀完了)
fos.close();
fis.close();
java.io.Reader:字元輸入流,是字元輸入流的最頂層的父類,定義了一些共性的成員方法,是一個抽象類 共性的成員方法: int read() 讀取單個字元並返回 int read(char[] cbuf):一次讀取多個字元,將字元讀入陣列。 void close() 關閉該流並釋放與之關聯的所有資源。
java.io.FileReader extends InputSreamReader extends Reader
FileReader:檔案字元輸入流。 作用:把硬碟檔案中的資料以字元的方式讀取到記憶體中。 構造方法: FileReader(String fileName) 檔案的路徑 FileReader(File file) 一個檔案 引數:讀取檔案的資料來源 FileReader構造方法的作用: 1.建立一個FilReader物件 2.會把FileReader物件指向要讀取的檔案 字元輸入流的使用步驟:
1.建立FileReader物件,構造方法中繫結要讀取的資料來源 2.使用FileReader物件中的方法read讀取去的資料來源 3.釋放資源。 java.io.Writer:字元輸出流,是所有字元輸出流的最頂層的父類,是一個抽象類。 共性的成員方法:
Writer append(charc)
將指定字元新增到此 writer。
Writer append(CharSequencecsq)
將指定字元序列新增到此 writer。
Writer append(CharSequencecsq, intstart, intend)
將指定字元序列的子序列新增到此 writer.Appendable
abstract void
abstract void flush()
重新整理該流的緩衝。
void write(char[]cbuf)
寫入字元陣列。
abstract void write(char[]cbuf, intoff, intlen)
寫入字元陣列的某一部分。
void write(intc)
寫入單個字元。
void write(Stringstr)
寫入字串。
void write(Stringstr, intoff, intlen)
寫入字串的某一部分。
java.io.FileWriter extends OutputStreamWriter extends Writer FileWriter:檔案字元輸出流 作用:把記憶體中字元資料寫入到檔案中。 構造方法: FileWriter(Filefile)根據給定的 File 物件構造一個 FileWriter 物件。 FileWriter(StringfileName)根據給定的檔名構造一個 FileWriter 物件。 構造方法的作用: 1.創造FileWriter物件。 2.會根據構造方法中傳遞的檔案/檔案的路徑,建立檔案。 3.會把FileWriter物件指向建立好的檔案。 字元輸出流的使用步驟: 1.建立FileWriter物件,構造方法中繫結要寫入資料的目的地 2.使用FileWriter中的方法writer,把資料寫入到記憶體緩衝區中(字元轉換為位元組的過程) 3.使用FileWriter中的方法flush。把記憶體緩衝區中的資料,重新整理到檔案中。 4.釋放資源(會先把記憶體緩衝區中的資料重新整理到檔案中) flush方法和close方法的區別 -flush:重新整理緩衝區,流物件可以繼續使用 -close:先重新整理緩衝區,然後通知系統釋放資源,流物件不可以再被使用了 續寫和換行 續寫:追加寫:使用兩個引數的構造方法 FileWriter(String fileName,boolean append) FileWriter(File file,boolean append) 引數:
String name,File file:寫入資料的目的地
boolean append:追加寫開關
true:建立物件不會覆蓋原檔案,繼續在檔案的末尾追加寫資料。
false:建立一個新檔案,覆蓋原檔案。
寫換行:寫換行符號
windows:\r\n
linux:/n
mac:/r
再jdk1.7之前使用try catch finally 處理流中的異常 格式: try{ 可能會產出異常的程式碼 }catch(異常類變數 變數名){ 異常的處理邏輯 }finally{ 一定會執行的程式碼 資源釋放 }

//提高變數fw的作用域,讓finally可以使用
//變數在定義的時候,可以沒有值,但是使用的時候必須有值
FileWriter fw = null;
try {
//可能會產出異常的程式碼
fw = new FileWriter("C:\\IdeaProjects\\com.itheima\\c.txt", true);
for (int i = 0; i < 10; i++) {
fw.write("HelloWorld" + i + "\r\n");
}
} catch (IOException e) {
//異常處理邏輯
System.out.println(e);
} finally {
//一定會執行的程式碼
//建立物件失敗了,fw的預設值為null,null是不能呼叫方法的,會丟擲NullPointerException,需要增加一個判斷,不是null把資源釋放
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
JDK7的新特性 在try的後邊可以增加一個(),在括號中可以定義流物件,那麼這個流物件的作用域就在try{}中有效。 try中的程式碼執行完畢,會自動把程式碼釋放,不用寫finally 格式: try(定義流物件;定義流物件....){ 可能會產生的異常程式碼 }catch(異常類變數 變數名){ 異常的處理邏輯 }
//不用關流
try (
FileInputStream fis = new FileInputStream("C:\\IdeaProjects\\com.itheima\\b.txt");
FileOutputStream fos = new FileOutputStream("C:\\IdeaProjects\\com.itheima\\c.txt");
) {
byte[] b = new byte[1024];
int len = 0;
while ((len = fis.read(b)) != -1) {
fos.write(b, 0, len);
}
} catch (IOException e) {
System.out.println(e);
}
JDK9新特性 在try的前邊可以定義流物件;在try後邊的()中可以直接引入流物件的名稱(變數名) 在try程式碼執行完畢之後,流物件也可以釋放掉,不用寫finally 格式: A a=new A(); B b=new B(); try(a,b){ 可能會產出異常的程式碼 }catch{ 異常的處理邏輯 }
  //自動關流
public static void main(String[] args) throws FileNotFoundException {
FileInputStream fis = new FileInputStream("C:\\IdeaProjects\\com.itheima\\b.txt");
FileOutputStream fos = new FileOutputStream("C:\\IdeaProjects\\com.itheima\\c.txt");

try (fis; fos) {
byte[] b = new byte[1024];
int len = 0;
while ((len = fis.read(b)) != -1) {
fos.write(b, 0, len);
}
} catch (IOException e) {
System.out.println(e);
}

}
}
java.util.Properties集合 extends Hashtable<k,v> implements Map<k,v> Properties 類表示一個持久化的屬性集,Properties可儲存在流中或從流中載入。 Properties集合是一個唯一和IO流相結合的集合 可以使用Properties集合中的方法store,把集合中的臨時資料,持久化寫入到硬碟中儲存。 可以使用Properties集合中的方法load,把硬碟中儲存的檔案(鍵值對),讀取到集合中使用。 屬性列表中每一個鍵及其對應值都是一個字串。 Properties集合是一個雙列集合,key和value預設都是字串。 使用Properties集合儲存資料,遍歷取出Properties集合中的資料。 Properties集合是一個雙列集合,key和value預設都是字串。 Properties集合有一些操作字串的特有方法: setProperty(Stringkey,Stringvalue)呼叫Hashtable的方法putgetProperty(Stringkey)用指定的鍵在此屬性列表中搜索屬 stringPropertyNames()返回此屬性列表中的鍵集,其中該鍵及其對應值是字串,如果在主屬性列表中未找到同名的鍵,則還包括預設屬性列 表中不同的鍵。 可以使用Properties集合中的方法store,把集合中的臨時資料,持久化寫入到硬碟中儲存。 void store(OutputStream out,String comments) void store(Writer writer,String comments) 引數: OutputStream out:位元組輸出流,不能寫入中文。 Writer writer:字元輸出流,可以寫中文。 String comment:註釋,用來解釋說明儲存的檔案是做什麼用的,不能使用中文,會產生亂碼,預設是Unicode編碼,一般使空“”字串 使用步驟: 1.建立Properties集合物件,新增資料。 2.建立位元組輸出流/字元輸出流物件,構造方法中繫結要輸出的目的地。 3.使用Properties集合中的方法store,把集合中的臨時資料,持久化寫入到硬碟中儲存。 4.釋放資源。匿名建立的位元組輸出流/字元輸出流物件會自動關閉,不用close 可以使用Properties集合中的方法load,把硬體中儲存的檔案(鍵值對),讀取到集合中使用 void load(InputStream inStream) void load(Reader reader) 引數: InputStream inStream :位元組輸入流,不能讀取含有中文的鍵值對 Reader reader :字元輸出流,能讀取含有中文的鍵值對 使用步驟: 1.建立Properties集合物件 2.使用Properties集合物件中的方法load讀取儲存鍵值對的檔案 3.遍歷Properties集合 注意: 1.儲存鍵值對的檔案中,鍵與值預設的連線符號可以使用-,空格(其他符號) 2.儲存鍵值對的檔案中,可以使用#進行註釋,備註是的鍵值對不會再被讀取。 3.儲存鍵值對的檔案中,鍵與值預設都是字串,不用再加引號。
位元組緩衝輸入流 給基本的位元組輸入流增加一個緩衝區(陣列)提高基本的位元組輸入流的讀寫效率 java.io.BufferedOutputStream extends OutputStream BufferedOutputStream:位元組緩衝輸出流 繼承自父類的共性成員方法: -public void close():關閉此輸出流並釋放與此流相關聯的任何系統資源。
-public void flush():重新整理此輸出流並強制任何緩衝的輸出位元組被寫出。
-public void write(byte[] b):將b.length位元組從指定的位元組陣列寫入此輸出流。
一次寫多個位元組是正數(0~127),那麼顯示的時候會查詢ASCII表
如果第一個位元組是負數,那麼第一個位元組會和第二個位元組,兩個位元組組成一箇中文顯示,查詢系統預設碼錶。
-public void write(byte[] b,int off,int len):從指定的位元組陣列寫入len位元組,從偏移量off開始輸出到此輸出流。
-public abstract void write(int b):將指定的位元組輸出流。 構造方法: BufferedOutputStream(OutputStreamout): 建立一個新的緩衝輸出流,以將資料寫入指定的底層輸出流。 BufferedOutputStream(OutputStreamout, intsize)建立一個新的緩衝輸出流,以將具有指定緩衝區大小的資料寫入指定的底層輸出流。 引數: OutputStream out:位元組輸出流 我們可以傳遞FileOutputStream,緩衝流會給FileOutputStream增加一個緩衝區,提高FileOutputStream的寫入效率。 int size:指定緩衝流內部緩衝區的大小,不指定預設 使用步驟: 1.建立FileOutputStream物件,構造方法中繫結要輸出的目的地。 2.建立BufferedOutputStream物件,構造方法中傳遞FileOutputStream物件,提高FileOutputStream物件效率。 3.使用BufferedOutputStream物件中的方法write,把資料寫入到內部緩衝區中。 4.使用BufferedOutputStream物件中的方法flush,把內部緩衝區中的資料,重新整理到檔案中。 5.釋放資源(會先呼叫flush方法重新整理資料,第四步可以省略) public classBufferedInputStreamextendsFilterInputStream BufferedInputStream:位元組緩衝輸入流 繼承自父類的成員方法: int read():從輸入流中讀取資料的下一個位元組。 int read(char[] cbuf):一次讀取多個字元,將字元讀入陣列。 void close() 關閉該流並釋放與之關聯的所有資源。 構造方法: BufferedInputStream(InputStreamin) 建立一個BufferedInputStream並儲存其引數,即輸入流in,以便將來使用。 BufferedInputStream(InputStreamin, intsize)建立具有指定緩衝區大小的BufferedInputStream並儲存其引數,即輸入流in,以 便將來使用。 引數: InputStream in:位元組輸入流 我們可以傳遞FileInputStream,緩衝流會給FileInputStream增加一個緩衝區,提高FileInputStream的讀寫效率。 int size :指定緩衝流內部緩衝區的大小,不指定預設。 使用步驟: 1.建立FileInputStream物件,構造方法中繫結要讀取的資料來源。 2.建立BufferedInputStream物件,構造方法中傳遞FileInputStream物件,提高FileInputStream物件的讀寫效率。 3.使用BufferedInputStream物件中的方法read,讀取檔案。 4.釋放資源。 java.io.BufferedWriterextendsWriter BufferedWriter :字元緩衝輸出流 繼承自父類的共性成員方法:
void close()
關閉此流,但要先重新整理它。
void flush()
重新整理該流的緩衝。
void newLine()
寫入一個行分隔符。
void write(char[]cbuf, intoff, intlen)
寫入字元陣列的某一部分。
void write(intc)
寫入單個字元。
void write(Strings, intoff, intlen)
寫入字串的某一部分。
構造方法:
BufferedWriter(Writerout)
建立一個使用預設大小輸出緩衝區的緩衝字元輸出流。
BufferedWriter(Writerout, intsz)
建立一個使用給定大小輸出緩衝區的新緩衝字元輸出流。
引數: Writer out:字元輸出流 我們可以傳遞FileWriter,緩衝流會把FileWriter增加一個緩衝區,提高FileWriter的寫入效率。 int sz:指定緩衝區的大小,不寫預設大小。 特有的成員方法:
void newLine() 寫入一個行分隔符。
換行:換行符號 window:\r\n Linux:/n mac:/r 使用步驟: 1.建立字元緩衝輸出流物件,構造方法中傳遞字元輸出流。 2.呼叫字元緩衝輸出流中的方法write,把資料寫入到記憶體緩衝區中。 3.呼叫字元緩衝輸出流中的方法flush,把記憶體緩衝區中的資料,重新整理到檔案中。 4.釋放資源。 java.io.BufferedReaderextends Reader 繼承自父類的共性成員方法: int read() 讀取單個字元並返回 int read(char[] cbuf):一次讀取多個字元,將字元讀入陣列。 void close():關閉該流並釋放與之相關聯的所有資源。 構造方法: BufferedReader(Readerin)建立一個使用預設大小輸入緩衝區的緩衝字元輸入流。 BufferedReader(Readerin, intsz)建立一個使用指定大小輸入緩衝區的緩衝字元輸入流。 引數: Reader in:字元輸入流 我們可以傳遞FileReader,緩衝流會給FileReader增加一個緩衝區,提高FileReader的讀取效率。 特有的成員方法: String readLine() 讀取一個文字行。讀取一行資料。while迴圈遍歷,讀取到null結束,返回null 行的終止符號:通過下列字元之一即可認為行已禁止;換行('\n')、回車('\r')或回車後直接跟著換行(\r\n)。 返回值: 包含該行內容的字串,不包含任何行終止符,如果已到達流末尾,則返回null 使用步驟: 1.建立字元緩衝輸入流物件,構造方法中傳遞字元輸入流。 2.使用字元緩衝輸入流物件中的方法read/readLine讀取文字 3.釋放資源。 字元編碼:就是一套自然語言的字元與二進位制之間的對應規則。 編碼表:生活中文字和計算機中二進位制的對應規則。 編碼: 字元(能看懂)——》位元組(看不懂的) 解碼: 位元組(看不懂的)——》字元(能看懂的) FileReader讀取專案中的文字檔案時,由於IDEA的設定,都是預設的UTF-8編碼,Window系統預設的都是GBK編碼,所以會出現亂碼。 java.io.OutputStreamwriter extends Writer OutputStreamWriter:是字元通向位元組的橋樑,可以使用指定的charset,將要寫入流中的字元編碼成位元組。 繼承自父類的共性成員方法:
void close()
關閉此流,但要先重新整理它。
void flush()
重新整理該流的緩衝。
String getEncoding()
返回此流使用的字元編碼的名稱。
void write(char[]cbuf, intoff, intlen)
寫入字元陣列的某一部分。
void write(intc)
寫入單個字元。
void write(Stringstr, intoff, intlen)
寫入字串的某一部分。
構造方法: OutputStreamWriter(OutputStream out)建立使用預設字元編碼的OutputStreamWriter。 OutputStreamWriter(OutputStream out,String charsetName)建立使用指定的字符集的OutputStreamWriter。 引數: OutputStream out:位元組輸出流,可以用來寫轉換之後的位元組到檔案中。 String charsetName:只當的編碼表名稱,不區分大小寫,可以是UTF-8/utf-8,gbk/GBK,...不指定預設使用UTF-8. 使用步驟: 1.建立OutputStreamWriter物件,構造方法中傳遞字元輸出流和指定的編碼表名稱。 2.使用OutputStreamWriter物件中的方法Writer,把字元轉換成位元組儲存緩衝區中。 3.使用OutputStreamWriter物件中的方法flush,把記憶體緩衝區中的位元組重新整理到檔案中(使用位元組流寫位元組的過程)。 4.釋放資源。 java.io.InputStreamReader extends Reader InputStreamReader:是位元組流通向字元流的橋樑,它使用指定的charset讀取位元組並將其解碼為字元。 繼承自父類的共性方法:
void close()
關閉該流並釋放與之關聯的所有資源。
String getEncoding()
返回此流使用的字元編碼的名稱。
int read()
讀取單個字元。
int read(char[]cbuf, intoffset, intlength)
將字元讀入陣列中的某一部分。
boolean ready()
判斷此流是否已經準備好用於讀取。
構造方法:
InputStreamReader(InputStreamin)
建立一個使用預設字符集的 InputStreamReader。
InputStreamReader(InputStreamin,Charsetcs)
建立使用給定字符集的 InputStreamReader。
引數: InputStreamReader in:位元組輸入流,用來讀取檔案中儲存的位元組。 String charsetWriter:指定的編碼表名稱,不區分大小寫,可以是utf-8/UTF-8,gbk/GBK,...不指定預設使用utf-8 使用步驟: 1.建立InputStreamReader物件,構造方法中傳遞字元輸入流和指定的編碼表名稱。 2.使用InputStreamReader物件中的方法read讀取檔案。 3.釋放資源。 注意事項: 構造方法中只當的編碼表名稱要和檔案的編碼相同,否則會發生亂碼。 序列化和反序列化的時候,會丟擲NotSerialzableException,沒有序列化異常類通過實現java.io.Serialzable 介面以啟用其序列化功能,未實現此介面的類將無法使其任何狀態序列化或反序列化。 Serizable介面也叫標記型介面 要進行序列化和反序列化的類必須實現Serializable介面,就會給類新增一個標記。 當我們進行序列化和反序列化的時候,就會檢測類上是否有這個標記。 有:就可以序列化和反序列化。 沒有:就會丟擲NotSerializableException異常。 去市場買肉--》肉上有一個藍色章(檢測合格)--》放心購買--》買回來怎麼吃隨意。 java.io.ObjectOutputStream extends OutputStream ObjectOutputStream:物件的序列化流 作用:把物件以流的方式寫入到檔案中儲存。 構造方法: ObjectOutputStream(OutputStream out)建立寫入指定 OutputStream 的ObjectOutputStream. 引數: OutputStream out:位元組輸出流。 特有的成員方法: void writeObjcet(Object obj):將指定的物件寫入 ObjcetOutputStream. 使用步驟: 1.建立ObjectOutputStream物件,構造方法中傳遞位元組輸出流。 2.使用ObjectOutputStream物件中的方法writeObject,把物件寫入到檔案中。 3.釋放資源。 java.io.ObjectInputStream extends InputStream ObjectInputStream:物件的反序列化 作用:把檔案中儲存的物件,以流的方式讀取出來使用。 構造方法: ObjectInputStream(InputStream in)建立從指定 InputStream 讀取的 ObjectInputStream。 引數: InputStream in:位元組輸入流 特有的成員方法: Object readObject() 從ObjectInputStream 讀取物件那個。 使用步驟: 1.建立ObjectInputStream物件,構造方法中傳遞位元組輸入流。 2.使用ObjectInputStream物件中的方法readObject讀取儲存物件的檔案。 3.釋放資源。 static關鍵字:靜態關鍵字。 靜態優先於非靜態載入到記憶體中(靜態優先於物件到記憶體中) 被static修飾的成員變數不能被序列化的,序列化的都是物件。 transient關鍵字:瞬態關鍵字 被transient修飾的成員變數,不能被序列化。功能和static差不多但是沒有靜態的含義。 static屬性定義在類檔案中之後,在其他類中呼叫該屬性,並更改了成員變數的值,只是更改了記憶體中成員變數的值,類檔案中定義的成員變數並沒有受到影響,在呼叫時,先把類檔案載入到記憶體中 ,修改得只是記憶體中成員變數的值,類檔案定義的資訊沒有發生改變。 編譯器(javac.exe)會把Person.java檔案編譯生成Psrson.class檔案。Person類實現了Servalizable介面,會根據類的定義給Persion.class檔案,新增一個序列號。 反序列化的時候,會使用Person.class檔案中的序列號和Person.txt檔案中的序列號比較。如果是一樣則反序列化成功;如果不一樣,則丟擲序列化衝突異常:InvalidClassException。 問題:每次修改類的定義。都會給class檔案生成一個新的序列號 解決方案:無論是否對類的定義進行修改,都不重新生成新的序列號。可以手動新增一個序列號。 格式在Serializable介面規定: static final long serialVersionUID=42L;常量不能變 java.io.PrintStream:列印流 PrintStream:為其他輸出流添加了功能,使用它們能夠方便地列印各種資料值表示形式。 PrintStream特點: 1.只負責資料的輸出,不負責資料的讀取。 2.與其他輸出流不同,PrintStream 永遠不會丟擲IOException 3.特有的方法,print,println void print(任意型別的值) void println(任意型別的值並換行) 構造方法: PrintStream(Filefile)建立具有指定檔案且不帶自動行重新整理的新列印流。輸出的目的地是一個檔案。 PrintStream(OutputStreamout)建立新的列印流。輸出目的地是一個位元組輸出流。 PrintStream(StringfileName)建立具有指定檔名稱且不帶自動行重新整理的新列印流。輸出的目的地是一個檔案路徑。 PrintStream extends OutputStream 繼承自父類的成員方法: -public void close():關閉此輸出流並釋放與此流相關聯的任何系統資源。
-public void flush():重新整理此輸出流並強制任何緩衝的輸出位元組被寫出。
-public void write(byte[] b):將b.length位元組從指定的位元組陣列寫入此輸出流。
一次寫多個位元組是正數(0~127),那麼顯示的時候會查詢ASCII表
如果第一個位元組是負數,那麼第一個位元組會和第二個位元組,兩個位元組組成一箇中文顯示,查詢系統預設碼錶。
-public void write(byte[] b,int off,int len):從指定的位元組陣列寫入len位元組,從偏移量off開始輸出到此輸出流。
-public abstract void write(int b):將指定的位元組輸出流。 注意: 如果使用繼承自父類的write方法寫資料,那麼檢視資料的時候會查詢編碼表:97->a 如果使用自己特有的方法print/println方法寫資料,寫的資料原樣輸出 97->97 可以改變輸出語句的目的地(列印流的語句) 輸出語句,預設在控制檯輸出 使用System.setOut方法改變輸出語句的目的地改為引數中傳遞的列印流的目的地。 static void setOut(PrintStream out) 重新分配“標準”輸出流。
public static void main(String[] args) throws FileNotFoundException {
System.out.println("在控制檯列印輸出");
PrintStream ps=new PrintStream("C:\\IdeaProjects\\com.itheima\\p.txt");
System.setOut(ps);
System.out.println("在列印流目的地列印");
}

【【網路】】 物理層/資料鏈路層:鏈路層是用於定義物理傳輸通道,通常是對某些網路連線裝置的驅動協議,例如針對光纖、網線提供的驅動。 網路層:網路層是整個TCP/IP協議的核心,它主要用於將傳輸的資料進行分組,將分組資料傳送到目標計算機或者網路。 運輸層:主要使網路程式進行通訊,在進行網路通訊時,可以採用TCP協議,也可以採用UDP協議。 應用層:主要負責應用程式的協議,例如HTTP協議,FTP協議等。 協議 UDP:使用者資料報協議(User Datagram Protocol),面向無連線性,不能保證資料的完整性。特點:資料被限制在64kb以內,超出這個範圍就不能 傳送了。比如視訊會議。 TCP:傳輸控制協議(Transmission Control Protocol),得到的TCP協議面向連線的通訊協議。提供了兩個計算機之間可靠無差錯的資料傳輸。 IP地址。 三次握手: 第一次握手,客戶端向服務端傳送連線請求,等待服務端確認。 第二次握手,伺服器向客戶端回送一個響應,通知客戶端收到了連線請求。 第三次握手,客戶端再次向伺服器端傳送確認資訊,確認連線。 IPv4:是一個32位的二進位制數,通常被分為4個位元組,表示成a、b、c、d的形式,例如192.168.65.100。其中a、b、c、d都是0-255之間的十進位制整數,那麼最多可以表示2的32次方個大約42億個。 IPv6:採用128位地址長度,每16個位元組一組,分成8組十六進位制數。 常用命令: 檢視本地IP地址,在控制檯輸入: ipconfig 檢查網路是否連通,在控制檯輸入:ping 空格 IP地址 特殊的IP地址: 本機IP地址: 127.0.0.1 、 localhost 埠號:是一個邏輯埠,我們無法直接看到,可以使用一些軟體檢視埠號。 當我們使用網路軟體一開啟,那麼作業系統就會為網路軟體分配一些軟體檢視埠號 或者網路軟體在開啟的時候和系統要 指定的埠號 埠號是由兩個位元組組成,取值範圍在0-65535之間 注意: 1024之前的埠號已經被系統分配給已知的網路軟體,我們不能用。 網路軟體的埠號不能重複。 常用的埠號: 1.80埠 網路埠 www.baidu.com:80正確的網址 2.資料庫 mysql:3306 oracle:1521 3.Tomcat服務區:8080 多個客服端同時和伺服器互動,就需要使用多個IO流物件。伺服器是沒有IO流的,伺服器可以獲取到請求的客戶端物件Socket使用每個客戶端Socket中提供的IO流和客戶端進行互動。伺服器用客戶端的位元組輸入流和位元組輸出流給客戶端傳送資料和回寫資料。 TCP通訊的客戶端:向伺服器傳送連線請求,給伺服器傳送資料,讀取伺服器回寫的資料。 表示客戶端的類: java.net.Socket:此類實現客戶端套接字(也可以叫“套接字”),套接字是兩臺機器間通訊的端點。 套接字:包含了IP地址和埠號的網路單位。 構造方法: Socket(InetAddressaddress, intport)建立一個流套接字並將其連線到指定 IP 地址的指定埠號。 引數: String host:伺服器主機的名稱/伺服器的IP地址。 int port:伺服器的埠號。 成員方法: getOutputStream()返回此套接字的輸出流。 getInputStream()返回此套接字的輸入流。 close() 關閉此套接字。 實現步驟: 1.建立一個客戶端物件Socket,構造方法繫結伺服器的IP地址和埠號。 2.使用Socket物件中的方法getOutputStream()獲取網路位元組輸出流OutputStream物件。 3.使用網路位元組輸出流OutputStream物件中的方法write(),給伺服器傳送資料。 4.使用Socket物件中的方法getInputStream()獲取網路位元組輸入流InputStream物件。 5.使用網路位元組輸入流InputStream物件中的方法read,讀取伺服器回寫的資料。 注意: 1.客戶端和伺服器端進行互動,必須使用Socket中提供的網路流,不能使用自己建立的流物件。 2.當我們建立客戶端物件Socket的時候,就會去請求伺服器和伺服器經過3次握手建立連線通絡路。 這時如果伺服器沒有啟動,就會拋異常;如果伺服器已經啟動,那麼就可以進行互動了。 TCP通訊的服務端:接收客戶端的請求,讀取客戶端傳送的資料。給客戶端回寫資料表示服務端的類: java.net.ServerSocket:此類實現伺服器套接字。 構造方法: ServerSocket(int port)建立繫結到特定埠的伺服器套接字。 伺服器端必須明確一件事情,必須知道是哪個客戶端請求的伺服器。 所以可以使用accept方法獲取到請求的客戶端物件Socket 成員方法: Socket accept() 監聽並接受到此套位元組的連線。 伺服器的實現步驟: 1.建立伺服器ServerSocket物件和系統要指定的埠號。 2.使用ServerSocket物件中的方法accept。獲取到請求的客戶端物件Socket。 3.使用Socket物件中的方法getOutputStream()獲取網路位元組輸出流OutputStream物件。 4.使用網路位元組輸出流OutputStream物件中的方法write(),給伺服器傳送資料。 5.使用Socket物件中的方法getInputStream()獲取網路位元組輸入流InputStream物件。 6.使用網路位元組輸入流InputStream物件中的方法read,讀取伺服器回寫的資料。 7.釋放資源(Socket、ServerSocket) 客戶端和伺服器和本地硬碟進行讀寫,需要使用自己建立的位元組流物件(本地流) 客戶端和伺服器之間進行讀寫,必須使用Socket中提供的位元組流物件(網路流) read方法阻塞,解決:上傳完檔案,給伺服器一個結束標記 void shutdownOutput() 禁用此套接字的輸出流 對於 TCP 套接字,任何以前寫入的資料都將被髮送,並且後跟TCP的正常連線終止序列。 瀏覽器解析伺服器回寫的html頁面,頁面中如果有圖片,那麼瀏覽器就會單獨的開啟一個執行緒,讀取伺服器的圖片。 我們要讓伺服器一直處於監聽狀態,客戶端請求一次,伺服器就回寫一次。
函式式介面:在java中是指:有且僅有一個抽象方法的介面。當然介面中可以同時包含其他方法(預設、靜態、私有) @FunctionalInterface註解 作用:可以檢測介面是否是一個函式式介面 是:編譯成功 否:編譯失敗(介面中的抽象方法個數不唯一) 函式式介面的使用:一般可以作為方法的引數和返回值型別 使用Lambda優化日誌案例: 使用Lambda表示式作為引數傳遞傳遞,僅僅是把引數傳遞到showLog方法中只有滿足條件,日誌的等級是1級 才會呼叫介面MessageBuilder中的方法builderMessage,才不會進行字串的拼接。 如果不滿足條件,日誌的等級不是1級 那麼MessageBuilder介面中的方法builderMessage也不會執行,所以拼接字串的程式碼也不會執行。 Lambda的特點:延遲載入 Lambda的使用前提,必須存在函式式介面 例如java.lang.Runnable介面就是一個函式式介面。 假設有一個startThread方法使用該介面作為引數,那麼就可以使用Lambda進行傳參。這種情況其實和Thread類的構造方法引數沒有本質區別。 如果一個方法的返回值型別是一個函式式介面,那麼就可以直接返回一個Lambda表示式。 當需要通過一個方法來獲取一個java.util.Comparator介面型別的物件作為排序器時,就可以調該方法獲取。 常用的函式式介面: java.util.function.Supplier<T>介面僅包含一個無參的方法:T get()。 用來獲取一個泛型引數指定型別的物件資料。 Supplier<T>介面被稱為生產型介面,指定介面泛型是什麼型別,那麼介面中的get方法就會產生什麼型別的資料 java.util.function.Consumer<T>介面正好與Supplier介面相反,它不是產生一個數據,而是消費一個數據,其資料型別由泛型決定。 Consumer介面中包含抽象方法void accept(T t),意為消費一個指定泛型的資料。 Consumer介面是一個消費性介面,泛型執行什麼型別,就可以使用accept方法消費什麼型別的資料,至於具體怎麼消費(使用),則需要自定義(輸出,計算......) Consumer介面的預設方法andThen 作用:需要兩個Consumer介面,可以把兩個Consumer介面組合到一起,再對資料進行消費。 例如: Consumer<String> con1 Consumer<String> con2 String s="hello"; con1.accept(s); con2.accept(s); 連線兩個Consumer介面,再進行消費 con1.andthen(con2).accept(s);誰寫前面誰先消費 java.util.function.Predicate<T>介面 作用:對某種資料型別的資料進行判斷,結果返回一個boolean值。 Predicate介面中包含一個抽象方法: boolean test(T t):用來對指定資料型別資料進行判斷的方法 結果: 符合條件,返回true 不符合條件,返回false 邏輯表示式:可以連線多個判斷條件 && || ! Predicate介面中有一個預設方法and,表示並且關係,也可以用於連線兩個判斷條件 default Predicate<T> and (Predicate<? super T> other){ Objects.requireNonNull(other); return (t)->this.test(t) && other.test(t); } 方法內部的判斷條件,也是用&&運算子連線起來的。 Predicate介面中有一個預設方法or,表示或者關係,也可以用於連線兩個判斷條件 default Predicate<T> or (Predicate<? super T> other){ Objects.requireNonNull(other); return (t)->this.test(t) || other.test(t); } Predicate介面中有一個預設方法negate,也表示取反的意思 default Predicate<T> negate(){ return (t) -> !test(t); } java.util.function.Function<T,R>介面用來根據一個型別得到另一個型別的資料,前者稱為前置條件,後者稱為後置條件。 Function介面中最主要的抽象方法為: R apply(T t),根據型別T的引數獲取型別R的結果。使用的場景例如:將String型別轉換為Integer型別。 Function介面中的預設方法andThen:用來進行組合操作。
Stream流 說到Stream便容易想到I/O Stream,而實際上,誰規定“流”就一定是“I/O流”呢?在java8中,得益於Lambda所帶來得函數語言程式設計,引入一個全新的Stream概念,關注的是做什麼,而不是怎麼做,用於解決已有集合類庫既有的弊端。 這裡的filter、map、skip都是對函式模型進行操作,集合元素並沒有真正被處理。只有當終結方法count執行的時候,整個模型才會按照指定策略執行操作。而這得益於Lambda的延遲執行特性。 ”Stream流“其實是一個集合元素的函式模型,它並不是集合,也不是資料結構,其本身並不儲存任何元素(或其地址值)。 Stream(流)是一個來自資料來源的元素佇列 元素是特定型別的物件,形成一個佇列。java中的Stream並不會儲存元素,而是按需計算。 資料來源 流的來源。可以是集合,陣列等。 和以前的Collection操作不同,Stream操作還有兩個基礎的特徵: 1.Pipelining:中間操作都會返回流物件本身。這樣多個操作可以串聯成一個管道,如同流式風格(fluent style)。這樣可以對操作進行優化,比如延遲執行(laziness)和短路(short-circuiting)。 2.內部迭代:以前對集合遍歷都是通過Iterator或者增強for的方式,顯示的在集合外部進行迭代,這叫做外部迭代。Stream提供了內部迭代的方式,流可以直接呼叫遍歷方法。 當使用一個流的時候,通常包括三個基本步驟:獲取一個數據源(source)——>資料轉換——>執行操作獲取想要的結果,每次轉換原有Stream物件不改變,返回一個新的Stream物件(可以有多次轉換),這就允許對其操作可以像鏈條一樣排列,變成一個管道。 java.util.stream.Stream<T>是Java8 新加入的最常用的流介面。(這並不是一個函式式介面) 獲取一個流非常簡單,有以下幾種常用的方式: -所有的Collection集合都可以通過stream預設方法獲取流; default Stream<E> stream() -Stream介面的靜態方法of可以獲取陣列對應的流。 static <T> Stream<T> of (T...values) 引數是一個可變引數,那麼我們可以傳遞一個數組。 流模型中常用的API: 延遲方法:返回值型別不再是Stream介面自身型別的方法,因此支援鏈式呼叫。(除了終結方法外,其餘方法均為延遲方法。) 終結方法:返回值型別不再是Stream介面自身型別的方法,因此不再支援類似StringBuilder那樣的鏈式呼叫。終結方法有count和forEach方法等。 Stream流中的常用方法forEach void forEach(Consumer<? super T> action); 該方法接受一個Consumer介面函式,會將每一個流元素交給該函式進行處理。 Consumer介面是一個消費性的函式式介面,可以傳遞Lambda表示式,消費資料。 簡單記:forEach方法用來遍歷流中的資料,是一個終結方法,遍歷之後不能繼續呼叫Stream流中的其他方法。 Stream流中的常用方法filter:用於對Stream流中的資料進行過濾 Stream<T> filter(Predicate<? super T> predicate); filter方法的引數Predicate是一個函式式介面,所以可以傳遞Lambda表示式,對資料進行過濾。 Predicate中的抽象方法: boolean test(T t); Stream流屬於管道流,只能被消費(使用)一次 第一個Stream流呼叫完畢方法,資料就會流轉到下一個Stream上,而這時第一個Stream流已經使用完畢,就會關閉了,所以第一個Stream流就不能再呼叫方法了。 會丟擲java.lang.IllegalStateException: stream has already been operated upon or closed 異常

如果需要將流中的元素對映到另一個流中,可以使用map方法。
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
該介面需要一個Function函式式介面引數,可以將當前流中的T型別資料轉換為另一種R型別的流。
Function中的抽象方法:R apply(T t);
正如舊集合Collection當中size方法一樣, Stream流中的常用方法 count:用於統計Stream流中元素的個數 long count(); count方法是一個終結方法,返回值是一個long型別的整數,所以不能再繼續呼叫Stream流中的其他方法了。 Stream流中的常用方法limit:用與擷取流中的元素 limit方法可以對流進行擷取,只取用前n個。 方法簽名: Stream<T> limit(long maxSize); 引數是一個long型,如果集合當前長度大於引數則進行擷取,否則不進行操作。 limit方法是一個延遲方法,只是對流中的元素進行擷取,返回是一個新的流,所以可以繼續呼叫Stream流中的其他方法。 Stream流中常用的方法 skip:用於跳過元素 如果希望跳過前幾個元素,可以使用skip方法獲取一個擷取之後的新流: Stream<T> skip(long n); 如果流的當前長度大於n,則跳過前n個;否則將會得到一個長度為0的空流。 Stream 流中的常用方法 concat:用於把流組合到一起 如果有兩個流,希望合併成為一個流,那麼可以使用Stream介面的靜態方法concat static <T> Stream<T> concat(Stream<? extends T> a,Stream<? extends T> b) 方法引用符 雙冒號::為引用運算子,而它所在的表示式被稱為方法引用。如果Lambda要表達的函式方案已經存在於某個方法的實現中,那麼則可以通過雙冒號來引用該方法作為Lambda的代替者。

public static void main(String[] args) {
//第一種語義是指:拿到引數之後經Lambda之手,繼而傳遞給System.out.println方法去處理。
printString(s-> System.out.println(s));
/*
* 分析:
* Lambda表示式的目的,列印引數傳遞的字串。
* 把引數s,傳遞給System.out物件,呼叫out物件中的方法println對字串進行了輸出
* 注意:
* 1.System.out物件是已經存在的
* 2.println方法也是已經存在的
* 所以可以使用System.out方法直接引用(呼叫)println方法。
* */
//第二種等效寫法的語義是指:直接讓System.out中的println方法來取代Lambda。兩種寫法的執行效果完全一樣,而第二種方法引用
//的寫法複用了已有方案,更加簡潔。
//注:Lambda中 傳遞的引數一定是方法引用中的那個方法可以接受的型別,否則會丟擲異常。
printString(System.out::println);
}
//Printtable 是自定義的函式式介面包含一個抽象方法print()
public static void printString(Printable p){
p.print("HelloWorld");
}
通過物件名引用成員方法,使用前提是物件名是已經存在的,成員方法也是已經存在的,就可以使用物件名來引用成員方法。
MethodRerObject obj=new MethodRerObject();
printString(obj::printUpperCaseString);
通過類名引用靜態成員方法,類已經存在,靜態成員方法也已經存在,就可以通過類名直接引用靜態成員方法。
int b=method(-10,Math::abs);
System.out.println(b);
通過super引用父類成員方法,如果存在繼承關係,當Lambda中需要出現super呼叫時,也可以使用方法引用進行代替。首先是函式式介面
method(super::sayHello);
通過this引用成員方法,使用方法引用優化Lambda表示式,this是已經存在的,本類的成員方法buyHouse也是已經存在的,所以我們可以直接使用this引用本類的成員方法buyHouse
marray(this::byHouse);
使用方法引用優化Lambda表示式,構造方法new Person(String name) 已知, 建立物件已知 new,就可以使用Person引用new建立物件。
printName("迪麗熱巴",name->new Person(name));
陣列的構造器引用 定義一個方法,方法的引數傳遞建立陣列的長度和ArrayBuilder介面;方法內部根據傳遞的長度使用ArrayBuilder中的方法建立陣列並返回。 使用方法引用優化lambda表示式,已知建立的就是int[]陣列,陣列的長度也是已知的,就可以使用方法引用,int[]引用new,根據引數傳遞的長度來建立陣列。
int[] in1=createArray(10,int[]::new);