1. 程式人生 > >Java JVM(九):JDK8的集合流式操作

Java JVM(九):JDK8的集合流式操作

一. 基本概念

二. 序列流和並行流

三. 中間操作 和 最終操作

 

一. 基本概念

1.1 為什麼加入 集合的流式操作     

        JDK8 的Stream 是一個受到 函數語言程式設計 和 多核時代影響而產生的東西。很多時候我們需要到底層返回資料,上層再對資料進行遍歷,進行一些資料統計,但是之前的Java API 中很少有這種方法,這就需要我們自己來 Iterator 來遍歷,如果JDK 能夠為我們提供一些這種方法,並且能夠為我們優化就好了。

         所以JDK8加入 了 java.util.stream包,實現了集合的流式操作,流式操作包括集合的過濾,排序,對映等功能。根據流的操作性,又可以分為 序列流 和 並行流。根據操作返回的結果不同,流式操作又分為中間操作和最終操作。大大方便了我們對於集合的操作。

  • 最終操作:返回一特定型別的結果。
  • 中間操作:返回流本身。

1.2 什麼是 流

        Stream 不是 集合元素,也不是資料結構,它相當於一個 高階版本的 Iterator,不可以重複遍歷裡面的資料,像水一樣,流過了就一去不復返。它和普通的 Iterator 不同的是,它可以並行遍歷,普通的 Iterator 只能是序列,在一個執行緒中執行。

 

二. 序列流和並行流:

        序列流操作在一個執行緒中依次完成。並行流在多個執行緒中完成,主要利用了 JDK7 的 Fork/Join 框架來拆分任務和加速處理。相比序列流,並行流可以很大程度提高程式的效率。

 

三. 中間操作 和 最終操作        

中間操作:

  • filter(): 對元素進行過濾
  • sorted():對元素排序
  • map():元素對映
  • distinct():去除重複的元素

最終操作:

  • forEach():遍歷每個元素。
  • reduce():把Stream 元素組合起來。例如,字串拼接,數值的 sum,min,max ,average 都是特殊的 reduce。
  • collect():返回一個新的集合。
  • min():找到最小值。
  • max():找到最大值。

 

3.1 filter() 對元素進行過濾

Demo(有一連結串列,{1,2,3,4,5},把偶數過濾掉):

 
  1. public class Test {

  2. public static void main(String[] args) throws InterruptedException {

  3. List list = new ArrayList();

  4. for(int i = 1 ; i <= 5; ++i){

  5. list.add(i);

  6. }

  7. list.stream().filter(param -> (int)param % 2 == 1)

  8. .forEach(System.out::println);

  9. }

  10. }

輸出:

1
3
5


3.2 sorted() 對元素進行排序

Demo(有一連結串列,{2,3,1,5,4},從小到大排序):

 
  1. public class Test {

  2. public static void main(String[] args) throws InterruptedException {

  3. List list = new ArrayList();

  4. list.add(2);

  5. list.add(3);

  6. list.add(1);

  7. list.add(5);

  8. list.add(4);

  9. list.stream().sorted().forEach(System.out::println);

  10. }

  11. }

輸出:

1
2
3
4
5

Ps1: 此時為升序,那麼有時候我們可能會需要到降序,此時做法可以如下:

        流除了提供預設的升序 sorted() 方法,也提供了:    

Stream<T> sorted(Comparator<? super T> comparator);

        那麼,自定義比較函式即可,如下程式碼:

 
  1. public class Test {

  2. public static void main(String[] args) throws InterruptedException {

  3. List list = new ArrayList();

  4. list.add(2);

  5. list.add(3);

  6. list.add(1);

  7. list.add(5);

  8. list.add(4);

  9. // list.stream().sorted().forEach(System.out::println);

  10. list.stream().sorted( (param1,param2) -> ((int)param1 < (int)param2 ? 1 : -1 ) )

  11. .forEach(System.out::println);

  12. }

  13. }

輸出為:

5
4
3
2
1

3.3 map() 元素對映

        也就是說,原來的連結串列的每個元素可以按照規則變成相應的元素。

Demo(連結串列 (1,0),變成 true,false):

 
  1. public class Test {

  2. public static void main(String[] args) throws InterruptedException {

  3. List list = new ArrayList();

  4. list.add(1);

  5. list.add(0);

  6. list.stream().map( param -> (int)param == 1 ? true:false )

  7. .forEach(System.out::println);

  8. }

  9. }

輸出:

 
  1. true

  2. false

3.4  distinct() 去除重複元素

Demo:

 
  1. public class Test {

  2. public static void main(String[] args) throws InterruptedException {

  3. List list = new ArrayList();

  4. list.add(1);

  5. list.add(1);

  6. list.add(0);

  7. list.stream().distinct().forEach(System.out::println);

  8. }

  9. }

3.5 reduce() :把Stream 元素組合起來。

Demo(從1加到5):

 
  1. public class Test {

  2. public static void main(String[] args) throws InterruptedException {

  3. List list = new ArrayList();

  4. list.add(1);

  5. list.add(2);

  6. list.add(3);

  7. list.add(4);

  8. list.add(5);

  9. System.out.println(

  10. list.stream().reduce((param1,param2) ->(int)param1 + (int)param2 ).get());

  11. }

  12. }

        注意,reduce() 返回一個 Optional 型別的物件,可以通過 get() 方法獲得值。
 

3.6 collect() :返回一個新的集合

Demo(先把 list 集合的 奇數去掉,然後把剩下的偶數返回到 _list 集合中):

 
  1. public class Test {

  2. public static void main(String[] args) throws InterruptedException {

  3. List list = new ArrayList();

  4. list.add(1);

  5. list.add(2);

  6. list.add(3);

  7. list.add(4);

  8. list.add(5);

  9.  
  10. List _list = (List) list.stream().filter((param) -> (int)param % 2 == 0)

  11. .collect(Collectors.toList());

  12. _list.forEach(System.out::println);

  13. }

  14. }

輸出:

2
4

3.7 min(),max()  找到最大值最小值

 
  1. public class Test {

  2. public static void main(String[] args) throws InterruptedException {

  3. List list = new ArrayList();

  4. list.add(1);

  5. list.add(2);

  6. list.add(3);

  7. list.add(4);

  8. list.add(5);

  9.  
  10. System.out.println(list.stream().min(

  11. (param1,param2) -> (int)param1 > (int)param2 ? 1:-1 ).get());

  12. System.out.println(list.stream().max(

  13. (param1,param2) -> (int)param1 > (int)param2 ? 1:-1 ).get());

  14. }

  15. }

        注意, min(),max() 方法也是返回 Optional 物件, 可以通過 get() 方法返回值。

        

總結:

1. 流式操作的引入:提高執行效率(並行),方便編碼(有很多API 可用),提高可讀性。
2. 流的分類:可以分為序列流和並行流;對於操作:可以分為中間操作和最終操作
3. 流API:
        中間操作:

                filter(): 對元素進行過濾;

                sorted():對元素排序;

                map():元素對映;

                distinct():去除重複的元素 。

        最終操作:

                forEach():遍歷每個元素;

                reduce():把Stream 元素組合起來。例如,字串拼接,數值的 sum,min,max ,average 都是特殊的 reduce。

                collect():返回一個新的集合。

                min():找到最小值。

                max():找到最大值。

            

Ps1:除了上面介紹的方法,還有如下方法:

  • Intermediate:

                map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered

  • Terminal:

                forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

  • Short-circuiting:

                anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit

 

 

 

Ps2:在JDK 8 中的 Comparator 介面中,既有 equals 方法,也有 compare 方法,為什麼還可以宣告為函式式介面?有哪位大神指導麻煩告知一下。

 

 

 

參考:

1. Java 8 新特性概述:http://www.ibm.com/developerworks/cn/java/j-lo-jdk8newfeature/index.html

2. Java 8 中的Stream API 詳解:https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/