java8 Stream流操作介紹
https://blog.csdn.net/sf_cyl/article/details/51900701
流操作在本人接觸到的部分,都是處理集合容器Collection,加入流操作主要是為了函數語言程式設計,在很大程度上可以簡化程式碼
簡潔的程式碼處理複雜邏輯這是每個程式猿的追求,廢話不多說,開始介紹
使用Stream基本步驟
1. 建立Stream;
2. 轉換Stream,每次轉換原有Stream物件不改變,返回一個新的Stream物件(**可以有多次轉換**);
3. 對Stream進行聚合(Reduce)操作,獲取想要的結果;
Stream 建立
//Lists是Guava中的一個工具類
List<Integer> nums = Lists.newArrayList(1,null,3,4,null,6);
nums.stream().filter(num -> num != null).count();
/**
of方法:有兩個overload方法,一個接受變長引數,一個介面單一值
*/
Stream<Integer> integerStream = Stream.of(1, 2, 3, 5);
Stream<String> stringStream = Stream.of("taobao");
/**
generator方法:生成一個無限長度的Stream,其元素的生成是通過給定的Supplier
*/
Stream.generate(new Supplier<Double>() {
@Override
public Double get() {
return Math.random();
}
});
Stream.generate(() -> Math.random());
Stream.generate(Math::random);
/**
iterate方法:也是生成無限長度的Stream,和generator不同的是,其元素的生成是重複對給定的種子值(seed)
呼叫使用者指定函式來生成的。其中包含的元素可以認為是:seed
*/
Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println);
所有集合類都可以直接呼叫stream()方法返回一個Stream物件
這個在本文的第一個例子中就展示了從List物件獲取其對應的Stream物件,如果檢視Java doc就可以發現Collection介面有一個stream方法,所以其所有子類都都可以獲取對應的Stream物件。
public interface Collection<E> extends Iterable<E> {
//其他方法省略
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
}
轉換Stream
轉化Stream方法有很處理方法,此處全部介紹,介紹幾種,其餘方法的使用都差不多
1. distinct: 對於Stream中包含的元素進行去重操作(去重邏輯依賴元素的equals方法),新生成的Stream中沒有重複的元素;
List<String> list = Arrays.asList("aa", "bb", "cc", "a", "b", "c", "aa", "ab", "cc", "bb", "bc");
list = list.stream().distinct().collect(Collectors.toList()); // [aa, bb, cc, a, b, c, ab, bc]
2. filter: 對於Stream中包含的元素使用給定的過濾函式進行過濾操作,新生成的Stream只包含符合條件的元素
List<String> list = Arrays.asList("aa", "bb", "cc", "a", "b", "c","a", "aa", "ab", "cc", "bb", "bc");
list.stream().filter(e -> e.length()>=2).forEach(e -> System.out.print(e + ","));
// aa,bb,cc,aa,ab,cc,bb,bc,
3. map: 對於Stream中包含的元素使用給定的轉換函式進行轉換操作,新生成的Stream只包含轉換生成的元素。這個方法有三個對於原始型別的變種方法,分別是:mapToInt,mapToLong和mapToDouble。這三個方法也比較好理解,比如mapToInt就是把原始Stream轉換成一個新的Stream,這個新生成的Stream中的元素都是int型別。之所以會有這樣三個變種方法,可以免除自動裝箱/拆箱的額外消耗;
List<Integer> integerList = Arrays.asList(1, 2, 3, 8, 9, 6, 4, 2, 3, 7, 6);
integerList.stream().map(var -> { var ++; var += 2; return var; }).forEach(System.out::print);
DoubleStream doubleStream = integerList.stream().mapToDouble((value) -> value * 1.0);
4. flatMap:和map類似,不同的是其每個元素轉換得到的是Stream物件,會把子Stream中的元素壓縮到父集合中;
List<Integer> together = Stream.of(asList(1, 2),asList(3, 4)).flatMap(numbers -> numbers.stream()).collect(toList());
將兩個佇列一起處理流操作的時候,可以利用此方法將其轉化為一個流
上部分的程式碼可以簡化為
List<Integer> together = Stream.of(Arrays.asList(1, 2),Arrays.asList(3, 4))
.flatMap(Collection::stream).collect(Collectors.toList());
5. peek: 生成一個包含原Stream的所有元素的新Stream,同時會提供一個消費函式(Consumer例項),新Stream每個元素被消費的時候都會執行給定的消費函式;
此方法不會更改流中元素形式,主要用於除錯或輸出。
list.stream().distinct().peek(e -> System.out.println(e.length())).count();
在peek()方法中使用lambda 表示式的時候,返回值只能為void型別
方法暫時只介紹這麼幾個其餘還有 limit() skip() forEach()等
聚合(Reduce)操作
下面會分兩部分來介紹匯聚操作:
1. 可變匯聚:把輸入的元素們累積到一個可變的容器中,比如Collection或者StringBuilder;
List<Integer> nums = Lists.newArrayList(1,1,null,2,3,4,null,5,6,7,8,9,10);
List<Integer> numsWithoutNull = nums.stream().filter(num -> num != null).
collect(() -> new ArrayList<Integer>(),
(list, item) -> list.add(item),
(list1, list2) -> list1.addAll(list2));
上面這段程式碼就是對一個元素是Integer型別的List,先過濾掉全部的null,然後把剩下的元素收集到一個新的List中。進一步看一下collect方法的三個引數,都是lambda形式的函式(*上面的程式碼可以使用方法引用來簡化,留給讀者自己去思考*)。
第一個函式生成一個新的ArrayList例項;
第二個函式接受兩個引數,第一個是前面生成的ArrayList物件,二個是stream中包含的元素,函式體就是把stream中的元素加入ArrayList物件中。第二個函式被反覆呼叫直到原stream的元素被消費完畢;
第三個函式也是接受兩個引數,這兩個都是ArrayList型別的,函式體就是把第二個ArrayList全部加入到第一個中;
但是上面的collect方法呼叫也有點太複雜了,沒關係!我們來看一下collect方法另外一個override的版本,其依賴
<R, A> R collect(Collector<? super T, A, R> collector);
Java8還給我們提供了Collector的工具類–[Collectors]其中已經定義了一些靜態工廠方法,比如:Collectors.toCollection()收集到Collection中, Collectors.toList()收集到List中和Collectors.toSet()收集到Set中。這樣的靜態方法還有很多,這裡就不一一介紹了,大家可以直接去看JavaDoc。下面看看使用Collectors對於程式碼的簡化:
List<Integer> numsWithoutNull = nums.stream().filter(num -> num != null).
collect(Collectors.toList());
2. 其他匯聚:除去可變匯聚剩下的,一般都不是通過反覆修改某個可變物件,而是通過把前一次的匯聚結果當成下一次的入參,反覆如此。比如reduce,count,allMatch;
reduce方法:reduce方法非常的通用,後面介紹的count,sum等都可以使用其實現。reduce方法有三個override的方法,本文介紹兩個最常用的,最後一個留給讀者自己學習。先來看reduce方法的第一種形式,其方法定義如下:
Optional<T> reduce(BinaryOperator<T> accumulator);
接受一個BinaryOperator型別的引數,在使用的時候我們可以用lambda表示式來。
List<Integer> ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
System.out.println("ints sum is:" + ints.stream().reduce((sum, item) -> sum + item).get());
可以看到reduce方法接受一個函式,這個函式有兩個引數,第一個引數是上次函式執行的返回值(也稱為中間結果),第二個引數是stream中的元素,這個函式把這兩個值相加,得到的和會被賦值給下次執行這個函式的第一個引數。要注意的是:**第一次執行的時候第一個引數的值是Stream的第一個元素,第二個引數是Stream的第二個元素**。這個方法返回值型別是Optional,這是Java8防止出現NPE的一種可行方法,後面的文章會詳細介紹,這裡就簡單的認為是一個容器,其中可能會包含0個或者1個物件。
reduce方法還有一個很常用的變種:
T reduce(T identity, BinaryOperator<T> accumulator);
這個定義上上面已經介紹過的基本一致,不同的是:它允許使用者提供一個迴圈計算的初始值,如果Stream為空,就直接返回該值。而且這個方法不會返回Optional,因為其不會出現null值。下面直接給出例子,就不再做說明了。
List<Integer> ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
System.out.println("ints sum is:" + ints.stream().reduce(0, (sum, item) -> sum + item));
count方法:獲取Stream中元素的個數。比較簡單,這裡就直接給出例子,不做解釋了。
List<Integer> ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
System.out.println("ints sum is:" + ints.stream().count());
– 搜尋相關
– allMatch:是不是Stream中的所有元素都滿足給定的匹配條件
– anyMatch:Stream中是否存在任何一個元素滿足匹配條件
– findFirst: 返回Stream中的第一個元素,如果Stream為空,返回空Optional
– noneMatch:是不是Stream中的所有元素都不滿足給定的匹配條件
– max和min:使用給定的比較器(Operator),返回Stream中的最大|最小值
下面給出allMatch和max的例子,剩下的方法讀者當成練習。
List<Integer> ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
System.out.println(ints.stream().allMatch(item -> item < 100));
ints.stream().max((o1, o2) -> o1.compareTo(o2)).ifPresent(System.out::println);
相關文章
- Java8之Stream流(三)縮減操作Java
- Java8——Stream流Java
- Java8的stream流讓操作集合更容易Java
- Java8 新特性 Stream流操作List集合 (二)Java
- node中的流的介紹(Stream)
- java8新特性stream流Java
- Java8 Stream流的合併Java
- Java8之Stream常用操作方式Java
- list轉map,使用java8,stream流Java
- [譯] 一文帶你玩轉 Java8 Stream 流,從此操作集合 So EasyJava
- Java Stream流操作面試題Java面試題
- Java Stream API groupingBy()介紹JavaAPI
- Java8 的 Stream 流式操作之王者歸來Java
- Java8之Stream-強大的collect操作Java
- Java8新特性——從Lambda表示式到Stream流Java
- Stream流的基本介紹以及在工作中的常用操作(去重、排序以及數學運算等)排序
- java .stream(). 使用介紹 Streams APIJavaAPI
- Java Stream 流如何進行合併操作Java
- JAVA基礎之六-Stream(流)簡介Java
- Flownet 介紹 及光流的簡單介紹
- Stream流
- Spring Cloud Stream 體系及原理介紹SpringCloud
- 【Java8新特性】面試官問我:Java8中建立Stream流有哪幾種方式?Java面試
- Can匯流排介紹
- Java開發工程師進階篇-Java8的Stream流使用技巧Java工程師
- etcd 常用操作介紹
- Git 分支操作介紹Git
- SAP工作流介紹之ABAP Business Workflow介紹
- Java8中的Stream APIJavaAPI
- Java8 Stream常用API整理JavaAPI
- Java8的Stream API使用JavaAPI
- Java8新特性--Stream APIJavaAPI
- java8學習:引入streamJava
- Java8 Lambda 之 Collection StreamJava
- 淺析Java8 Stream原理Java
- java8 Stream APi 入門JavaAPI
- Java8中的流操作-基本使用&效能測試Java
- 【Java8新特性】面試官:談談Java8中的Stream API有哪些終止操作?Java面試API