java8新特性-Stream入門學習心得
上一篇介紹了Lambda的學習,如果對Lambda表達式還不清晰的同學可以戳一下這個鏈接:java8新特性-lambda表達式入門學習。
java8除了提供了Lambda表達式,操作集合的Stream API也是非常新特性中最值得學習和掌握的,它大大簡化了,我們操作數(shù)據(jù)集合的代碼量的書寫。
簡單來說Stream是一個抽象概念,可以通過查找,過濾,映射等操作,這一點與Scala中集合操作很類似。
Stream是什么?
通俗的說就是操作數(shù)據(jù)集合的一種手段,你可以使用它,以獲取所需要的集合數(shù)據(jù)源類型,如下圖所示:
通常Stream流操作整個流程是創(chuàng)建流對象->對流操作->獲得目標數(shù)據(jù)源操作

創(chuàng)建Stream
通過Collection接口提供的Stream
1.返回一個順序流
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
2.返回一個并行流
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
那我們簡單演示一下這兩個流的使用。
Emplyee的基本實體類
package com.codegeek.lambda;
import lombok.*;
@Setter
@Getter
@NoArgsConstructor
@ToString
public class Employee {
/**
* 員工姓名
*/
private String name;
/**
* 員工年齡
*/
private int age;
/**
* 基本薪水
*/
private double basicSalary;
/**
* 訂單成交總額
*/
private double dealTotalPrice;
public Employee(String name, int age, double basicSalary,double dealTotalPrice) {
this.name = name;
this.age = age;
this.basicSalary = basicSalary;
this.dealTotalPrice = dealTotalPrice;
}
/**
* 員工總薪資=基本薪資+提成薪資
*
* @return Double
*/
public Double getTotalSalary() {
return this.basicSalary + this.dealTotalPrice * 0.04;
}
}
測試方法如下:
@Test
public void test() {
Employee qingLong = new Employee("青龍", 25, 5500, 7500);
Employee baiHu = new Employee("白虎", 27, 5000, 9000);
Employee zhuQue = new Employee("朱雀", 22, 3800, 4500);
Employee xuanWu = new Employee("玄武", 24, 3300, 3300);
List<Employee> employees = Arrays.asList(qingLong, baiHu, zhuQue, xuanWu);
// 得到一個順序流,并獲取工資大與4000的員工的姓名
Stream<Employee> stream = employees.stream();
stream.filter(e-> e.getTotalSalary()>4000).map(Employee::getName).forEach(System.out::println);
// 得到一個并行流,獲取年齡大于25的員工姓名
Stream<Employee> employeeStream = employees.parallelStream();
employeeStream.filter(employee -> employee.getAge()> 25).map(Employee::getName).forEach(System.out::println );
}
通過Arrays創(chuàng)建Stream流
注意數(shù)組里面是什么類型的數(shù)組,就會產(chǎn)生同類型的流。
1.產(chǎn)生IntStream
public static IntStream stream(int[] array) {
? ?return stream(array, 0, array.length);
}2.產(chǎn)生LongStream
public static LongStream stream(long[] array) {
?return stream(array, 0, array.length);
}3.產(chǎn)生DoubleStream
?public static DoubleStream stream(double[] array) {
? ?return stream(array, 0, array.length);
}下面簡單演示以下IntStream的使用案列
// 初始化一個數(shù)組對象
?int[] arr = {11, 55, 44, 20, 45, 16};
// 通過Arrays創(chuàng)建流對象是IntStream
?Arrays.stream(arr).sorted().forEach(System.out::println);Stream常見的操作
上面簡單介紹了下,流的創(chuàng)建,當流創(chuàng)建好后,我們又該如何使用呢,常見流的操作如下?
- 過濾和切片
| 方法 | 方法介紹 |
|---|---|
| filter(Predicate<? super T> predicate) | 接收斷言接口,并從流中排除元素 |
| distinct() | 去除流中重復的元素 |
| limit(long maxSize) | 截取流中元素個數(shù),類似sql查詢limit |
| skip(long n) | 跳過元素,跳過前n個元素 |
使用演示:
@Test
public void testFilter() {
int[] age = {11, 22, 44, 22, 24, 24, 66, 77, 77, 25, 34};
// 使用filter過濾獲得大于33的數(shù)組元素
Arrays.stream(age).filter(i -> i > 33).forEach(System.out::println);
// 去重
Arrays.stream(age).distinct().forEach(System.out::println);
// 截取3個元素
Arrays.stream(age).limit(3).forEach(System.out::println);
// 跳過前3個元素
Arrays.stream(age).skip(3).forEach(System.out::println);
}
- 映射
| 方法 | 方法介紹 |
|---|---|
| map(Function mapper) | 接收一個函數(shù)式接口,將會映射到流中的每一個元素 |
| mapToDouble(ToDoubleFunction mapper) | 接收函數(shù)式接口,將映射產(chǎn)生DoubleStream |
| mapToLong(ToLongFunction mapper) | 接收函數(shù)式接口,將映射產(chǎn)生LongStream |
| mapToInt(ToIntFunction mapper) | 接收函數(shù)式接口,將映射產(chǎn)生IntStream |
| flatMap(Function extends Stream mapper) | 接收函數(shù),將流中的每個值都轉(zhuǎn)換一個流,然后將這些流匯成一個流 |
使用演示:
String[] arr = {"java", "scala", "php", "python", "c++"};
// 將流中的每一個元素轉(zhuǎn)換成大寫
Arrays.stream(arr).map(String::toUpperCase).forEach(System.out::println);
//將流中的數(shù)據(jù)轉(zhuǎn)Double類型
long[] array = {1, 4, 6, 7, 12};
// 返回Double類型的Stream
Arrays.stream(array).mapToDouble(e-> e* 100).forEach(System.out::println);
// 返回Long類型的Stream
Arrays.stream(array).mapToLong(e -> e + 23).forEach(System.out::println);
// flatMap演示
List<List<String>> database = new ArrayList<>();
List<String> noSql = Arrays.asList("redis", "hbase", "membercache");
List<String> sql = Arrays.asList("mysql", "oracle", "db2");
database.add(noSql);
database.add(sql);
List<String> h = database.stream().flatMap(s -> s.stream().filter(si -> si.contains("h"))).collect(Collectors.toList());
h.stream().forEach(System.out::println);
- 排序
- 排序相對簡單,以之前定義的employee類如下:
Employee qingLong = new Employee("青龍", 25, 5500, 7500);
Employee baiHu = new Employee("白虎", 27, 5000, 9000);
Employee zhuQue = new Employee("朱雀", 22, 3800, 4500);
Employee xuanWu = new Employee("玄武", 24, 3300, 3300);
List<Employee> employees = Arrays.asList(qingLong, baiHu, zhuQue, xuanWu);
// 按照薪水的大小進行排序
employees.stream().sorted(Comparator.comparing(Employee::getTotalSalary)).forEach(System.out::println);
- 查找與匹配
| 方法 | 方法介紹 |
|---|---|
| allMatch(Predicate p) | 檢查流中的元素是否都匹配 |
| anyMatch(Predicate p) | 檢查是否匹配一個元素 |
| noneMatch(Predicate p) | 檢查是否沒有匹配所有元素 |
| findFirst() | 返回第一個元素 |
| findAny() | 返回流中任意元素 |
| count | 返回流中的個數(shù) |
| max(Comparator c) | 返回流中最大值 |
| min(Comparator c) | 返回流中最小值 |
方法演示:以初始化的員工類
// 判斷所有的員工年齡是否大于18
boolean b = employees.stream().allMatch(e -> e.getAge() > 18);
System.out.println("allMatch="+b);// 結(jié)果為true
// 判斷所有員工中有沒有年齡大于35的
boolean b1 = employees.stream().anyMatch(e -> e.getAge() > 35);
System.out.println("anyMath=" + b1); // 結(jié)果為false
// 判斷所有員工中沒有年齡大于35的
boolean b1 = employees.stream().noneMatch(e -> e.getAge() > 35);
System.out.println("anyMath=" + b1); // 結(jié)果為true
// 返回第一個員工的信息
Optional<Employee> first = employees.stream().findFirst();
System.out.println(first.get());
// 統(tǒng)計年齡大于20的員工個數(shù)
ong count = employees.stream().filter(e -> e.getAge() > 20).count();
System.out.println("count="+count);
// 統(tǒng)計集合中員工薪資最高的員工信息
Optional<Employee> max = employees.stream().max(Comparator.comparing(Employee::getTotalSalary));
System.out.println("max=" + max);
- 歸約
| 方法 | 方法介紹 |
|---|---|
| reduce(BinaryOperator p) | 將流中的元素反復結(jié)合起來得到一個值返回Optional |
| reduce(T iden,BinaryOperator p) | 將流中的元素反復結(jié)合起來得到一個值T |
演示:
Optional<Double> reduce = employees.stream().map(Employee::getTotalSalary).reduce(Double::sum);
double v = reduce.get();
System.out.println("reduce="+v);
int[] array = {1, 4, 6, 7, 12};
System.out.println("====");
// 這里第一次將0作為x的值然后數(shù)組中1作為y,然后計算后的結(jié)果是1,第二次將1作為x的值,然后數(shù)組中的4作為y值進行相加,后面以此類推,直到將所有的值都進行相加
int reduce = Arrays.stream(array).reduce(0, (x, y) -> x + y);
System.out.println("reduce=" + reduce);
- 收集
| 方法 | 方法介紹 |
|---|---|
| collect(Collector c) | 將流轉(zhuǎn)換為其他形式,接收Collector接口實現(xiàn)。 |
下面將對Stream做一個總體的回顧和使用。
@Test
public void test() {
// 避免空指針異常
Optional<Employee> optional = employees.stream().sorted((e1, e2) -> e1.getTotalSalary().compareTo(e2.getTotalSalary())).findFirst();
// 若空指針異常就怎么處理
optional.orElse(new Employee());
System.out.println(optional);
// 返回任意一個(并行開啟多個線程查找)
Optional<Employee> any = employees.parallelStream().filter((e) -> e.getAge() > 25).findAny();
System.out.println(any);
// Max(Comparator按年齡比較)
Optional<Employee> max = employees.stream().max(Comparator.comparing((e) -> e.getAge()));
System.out.println(max);
Optional<Double> max1 = employees.stream().map(Employee::getTotalSalary().max(Double::compare);
System.out.println(max1.get());
// 流中元素接收,計算得到一個
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Integer reduce = list.stream().reduce(0, (x, u) -> x + u);//0+1+2.....+10
System.out.println(reduce);
Optional<Integer> reduce1 = employees.stream().map(Employee::getAge).reduce(Integer::sum);
System.out.println(reduce1.get() + "----------");
// 收集元素到list
employees.stream().map(Employee::getName).distinct().collect(Collectors.toList()).forEach(System.out::println);
System.out.println();
// 收集元素到LinkList
employees.stream().map(Employee::getName).distinct().collect(Collectors.toCollection(HashSet::new)).forEach(System.out::println);
// 獲取流中最大值
Optional<Integer> max2 = employees.stream().map(Employee::getAge).max(Integer::compare);
System.out.println(max2.get());
// 收集獲取總數(shù)(集合總數(shù))
Long collect = employees.stream().collect(Collectors.counting());
System.out.println(collect);
// 工資的平均值
Double collect1 = employees.stream().collect(Collectors.averagingDouble(Employee::getTotalSalary));
System.out.println(collect1);
// 獲取工資的總數(shù),綜合,最小值,平均值,最大值
DoubleSummaryStatistics collect2 = employees.stream().collect(Collectors.summarizingDouble(Employee::getTotalSalary));
System.out.println(collect2);
// 獲取年齡最大的員工
Optional<Employee> collect3 = employees.stream().collect(Collectors.maxBy((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())));
System.out.println(collect3.get());
// 獲取年齡最小的員工
Optional<Double> collect4 = employees.stream().map(Employee::getTotalSalary).collect(Collectors.minBy(Double::compare));
System.out.println(collect4.get());
// 按薪資分組
Map<Double, List<Employee>> collect5 = employees.stream().collect(Collectors.groupingBy(Employee::getTotalSalary));
System.out.println(collect5);
// 薪資分區(qū)(匹配true)
Map<Boolean, List<Employee>> collect6 = employees.stream().collect(Collectors.partitioningBy((e) -> e.getTotalSalary() > 5000d));
System.out.println(collect6);
}
總結(jié)
到這里Stream介紹基本完成了。以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java兩種方法計算出階乘尾部連續(xù)0的個數(shù)
這篇文章主要介紹了Java兩種方法計算出階乘尾部連續(xù)0的個數(shù),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-03-03
在java中 利用匿名內(nèi)部類進行較簡潔的雙括弧初始化的方法
本篇文章小編將為大家介紹,關(guān)于在java中 利用匿名內(nèi)部類進行較簡潔的雙括弧初始化的方法,有需要的朋友可以參考一下2013-04-04
使用Spring Security集成手機驗證碼登錄功能實現(xiàn)
本文詳細介紹了如何利用SpringSecurity來實現(xiàn)手機驗證碼的注冊和登錄功能,在登錄過程中,同樣需通過驗證碼進行驗證,文章還提供了相關(guān)的代碼實現(xiàn)2024-10-10
MyBatis使用嵌套查詢collection和association的實現(xiàn)
本文詳細介紹了使用MyBatis框架進行數(shù)據(jù)庫操作時,如何利用collection標簽實現(xiàn)一對多的嵌套查詢和使用association標簽實現(xiàn)一對一的嵌套查詢,感興趣的可以了解一下2024-09-09
詳解Spring Cloud Gateway修改請求和響應body的內(nèi)容
這篇文章主要介紹了Spring Cloud Gateway修改請求和響應body的內(nèi)容的相關(guān)資料,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-09-09
java實現(xiàn)切割wav音頻文件的方法詳解【附外部jar包下載】
這篇文章主要介紹了java實現(xiàn)切割wav音頻文件的方法,結(jié)合實例形式詳細分析了java切割wav音頻文件的相關(guān)原理、操作技巧與注意事項,并附帶外部jar包供讀者下載,需要的朋友可以參考下2019-05-05

