Java 8 Streams的簡單使用方法
1 package JDK8Test; 2 import java.util.ArrayList; 3 4 public class Main 5 { 6 public static void main(String[] args) 7 { 8 ArrayList<Integer> nums=new ArrayList<Integer>(); 9 nums.add(1); 10 nums.add(null); 11 nums.add(3); 12 nums.add(4); 13 nums.add(null); 14 nums.add(6); 15 int n=(int)nums.stream().filter(num->num!=null).count(); 16 System.out.println(n);//4 17 } 18 }
上面這段代碼是獲取一個List中,元素不為null的個數。
紅色框中的語句是一個Stream的生命開始的地方,負責創建一個Stream實例;綠色框中的語句是賦予Stream靈魂的地方,把一個Stream轉換成另外一個Stream,紅框的語句生成的是一個包含所有nums變量的Stream,通過綠框的filter方法以后,重新生成了一個過濾掉原nums列表所有null以后的Stream;藍色框中的語句是豐收的地方,把Stream的里面包含的內容按照某種算法來匯聚成一個值。
使用Stream的基本步驟:
1.創建Stream;
2.轉換Stream,每次轉換原有Stream對象不改變,返回一個新的Stream對象(可以有多次轉換);
3.對Stream進行聚合操作,獲取想要的結果;
怎么得到Stream:
①使用Stream靜態方法來創建Stream:
of方法:有兩個重載方法,一個接受變長參數,一個接受單一值
Stream integerStream = Stream.of(1, 2, 3, 5);
Stream stringStream = Stream.of(“taobao”);
②通過Collection接口的默認方法stream(),把一個Collection對象轉換成Stream。
轉換Stream:
轉換Stream其實就是把一個Stream通過某些行為轉換成一個新的Stream。
①distinct: 對於Stream中包含的元素進行去重操作(去重邏輯依賴元素的equals方法),新生成的Stream中沒有重復的元素;
②filter: 對於Stream中包含的元素使用給定的過濾函數進行過濾操作,新生成的Stream只包含符合條件的元素;
③map: 對於Stream中包含的元素使用給定的轉換函數進行轉換操作,新生成的Stream只包含轉換生成的元素。這個方法有三個對於原始類型的變種方法,分別是:mapToInt,mapToLong和mapToDouble。這三個方法也比較好理解,比如mapToInt就是把原始Stream轉換成一個新的Stream,這個新生成的Stream中的元素都是int類型。
例子:
1 package JDK8Test; 2 import java.util.*; 3 import java.util.Arrays; 4 import java.util.stream.Collectors; 5 6 public class Main 7 { 8 public static void main(String[] args) 9 { 10 List<String> list=Arrays.asList(new String[] {"Ni","Hao","Lambda"}); 11 List<String> list2=list.stream().map(item->item.toLowerCase()).collect(Collectors.toList()); 12 System.out.println(list2); 13 }//[ni, hao, lambda] 14 }
這段代碼就是對一個字符串的列表,把其中包含的每個字符串都轉換成全小寫的字符串。注意代碼第四行的map方法調用,這里map方法就是接受了一個lambda表達式。
1 package JDK8Test; 2 import java.util.*; 3 import java.util.Arrays; 4 import java.util.stream.Collectors; 5 6 public class Main 7 { 8 public static void main(String[] args) 9 { 10 List<String> list=Arrays.asList(new String[] {"Ni","Hao","Lambda"}); 11 List<String> list2=list.stream().map(item->{return "lambda:"+item;}).collect(Collectors.toList()); 12 list2.forEach(System.out::println); 13 } 14 } 15 /* 16 lambda:Ni 17 lambda:Hao 18 lambda:Lambda 19 */
集合的forEach()方法,對集合進行遍歷,小括號中的方法就是應用到集合中每個元素的身上,以達到遍歷的目的。
1 package JDK8Test; 2 import java.util.*; 3 import java.util.Arrays; 4 import java.util.stream.Collectors; 5 6 public class Main 7 { 8 public static void main(String[] args) 9 { 10 String waibu="lambda:"; 11 List<String> proStrs=Arrays.asList(new String[] {"Ni","Hao","Lambda"}); 12 List<String> exeStrs=proStrs.stream().map(chuandi->{ 13 long zidingyi=System.currentTimeMillis(); 14 return waibu+chuandi+"------:"+zidingyi; 15 }).collect(Collectors.toList()); 16 exeStrs.forEach(System.out::println); 17 } 18 } 19 /* 20 lambda:Ni------:1559118070052 21 lambda:Hao------:1559118070052 22 lambda:Lambda------:1559118070052 23 */
lambda表達式可以訪問給它傳遞的變量,訪問自己內部定義的變量,同時也能訪問它外部的變量。 不過lambda表達式訪問外部變量有一個非常重要的限制:變量不可變(只是引用不可變,而不是真正的不可變)。 當在表達式內部修改waibu = waibu + " ";時,IDE就會報錯。因為變量waibu被lambda表達式引用,所以編譯器會隱式的把其當成final來處理。
以前Java的匿名內部類在訪問外部變量的時候,外部變量必須用final修飾。現在java8對這個限制做了優化,可以不用顯示使用final修飾,但是編譯器隱式當成final來處理。
④peek: 生成一個包含原Stream的所有元素的新Stream,同時會提供一個消費函數(Consumer實例),新Stream每個元素被消費的時候都會執行給定的消費函數;
⑤limit: 對一個Stream進行截斷操作,獲取其前N個元素,如果原Stream中包含的元素個數小於N,那就獲取其所有的元素;
⑥skip: 返回一個丟棄原Stream的前N個元素后剩下元素組成的新Stream,如果原Stream中包含的元素個數小於N,那么返回空Stream;
匯聚Stream:
匯聚操作(也稱為折疊)接受一個元素序列為輸入,反復使用某個合並操作,把序列中的元素合並成一個匯總的結果。比如查找一個數字列表的總和或者最大值,或者把這些數字累積成一個List對象。Stream接口有一些通用的匯聚操作,比如reduce()和collect();也有一些特定用途的匯聚操作,比如sum(),max()和count()。注意:sum方法不是所有的Stream對象都有的,只有IntStream、LongStream和DoubleStream實例才有。
①reduce():把 Stream 元素組合起來。它提供一個起始值(種子),然后依照運算規則(BinaryOperator),返回單個的結果值,並且reduce操作每處理一個元素總是創建一個新值。
②collect:正如其名字顯示的,它可以把Stream中的所有元素收集到一個結果容器中(比如Collection)。
Java 8還給我們提供了Collector的工具類——Collectors,其中已經定義了一些靜態工廠方法,比如Collectors.toCollection()收集到Collection中, Collectors.toList()收集到List中和Collectors.toSet()收集到Set中。
List numsWithoutNull = nums.stream().filter(num -> num != null).collect(Collectors.toList());
③count方法:獲取Stream中元素的個數。
– 搜索相關
– allMatch:是不是Stream中的所有元素都滿足給定的匹配條件
– anyMatch:Stream中是否存在任何一個元素滿足匹配條件
– findFirst: 返回Stream中的第一個元素,如果Stream為空,返回空Optional
– noneMatch:是不是Stream中的所有元素都不滿足給定的匹配條件
– max和min:使用給定的比較器(Operator),返回Stream中的最大|最小值
下面給出allMatch和max的例子:
1 package JDK8Test; 2 import java.util.*; 3 4 5 public class Main 6 { 7 public static void main(String[] args) 8 { 9 ArrayList<Integer> nums=new ArrayList<Integer>(); 10 nums.add(1); 11 nums.add(null); 12 nums.add(3); 13 nums.add(4); 14 nums.add(null); 15 nums.add(6); 16 System.out.println(nums.stream().filter(item->item!=null).allMatch(item->item<100)); 17 } 18 } 19 /* 20 true 21 */
以上代碼,判斷nums列表里的不為null元素是否都滿足“小於100“這個條件,輸出為true。
1 package JDK8Test; 2 import java.util.*; 3 4 5 public class Main 6 { 7 public static void main(String[] args) 8 { 9 ArrayList<Integer> nums=new ArrayList<Integer>(); 10 nums.add(1); 11 nums.add(null); 12 nums.add(3); 13 nums.add(4); 14 nums.add(null); 15 nums.add(6); 16 nums.stream().filter(item->item!=null).max((o1,o2)->o1-o2).ifPresent(System.out::println); 17 } 18 } 19 /* 20 6 21 */
以上代碼,先把nums里為null的元素過濾掉,然后輸出nums里元素的最大值。輸出為6。