1. 程式人生 > >JAVA8新特性--集合流操作Stream

JAVA8新特性--集合流操作Stream

Stream類全路徑為:java.util.stream.Stream
對Stream的描述,引用其他文章中覺得比較好的介紹:

Java 8 中的 Stream 是對集合(Collection)物件功能的增強,它專注於對集合物件進行各種非常便利、高效的聚合操作(aggregate operation),或者大批量資料操作 (bulk data operation)。Stream API 藉助於同樣新出現的 Lambda 表示式,極大的提高程式設計效率和程式可讀性。

即Stream的原理:

這種風格將要處理的元素集合看作一種流, 流在管道中傳輸, 並且可以在管道的節點上進行處理, 比如篩選, 排序,聚合等。元素流在管道中經過中間操作(intermediate operation)的處理,最後由最終操作(terminal operation)得到前面處理的結果。

集合有兩種方式生成流:
- stream() − 為集合建立序列流。
- parallelStream() − 為集合建立並行流。

併發模式(parallelStream)能夠充分利用多核處理器的優勢,使用 fork/join 並行方式來拆分任務和加速處理過程。java中也提供了多種並行處理的方式,看到一片文章對各幾種並行的方式效能進行了測試,可以參考下:java中幾種並行方式的效能分析

Stream的的中間操作(intermediate)和最終操作(terminal)都包含哪些方法可以從類結構中看到:
這裡寫圖片描述
這裡寫圖片描述
上面截圖基本包含了Strram的所有方法。

  • 中間操作(intermediate)主要有以下方法(此型別的方法返回的都是Stream物件):
    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

此處按照類結構(截圖)中的方法的順序(以下例子中使用了Lambda表示式及方法引用,不瞭解的請戳Lambda介紹方法引用),進行介紹:

  • filter:通過設定條件來過濾元素。
List<String> list = Arrays.asList("aaa","ddd"
,"bbb","ccc","a2a","d2d","b2b","c2c","a3a","d3d","b3b","c3c"); list.stream() .filter((s)->s.contains("a")) .forEach(s -> System.out.println(s));

以上程式碼使用filter方法過濾出只包含”a”的元素,然後通過forEach將滿足條件的元素遍歷出來。輸出如下:

aaa
a2a
a3a

  • map:就是將對應的元素使用給定方法進行轉換。
list.stream()
        .filter((s)->s.contains("a"))
        .map((s)-> s + "---map")
        .forEach(s -> System.out.println(s));

在filter的基礎上,給每個元素後面新增字串”—map”,輸出如下:

aaa—map
a2a—map
a3a—map

  • mapToInt:和map方法進行一樣的操作,但是轉換函式必須返回int型別
  • mapToLong:和map方法進行一樣的操作,但是轉換函式必須返回long型別
  • mapToDouble:和map方法進行一樣的操作,但是轉換函式必須返回double型別
    此處以mapToInt進行演示:
list.stream()
        .filter((s)->s.contains("a"))
        .mapToInt((s)-> s.hashCode())
        .forEach(s -> System.out.println(s));

在filter的基礎上,將每個元素轉換為其hashCode。輸出為:

96321
94864
94895

  • flatMap:如果流的元素為陣列或者Collection,flatMap就是將每個Object[]元素或Collection<Object>元素都轉換為Object元素,如下:

Stream<String[]> 轉換為 Stream<String>
Stream<Set> 轉換為 Stream<String>
Stream<List> 轉換為 Stream<String>
Stream<List> 轉換為 Stream<Object>

看下例子:

List<String[]> setList =  new ArrayList<>();
setList.add(new String[]{"aa","bb"});
setList.add(new String[]{"cc","dd"});
setList.add(new String[]{"ee","ff"});
//使用map方法
setList.stream()
        .map(s->Arrays.stream(s))
        .forEach(s-> System.out.println("map==" + s));
//使用flatMap方法
setList.stream()
        .flatMap(s->Arrays.stream(s))
        .forEach(s-> System.out.println("flatMap==" + s));

輸出如下:

map==java.util.stream.ReferencePipeline&[email protected]
map==java.util.stream.ReferencePipeline&[email protected]
map==java.util.stream.ReferencePipeline&[email protected]
flatMap==aa
flatMap==bb
flatMap==cc
flatMap==dd
flatMap==ee
flatMap==ff

可以看出map就是將陣列流直接返回,flatMap是將陣列流中的每個元素都返回flatMapToIntflatMapToLongflatMapToDouble類似,只不過返回的是對應的型別的流,此處不做演示。

  • distinct:將集合中的元素去重。
List<String> disList = Arrays.asList("aaa","ddd","bbb","ddd","aaa");
disList.stream()
        .distinct()
        .forEach(s-> System.out.println(s));

輸出如下:

aaa
ddd
bbb

  • sorted:將集合中的元素排序。
List<Integer> integerList = Arrays.asList(1,2,3,4);
integerList.stream()
        .sorted()
        .forEach(s-> System.out.println(s));

輸出如下:

1
2
3
4

可以按照自定義排序:

integerList.stream()
        .sorted((s1,s2)->s2.compareTo(s1))
        .forEach(s-> System.out.println(s));

輸出如下:

4
3
2
1

  • peek:生成一個包含原Stream的所有元素的新Stream,同時會提供一個消費函式即引用的方法A,當Stream每個元素被消費的時候都會先執行新Stream給定的方法A。peek是中間操作,如果pee後沒有最終操作,則peek不會執行。
integerList.stream()
        .peek(s-> System.out.println("peek = "+s));

此時沒有輸出,程式碼改為:

integerList.stream()
        .peek(s-> System.out.println("peek = "+s))
        .forEach(s-> System.out.println("forEach = "+s));

輸出如下:

peek = 1
forEach = 1
peek = 2
forEach = 2
peek = 3
forEach = 3
peek = 4
forEach = 4

  • limit:返回Stream的前n個元素。
integerList.stream()
        .limit(1)
        .forEach(s-> System.out.println(s));

輸出為:

1

  • skip:刪除Stream的前n個元素。
integerList.stream()
        .skip(1)
        .forEach(s-> System.out.println(s));

輸出如下:

2
3
4

  • forEach:遍歷Stream中的每個元素,前面每個例子都有使用,此處不再演示。
  • forEachOrdered:遍歷Stream中的每個元素。
    區別
    在序列流(stream)中沒有區別,在並行流(parallelStream)中如果資料來源是有序集合,forEachOrdered輸出順序與資料來源中順序一致,forEach則是亂序。

看下使用forEach:

integerList.stream()
        .forEach(s-> System.out.println(s));

輸出(多次測試,每次結果都不一樣):

3
1
4
2

再看使用forEachOrdered:

integerList.parallelStream()
        .forEachOrdered(s-> System.out.println(s));

輸出(測試多次,每次都是這個結果,與integerList中的元素順序一致):

2
1
3
4

  • toArray:將流轉換為Object[]或者指定型別的陣列。
Object[] array = integerList.stream().toArray();
String[] strArr = integerList.stream().toArray(String[]::new);
  • reduce:將集合中的每個元素聚合成一條資料。有三種情況:
  • reduce(BinaryOperator accumulator):此處需要一個引數,返回Optional物件:
Optional<Integer> reduce = integerList.stream().reduce((a, b) -> a + b);
  • reduce(T identity, BinaryOperator accumulator):此處需要兩個引數,第一個引數為起始值,第二個引數為引用的方法。從起始值開始,每個元素執行一次引用的方法(方法引用的中的兩個引數:第一個引數為上個元素執行方法引用的結果,第二個引數為當前元素)。
int integer = integerList.stream().reduce(5,(a, b) -> a + b);
System.out.println(integer);

輸出為:

15

此例中使用起始值為5,對集合中每個元素求和,可以理解為:5+2+1+3+4=15。

  • reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner):此處需要三個引數。此方法用在併發流(parallelStream)中,啟動多個子執行緒使用accumulator進行平行計算,最終使用combiner對子執行緒結果進行合併,返回identity型別的資料,看到有篇文章對這個解釋比較清楚:java8中3個引數的reduce方法怎麼理解?
  • collect:將流轉換成集合或聚合元素。有兩種情況。接受一個引數和接受三個引數(三個引數在併發流parallelStream中使用),此處介紹一個引數的情況,單個引數接受的引數型別為Collector,Collectors 類實現了很多歸約操作,詳見:java8之collector
List<Integer> collects = integerList.stream()
        .filter(a -> a > 1)
        .collect(Collectors.toList());
System.out.println(collects);

此處統計集合中大於1的元素並最終返回list。輸出如下:

[2, 3, 4]

  • min:獲取集合中最小值。
Integer min = integerList.stream()
        .filter(a -> a > 1)
        .min((Integer a, Integer b) -> a.compareTo(b))
        .get();
System.out.println(min);

輸出為:

2

  • max:獲取集合中最大值。
Integer max = integerList.stream()
        .filter(a -> a > 1)
        .max((Integer a, Integer b) -> a.compareTo(b))
        .get();
System.out.println(max);

輸出為:

4

  • count:獲取集合中元素個數
long count = integerList.stream()
        .filter(a -> a > 1)
        .count();
System.out.println(count);

輸出為:

3

  • anyMatch: Stream 中任意一個元素符合傳入的 predicate,返回 true
  • allMatch:Stream 中全部元素符合傳入的 predicate,返回 true
  • noneMatch:Stream 中沒有一個元素符合傳入的 predicate,返回 true
boolean b = integerList.stream()
        .anyMatch(s -> s > 0);
boolean b1 = integerList.stream()
        .allMatch(s -> s > 0);
boolean b2 = integerList.stream()
        .noneMatch(s -> s > 0);
System.out.println("anyMatch = " + b);
System.out.println("allMatch = " + b1);
System.out.println("noneMatch = " + b2);

輸出:

anyMatch = true
allMatch = true
noneMatch = false

  • findFirst:如果資料來源是有序集合,返回Stream 中第一個元素的Optional物件,如果是無序集合,則返回Stream 中任意一個元素的Optional物件。
Integer first = integerList.stream()
        .findFirst()
        .get();
System.out.println(first);

輸出為:

2

  • findAny:返回Stream 中任意一個元素的Optional物件。
Integer any = integerList.stream()
        .findAny()
        .get();
System.out.println(any);

輸出為:

2

Stream還有幾個靜態方法,返回都是Stream物件。
靜態方法如下:builder(返回Builder物件)、empty、of、iterate、generate、concat。
builder:返回一個Builder物件,Builder物件在呼叫build()返回Stream物件。
empty:返回一個空的有序的Stream物件。
of:返回包含單個元素的有序的Stream物件。
iterate:返回一個無限元素的有序的Stream物件。需要兩個引數,第一個引數為初始值,第二個引數為要引用的方法,然後會通過遞迴迴圈呼叫引用的方法。

Stream.iterate(2,s->s+s)
        .limit(10)
        .forEach(s-> System.out.println(s));

輸出為:

2
4
8
16
32
64
128
256
512
1024

generate:返回一個無限元素的無序的的Stream物件。需要一個引數,引數為引用的方法,然後會通過迴圈呼叫引用的方法來生成元素,常用於生成常量Stream和隨機元素Stream。
concat:將兩個Stream連線成一個Stream。需要兩個Stream作為引數,如果兩個Stream都是有序的並且無論引數Stream是否是並行Stream,得到的都是有序的Stream。輸出元素順序為先輸出第一個Stream的元素,然後輸出第二個Stream的元素。當結果Stream關閉時候,兩個引數Stream同時關閉。

Stream.concat(integerList.stream(),disList.stream())
        .forEach(s-> System.out.println(s));

輸出為:

2
1
3
4
11
aaa
ddd
33
bbb
ddd
aaa

相關推薦

JAVA8特性--合流操作Stream

Stream類全路徑為:java.util.stream.Stream 對Stream的描述,引用其他文章中覺得比較好的介紹: Java 8 中的 Stream 是對集合(Collection)物件功能的增強,它專注於對集合物件進行各種非常便利、高效的

三、java8特性 lambda表示式在stream中的應用

1.關於JSR335 JSR是Java Specification Requests的縮寫,意思是Java 規範請求,Java 8 版本的主要改進是 Lambda 專案(JSR 335),其目的是使 Java 更易於為多核處理器編寫程式碼。JSR 335=lambda表示式

java8 特性-流式操作

一. 流式處理簡介 在我接觸到java8流式處理的時候,我的第一感覺是流式處理讓集合操作變得簡潔了許多,通常我們需要多行程式碼才能完成的操作,藉助於流式處理可以在一行中實現。比如我們希望對一個包含字串的集合中篩選出所有包含指定字串的元素,並將其封裝成為一個新的

Java8特性(lambda、Stream、Optional)

1、λ表示式lambda表示式:λ表示式是Java8新增的一個特性,《Core Java》中的對它的解析是——“一個可傳遞的程式碼塊,可以在以後執行一次或多次”。從日常開發的角度來看,它可以簡化我們的很

2020了你還不會Java8特性?方法引用詳解及Stream 流介紹和操作方式詳解(三)

方法引用詳解 方法引用: method reference 方法引用實際上是Lambda表示式的一種語法糖 我們可以將方法引用看作是一個「函式指標」,function pointer 方法引用共分為4類: 類名::靜態方法名 引用名(物件名)::例項方法名 類名::例項方法名 (比較不好理解,個地方呼叫的方

Java8特性Stream API有哪些中間操作?看完你也可以吊打面試官!!

## 寫在前面 > 在上一篇《[【Java8新特性】面試官問我:Java8中建立Stream流有哪幾種方式?](https://www.cnblogs.com/binghe001/p/12961977.html)》中,一名讀者去面試被面試官暴虐!歸根結底,那哥兒們還是對Java8的新特性不是很瞭解呀!

Java8特性】面試官:談談Java8中的Stream API有哪些終止操作

## 寫在前面 > 如果你出去面試,面試官問了你關於Java8 Stream API的一些問題,比如:Java8中建立Stream流有哪幾種方式?(可以參見:《[【Java8新特性】面試官問我:Java8中建立Stream流有哪幾種方式?](https://www.cnblogs.com/binghe

java8特性-Stream

mat color img reac def list collect array java8 Java8中的Collection接口被擴展,提供了兩個獲取流的方法: default Stream<E>

java8特性學習:stream與lambda

包含 term strong java statistic 管道 特定 getname java8新特性 Streams api 對 Stream 的使用就是實現一個 filter-map-reduce 過程,產生一個最終結果,或者導致一個副作用(side effect)

36套精品Java高級課,架構課,java8新特性,P2P金融項目,程序設計,功能設計,數據庫設計,第三方支付,web安全,高並發,高性能,高可用,分布式,群,電商,緩存,性能調優,設計模式,項目實戰,大型分布式電商項目實戰視頻教程

java cti 投資 調優 dubbo pac 性能 -s clas 36套精品Java高級課,架構課,java8新特性,P2P金融項目,程序設計,功能設計,數據庫設計,第三方支付,web安全,高並發,高性能,高可用,分布式,集群,電商,緩存,性能調優,設計模式,項

java8 特性 Stream

ons match 方法 ams foreach jpg 在一起 classes ora 1. Stream初體驗 我們先來看看Java裏面是怎麽定義Stream的: A sequence of elements supporting sequential and

Java8特性Stream詳解二

       最近在公司的專案中常用Stream結合Lambda表示式來操作集合,使得專案整體程式碼簡潔和整齊;並且上一章也講了一些關於Stream的常用操作,比如:map()、filter()、concat()、reduce()、max()、min()、

Java8特性Stream詳解一

寫了Lambda表示式的部落格,怎麼能少了對Stream的學習呢!接下來就將我所理解的Stream分享給大家,歡迎指出不足之處... 一、為什麼要使用Stream?Stream是什麼?在Java中該怎麼用呢?        (1)為什麼要使用Str

java8特性——Stream介面

Stream介面 1,stream的foreach方法 Stream不是一個數據結構,不直接儲存資料,它通過管道來操作資料。 建立Stream介面實現類物件: stream():建立一個Stream介面實現類的物件: Stream<Person> stream = P

java8特性 lambda Stream map(函數語言程式設計)

1.介面的預設方法 Java 8允許我們給介面新增一個非抽象的方法實現,只需要使用 default關鍵字即可,這個特徵又叫做擴充套件方法 //Formula表示一個設計 計算公式 的介面 public interface Formula { //計算 double calculate

JAVA8特性Stream API

重要的 Stream API  : java.util.Stream.* Stream提供了一種高效且簡易處理資料的方式 注意:1.Stream自己不會儲存元素            2.對Stream進行操作不會改變資料來源,相反,

Java8特性Stream舉例

說明:分別用常規程式碼和Lambda舉例 計算集合空字串數量 List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl"); //1.

java8特性 stream、lambde、optional

一、stream: stream() − 為集合建立序列流。 parallelStream() − 為集合建立並行流。 forEach Stream 提供了新的方法 'forEach' 來迭代流中的每個資料。以下程式碼片段使用 forEach 輸出了1

看透Java8特性:lambda表示式和Stream API

Java11前兩天都發布了,Java8還沒搞清都有啥,這就很尷尬了~ Java8 的新特性:Lambda表示式、強大的 Stream API、全新時間日期 API、ConcurrentHashMap、MetaSpace。Java8 的新特性使 Java 的執行速度更快、程式碼更少(Lambda 表示式)、便

JAVA8特性Stream簡介以及建立

一:Stream簡介        1:什麼是Streatm?                         2:為什麼需要Stream?                        3:Stream操作的三個步驟               二:建立流的方式