详解Java8中流(Stream)的使用
文章列表
- 一、回憶Lambda表達式
- 二、什么是流
- 1、流只能遍歷一次
- 2、外部迭代和內部迭代
- 三、流操作
- 1、謂詞篩選
- 2、篩選各異元素
- 3、截段流
- 4、跳過元素
- 5、map和flatMap
- 6、查找和匹配
- 7、歸約reduce
寫在前面:
我是「境里婆娑」。我還是從前那個少年,沒有一絲絲改變,時間只不過是考驗,種在心中信念絲毫未減,眼前這個少年,還是最初那張臉,面前再多艱險不退卻。
寫博客的目的就是分享給大家一起學習交流,如果您對 Java感興趣,可以關注我,我們一起學習。
前言:還沒接觸過流的同學可以深入研究下此篇文章,讓你在寫代碼過程中可以讓你達到事半功倍效果。
一、回憶Lambda表達式
在學習流之前,我們先回憶一下Lambda表達式和函數式接口
| 布爾表達式 | (List< String> list -> list.isEmpty()) | Predicate<(List< String>> |
| 創建對象 | () -> new Car() | Supplier< Car> |
| 消費一個對象 | (Car car) -> System.out.println(car.getColor) | Consumer< Car> |
| 從一個對象提取 | (String s) -> s.length() | Function< String,Integer> |
| 合并兩個值 | (int a,int b) ->a*b | IntBinaryOperator |
| 比較兩個值對象 | (Apple a1,Apple a2) -> a1.getWeigth().compareTo(a2.getWeigth()) | Comparator< Apple>或BiFunction< Apple,Apple,Integer> |
二、什么是流
流是Java 新的API,它允許你以聲明性方式處理數據集合。可以把流看作是遍歷數據集合的高級迭代器。另外,流還可以透明的并行處理,無需寫任何多線程代碼。
public class Car {private String color;private String brand; }例Java7之前,選出小汽車顏色代碼如下:
List<Car> cars = Arrays.asList(new Car("bule", "aodi"), new Car("red", "BMW"), new Car("white", "benw")); List<String> list = new ArrayList<>(); for (Car car : cars) {list.add(car.getColor()); }例Java8之后可以如下:
List<String> collect = cars.stream().map(Car::getColor).collect(toList());總結一下:Java8中的Stream API可以讓你寫出這樣的代碼
- 聲明性 更簡潔,更易懂
- 可復合,更靈活
- 可并行,性能更好
看完上面代碼我們還是有疑惑,流到底是什么呢?簡短定義就是“從支持數據處理操作的源生成的元素序列”
- 元素序列,就像集合一樣,流提供一個接口,可以訪問特定元素類型的有序值。集合是數據結構,目的是以特定的時間/空間復雜度存儲和訪問元素。但流的目的在于表達計算。總的來說集合講的是數據,而流講的是計算。
- 源,流會使用一個提供數據的源,如集合、 數組或輸入輸出資源。
- 數據處理操作,流的數據處理功能支持類似數據庫的操作,以及函數式編程語言中的常用操作,如filter、map、reduce、find、match、sort。流操作可以順序執行,也可以并行執行。
- 流水線,很多流操作本身會返回一個流,這樣多個操作就可以連接起來,形成一個大的流水線。
- 內部迭代,與使用迭代器顯式迭代集合不同,流的迭代操作是在背后執行的。
1、流只能遍歷一次
流還有一個特點就是只能遍歷一次。遍歷完之后,我們說這個流已經被消費掉了。
2、外部迭代和內部迭代
使用Collection接口需要用戶去做迭代比如for-each,這稱為外部迭代。相反,Streams庫使用內部迭代。
采用內部迭代,項目可以透明地并行處理,或者用優化的順序進行處理,要是使用 Java 過去的外部迭代方法,這些優化都是很困難的
三、流操作
1、謂詞篩選
Streams接口支持filter方法,該操作會接受一個謂詞作為參數。
List<Car> aodi = cars.stream().filter(car -> car.getBrand().equals("aodi")).collect(toList());2、篩選各異元素
流還支持一個叫distinct的方法,它會返回一個元素各異的流。以下代碼會篩選出所有基數。
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4); numbers.stream() .filter(i -> i % 2 != 0) .distinct() .forEach(System.out::println);3、截段流
流支持limit方法,該方法會返回一個不超過給定長度的流。所需要的長度作為參數傳遞給limit。
List<Car> aodi = cars.stream().filter(car -> car.getBrand().equals("aodi")).limit(3).collect(toList());請注意limit也可以用在無序流上。比如源是一個Set,這種情況下,limit的結果不會以人物順序排列。
4、跳過元素
流還支持skip方法,返回一個扔掉了前n個元素的流。如果流中的元素不足n,則返回一個空流。注意。limit和skip是互補的。
List<Car> aodi = cars.stream().filter(car -> car.getBrand().equals("aodi")).skip(3).collect(toList());5、map和flatMap
map和flatMap如何選用:假如你的集合流中包含子集合,那么使用flatMap可以返回該子集合的集合流
words.stream() .map(word -> word.split("")) .flatMap(Arrays::stream) .distinct() .collect(toList());如果想詳細了解map和flatMap區別請看這篇文章:java8中map和flatMap區別
6、查找和匹配
另一個常見的數據處理套路是看看數據集中的某些元素是否匹配一個給定的屬性。
- anyMatch,流中是否有一個元素能匹配到給定的謂詞
- allMatch,是否匹配所有元素
- noneMatch,確保流中沒有任何元素與給定的謂詞匹配
allMatch、anyMatch、noneMatch都用到了我們所謂的短路,這就是大家熟悉java中的&&和||運算符。
- findAny返回當前流中的任意元素。
- findFirst()查出第一個元素
findAny()和findFirst()都會返回一個Optional泛型的對象。
Optional 是一個容器類,代表一個值存在或不存在。Optional方法如下:
- isPresent()將在Optional包含值的時候返回true。否則返回false
- ifPresent()會在值存在的時候執行給定代碼塊。
- get()會在值存在返回值。
- orElse()會在值存在時返回值。否則返回一個默認值。
7、歸約reduce
reduce是一個終端操作,比如我們做求和操作。
int sum = numbers.stream().reduce(0, (a, b) -> a + b);比如求最大值和最小值
Optional<Integer> min = numbers.stream().reduce(Integer::max); Optional<Integer> min = numbers.stream().reduce(Integer::min);至此我們把流的基本操作都介紹完。下面我們總結一下哪些是中間操作哪些是終端操作。
———————————————————————————
如果喜歡這篇文章的話請關注我!
總結
以上是生活随笔為你收集整理的详解Java8中流(Stream)的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 警惕由于使用YYYY-MM-dd引发的一
- 下一篇: “ShardingCore”是如何针对分