1. 程式人生 > 程式設計 >Java Stream函式語言程式設計第三篇:管道流結果處理

Java Stream函式語言程式設計第三篇:管道流結果處理

一、Java Stream管道資料處理操作

在本號之前寫過的文章中,曾經給大家介紹過 Java Stream管道流是用於簡化集合類元素處理的java API。在使用的過程中分為三個階段。在開始本文之前,我覺得仍然需要給一些新朋友介紹一下這三個階段,如圖:

Java Stream函式語言程式設計?用過都說好,案例圖文詳解送給你

  • 第一階段(圖中藍色):將集合、陣列、或行文字檔案轉換為java Stream管道流
  • 第二階段(圖中虛線部分):管道流式資料處理操作,處理管道中的每一個元素。上一個管道中的輸出元素作為下一個管道的輸入元素。
  • 第三階段(圖中綠色):管道流結果處理操作,也就是本文的將介紹的核心內容。

在開始學習之前,仍然有必要回顧一下我們之前給大家講過的一個例子:


List<String> nameStrs = Arrays.asList("Monkey","Lion","Giraffe","Lemur");

List<String> list = nameStrs.stream()
        .filter(s -> s.startsWith("L"))
        .map(String::toUpperCase)
        .sorted()
        .collect(toList());
System.out.println(list);
複製程式碼
  • 首先使用stream()方法將字串List轉換為管道流Stream
  • 然後進行管道資料處理操作,先用fliter函式過濾所有大寫L開頭的字串,然後將管道中的字串轉換為大寫字母toUpperCase,然後呼叫sorted方法排序。這些API的用法在本號之前的文章有介紹過。其中還使用到了lambda表示式和函式引用。
  • 最後使用collect函式進行結果處理,將java Stream管道流轉換為List。最終list的輸出結果是:[LEMUR,LION]

如果你不使用java Stream管道流的話,想一想你需要多少行程式碼完成上面的功能呢?回到正題,這篇文章就是要給大家介紹第三階段:對管道流處理結果都可以做哪些操作呢?下面開始吧!

二、ForEach和ForEachOrdered

如果我們只是希望將Stream管道流的處理結果打印出來,而不是進行型別轉換,我們就可以使用forEach()方法或forEachOrdered()方法。


Stream.of("Monkey","Lemur","Lion")
        .parallel()
        .forEach(System.out::println);
Stream.of("Monkey","Lion")
        .parallel()
        .forEachOrdered(System.out::println);
複製程式碼
  • parallel()函式表示對管道中的元素進行並行處理,而不是序列處理,這樣處理速度更快。但是這樣就有可能導致管道流中後面的元素先處理,前面的元素後處理,也就是元素的順序無法保證
  • forEachOrdered從名字上看就可以理解,雖然在資料處理順序上可能無法保障,但是forEachOrdered方法可以在元素輸出的順序上保證與元素進入管道流的順序一致。也就是下面的樣子(forEach方法則無法保證這個順序):
Monkey
Lion
Giraffe
Lemur
Lion
複製程式碼

三、元素的收集collect

java Stream 最常見的用法就是:一將集合類轉換成管道流,二對管道流資料處理,三將管道流處理結果在轉換成集合類。那麼collect()方法就為我們提供了這樣的功能:將管道流處理結果在轉換成集合類。

3.1.收集為Set

通過Collectors.toSet()方法收集Stream的處理結果,將所有元素收集到Set集合中。


Set<String> collectToSet = Stream.of(
   "Monkey","Lion"
) 
.collect(Collectors.toSet());

//最終collectToSet 中的元素是:[Monkey,Lion,Giraffe,Lemur],注意Set會去重。
複製程式碼

3.2.收集到List

同樣,可以將元素收集到List使用toList()收集器中。


List<String> collectToList = Stream.of(
   "Monkey","Lion"
).collect(Collectors.toList());

// 最終collectToList中的元素是: [Monkey,Lemur,Lion]
複製程式碼

3.3.通用的收集方式

上面為大家介紹的元素收集方式,都是專用的。比如使用Collectors.toSet()收集為Set型別集合;使用Collectors.toList()收集為List型別集合。那麼,有沒有一種比較通用的資料元素收集方式,將資料收集為任意的Collection介面子型別。 所以,這裡就像大家介紹一種通用的元素收集方式,你可以將資料元素收集到任意的Collection型別:即向所需Collection型別提供建構函式的方式。


LinkedList<String> collectToCollection = Stream.of(
   "Monkey","Lion"
).collect(Collectors.toCollection(LinkedList::new));

//最終collectToCollection中的元素是: [Monkey,Lion]
複製程式碼

注意:程式碼中使用了LinkedList::new,實際是呼叫LinkedList的建構函式,將元素收集到Linked List。當然你還可以使用諸如LinkedHashSet::newPriorityQueue::new將資料元素收集為其他的集合型別,這樣就比較通用了。

3.4.收集到Array

通過toArray(String[]::new)方法收集Stream的處理結果,將所有元素收集到字串陣列中。


String[] toArray = Stream.of(
   "Monkey","Lion"
) .toArray(String[]::new);

//最終toArray字串陣列中的元素是: [Monkey,Lion]
複製程式碼

3.5.收集到Map

使用Collectors.toMap()方法將資料元素收集到Map裡面,但是出現一個問題:那就是管道中的元素是作為key,還是作為value。我們用到了一個Function.identity()方法,該方法很簡單就是返回一個“ t -> t ”(輸入就是輸出的lambda表示式)。另外使用管道流處理函式distinct()來確保Map鍵值的唯一性。


Map<String,Integer> toMap = Stream.of(
    "Monkey","Lion"
)
.distinct()
.collect(Collectors.toMap(
       Function.identity(),//元素輸入就是輸出,作為key
       s -> (int) s.chars().distinct().count()// 輸入元素的不同的字母個數,作為value
));

// 最終toMap的結果是: {Monkey=6,Lion=4,Lemur=5,Giraffe=6}   
複製程式碼

3.6.分組收集groupingBy

Collectors.groupingBy用來實現元素的分組收集,下面的程式碼演示如何根據首字母將不同的資料元素收集到不同的List,並封裝為Map。


Map<Character,List<String>> groupingByList =  Stream.of(
    "Monkey","Lion"
)
.collect(Collectors.groupingBy(
       s -> s.charAt(0),//根據元素首字母分組,相同的在一組
       // counting()        // 加上這一行程式碼可以實現分組統計
));

// 最終groupingByList內的元素: {G=[Giraffe],L=[Lion,Lion],M=[Monkey]}
//如果加上counting() ,結果是:  {G=1,L=3,M=1}
複製程式碼

四、其他常用方法


boolean containsTwo = IntStream.of(1,2,3).anyMatch(i -> i == 2);
// 判斷管道中是否包含2,結果是: true

long nrOfAnimals = Stream.of(
    "Monkey","Lemur"
).count();
// 管道中元素資料總計結果nrOfAnimals: 4


int sum = IntStream.of(1,3).sum();
// 管道中元素資料累加結果sum: 6


OptionalDouble average = IntStream.of(1,3).average();
//管道中元素資料平均值average: OptionalDouble[2.0]



int max = IntStream.of(1,3).max().orElse(0);
//管道中元素資料最大值max: 3



IntSummaryStatistics statistics = IntStream.of(1,3).summaryStatistics();
// 全面的統計結果statistics: IntSummaryStatistics{count=3,sum=6,min=1,average=2.000000,max=3}

複製程式碼

期待您的關注