JAVA8 Stream流的使用

1.Stream簡介

1.Java 8 API添加了一個新的抽象稱爲流Stream,可以讓你以一種聲明的方式處理數據。
2.Stream 使用一種類似用 SQL 語句從數據庫查詢數據的直觀方式來提供一種對 Java 集合運算和表達的高階抽象。
3.Stream API可以極大提高Java程序員的生產力,讓程序員寫出高效率、乾淨、簡潔的代碼。
4.這種風格將要處理的元素集合看作一種流, 流在管道中傳輸, 並且可以在管道的節點上進行處理, 比如篩選, 排序,聚合等。
5.元素流在管道中經過中間操作(intermediate operation)的處理,最後由最終操作(terminal operation)得到前面處理的結果。

以上的流程轉換爲 Java 代碼爲:

+--------------------+       +------+   +------+   +---+   +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+       +------+   +------+   +---+   +-------+

2.Stream的優點

舉個例子: 有一個List列表,我們需要獲得年齡爲70歲的前10個Person的姓名。

過程式的解決方案:

List<Person> personList = fromDB(); // 獲得List<Person>
int limit = 10; // 限制條件
List<String> nameList = new ArrayList(); // 收集的姓名集合
for(Person personItem : personList){
    if(personItem.age == 70){ // 滿足條件
        nameList.add(personItem.name); // 加入姓名集合
        if(nameList.size() >= 10){ // 判斷是否超過限制
            break;
        }
    }
}
return nameList;

函數式stream解決方案:

List<Person> personList = fromDB(); // 獲得List<Person>
List<String> nameList = personList.stream()
      .filter(item->item.age == 70) // 過濾條件
      .limit(10)    // limit限制條件
      .map(item->item.name) // 獲得姓名
      .collect(Collector.toList()); // 轉化爲list
      .forEach(System.out::println);//遍歷並打印

return nameList;

兩種方案的不同之處:

1.從函數式的角度上看,過程式的代碼實現將收集元素、循環迭代、各種邏輯判斷耦合在一起,暴露了太多細節。當未來需求變動和變得更加複雜的情況下,過程式的代碼將變得難以理解和維護(需要控制檯打印出 年齡爲70歲的前10個Person中,姓王的Person的名稱)。

2.函數式的解決方案解開了代碼細節和業務邏輯的耦合,類似於sql語句,表達的是"要做什麼"而不是"如何去做",使程序員可以更加專注於業務邏輯,寫出易於理解和維護的代碼。

3.生成流和操作示例

在 Java 8 中, 集合接口有兩個方法來生成流:

  1. stream() − 爲集合創建串行流。

  2. parallelStream() − 爲集合創建並行流。

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
forEach

Stream 提供了新的方法 ‘forEach’ 來迭代流中的每個數據。以下代碼片段使用 forEach 輸出了10個隨機數:

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
map

map 方法用於映射每個元素到對應的結果,以下代碼片段使用 map 輸出了元素對應的平方數:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 獲取對應的平方數
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filter

filter 方法用於通過設置的條件過濾出元素。以下代碼片段使用 filter 方法過濾出空字符串:

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 獲取空字符串的數量
long count = strings.stream().filter(string -> string.isEmpty()).count();
limit

limit 方法用於獲取指定數量的流。 以下代碼片段使用 limit 方法打印出 10 條數據:

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
sorted

sorted 方法用於對流進行排序。以下代碼片段使用 sorted 方法對輸出的 10 個隨機數進行排序:

Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
Collectors

Collectors 類實現了很多歸約操作,例如將流轉換成集合和聚合元素。Collectors 可用於返回列表或字符串:

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
 
System.out.println("篩選列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合併字符串: " + mergedString);
統計

另外,一些產生統計結果的收集器也非常有用。它們主要用於int、double、long等基本類型上,它們可以用來產生類似如下的統計結果。

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
 
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
 
System.out.println("列表中最大的數 : " + stats.getMax());
System.out.println("列表中最小的數 : " + stats.getMin());
System.out.println("所有數之和 : " + stats.getSum());
System.out.println("平均數 : " + stats.getAverage());
並行(parallel)程序

parallelStream 是流並行處理程序的代替方法。以下實例我們使用 parallelStream 來輸出空字符串的數量:

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 獲取空字符串的數量
int count = strings.parallelStream().filter(string -> string.isEmpty()).count();

我們可以很容易的在順序運行和並行直接切換。

4.補充

上述代碼中->這是Java8裏新加入的特性lambda表達式,相當於無名稱的函數,匿名函數。一個簡單的例子是 Collections.sort(list, (x, y) -> y - x); 其中(x, y) -> y - x是一個lambda表達式,輸入兩個參數x, y,返回值 y - x。->起分隔作用。,Java會自動翻譯,這其實也有點類似JS中ES6的箭頭函數。

參考資料:https://www.runoob.com/java/java8-streams.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章