參考鏈接: 如何在Java 8中從Stream獲取ArrayList
摘要?
?Stream 作為 Java 8 的一大亮點,它與 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。它也不同于 StAX 對 XML 解析的 Stream,也不是 Amazon Kinesis 對大數據實時處理的 Stream。Java 8 中的 Stream 是對集合(Collection)對象功能的增強,它專注于對集合對象進行各種非常便利、高效的聚合操作(aggregate operation),或者大批量數據操作 (bulk data operation)。Stream API 借助于同樣新出現的 Lambda 表達式,極大的提高編程效率和程序可讀性。同時它提供串行和并行兩種模式進行匯聚操作,并發模式能夠充分利用多核處理器的優勢,使用 fork/join 并行方式來拆分任務和加速處理過程。通常編寫并行代碼很難而且容易出錯, 但使用 Stream API 無需編寫一行多線程的代碼,就可以很方便地寫出高性能的并發程序。所以說,Java 8 中首次出現的 java.util.stream 是一個函數式語言+多核時代綜合影響的產物。?
簡介?
流(Stream)是數據通道,用于操作數據源(集合,數組等)所生成的元素序列 “集合講的的是數據,流講的是計算” 注意: ?① Stream不會存儲元素 ?② Stream不會改變源對象,相反他們會返回一個持有結果的新的Stream ?③ Stream操作是延遲執行的,這意味著他們等到需要結果的時候才會執行(惰性求值)?
Stream操作的三個步驟?
創建Stream 一個數據源(如:集合,數組)獲取一個流中間操作 一個中間操作鏈,對數據源的數據進行處理終止操作(終端操作) 一個終止操作,執行中間操作鏈,并產生結果??
一:創建Stream?
Collection提供了兩個方法.stream()與paralleStream()?
@org.junit.Test
public void test4(){
? ? List<Integer> list = new ArrayList<>();
? ? Stream<Integer> stream = list.stream();//串行流
? ? Stream<Integer> integerStream = list.parallelStream();//并行流
}
?
通過Arrays中的Stream()獲取一個數組流。?
?Integer[] integers ={};
?Stream<Integer> stream1 = Arrays.stream(integers);
?
通過Stream類中靜態方法of()?
Stream<String> stream2 = Stream.of("aaa", "bbb");
?
創建無限流(無窮的數據)?
? 生成 //通過生成器產生5個10以內的隨機數,如果不使用limit就會無限生成10以內隨機數
Stream.generate(() -> Math.random() * 10).limit(5).forEach(System.out::println);
----------輸出--------
0.8320556195819129
6.260534125204207
7.344094646332503
0.18490598959698068
6.392272744710005
?
? 迭代 //通過迭代的方式(一元運算)生成5個數
Stream.iterate(0,x->x+2).limit(5).forEach(System.out::println);
-------------------輸出------------
0
2
4
6
8
??
二:中間操作?
?
?多個中間操作可以連接起來形成一個流水線,除非流水線上觸發終止操作,否則中間操作不會執行任何的處理,而在終止操作時一次性全部執行,稱為“惰性求值”?
?List<Integer> list = Arrays.asList(1,2,3,523,21,55);
Stream<Integer> stream3 = list.stream().filter(x -> {
? ? ? ? ?System.out.println("函數執行");
? ? ? ? ?return x > 10;
?// stream3.forEach(System.out::println);
?
?上面的代碼沒有終止操作,當你運行時不會打印任何東西?
?
①篩選與切片?
filter----接收Lambda,從流中排除某些元素?
//filter()中需要使用斷言型接口(Predicate)
List<Integer> list = Arrays.asList(1,2,3,523,21,55);
Stream<Integer> stream3 = list.stream().filter(x -> x > 10);
stream3.forEach(System.out::println);
?
limit----截斷流,使其元素不超過給定數量?
List<Integer> list = Arrays.asList(1,2,3,523,21,55);
Stream<Integer> stream3 = list.stream().limit(3);
stream3.forEach(System.out::println);
--------------------輸出---------------------
1
2
3
?
skip----跳過元素返回一個拋棄了前n個元素的流,若流中元素不滿足n個,則返回一個空流,與limit形成互補?
List<Integer> list = Arrays.asList(1,2,3,523,21,55);
Stream<Integer> stream3 = list.stream().skip(3);
stream3.forEach(System.out::println);
--------------------輸出---------------------
523
21
55
?
distinct----篩選,通過流所所生成元素的hashCode()和equals()去除重復元素?
? List<Integer> list = Arrays.asList(1,2,3,3,2,4);
? Stream<Integer> stream3 = list.stream().distinct();
? stream3.forEach(System.out::println);
? --------------------輸出---------------------
? 1
? 2
? 3
? 4
?
注意:自定義的實體類使用distinct去重時,一定要先重寫hashCode()和equals()?
②映射?
map----接收Lambda,將元素轉換為其他形式或提取信息時,接收一個函數作為參數,該函數被應用到每個元素上,并將其映射成一個新的元素//map()里面使用函數型接口(Function)
List<String> list = Arrays.asList("aa","bb","cc");
Stream<String> stream3 = list.stream().map(String::toUpperCase);
stream3.forEach(System.out::println);
----------------------輸出-----------------------
AA
BB
CC
------------------------------------------------
集合里的每一個元素都會使用到String.toUpperCase()方法
它是以aa作為一個元素,bb作為一個元素?
?flatMap----接收一個函數作為參數,將流中的每個值都換成另一個流,然后把所有流連接一個流List<String> list = Arrays.asList("aa","bb","cc");
? ? ? ?Stream<String> stream3 = list.stream().flatMap(l -> {
? ? ? ? ? ?String[] strings = l.split("");
? ? ? ? ? ?return Arrays.stream(strings);
? ? ? ?});
stream3.forEach(System.out::println);
-------------------輸出-----------
a
a
b
b
c
c
-----------------------------------------------
flatMap將原來的流轉換為一個新的流并且,是以每一個值為單位的
?
? ?
? ??
? ??
③排序?
sorted() 自然排序 按照Comparable的方式List<String> list = Arrays.asList("aa","cc","bb");
Stream<String> stream3 = list.stream().sorted();
stream3.forEach(System.out::println);
---------------輸出-----------
aa
bb
cc
?sorted( Comparator com)定制排序 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
?Stream<Integer> stream3 = list.stream().sorted(Integer::compare);
?stream3.forEach(System.out::println);
?--------------輸出--------------
?1
?2
?3
?3
?6
?8
?9
??
終止操作?
①查找與匹配?
allMatch----檢查是否匹配所有元素//allMatch()里面的時斷言型接口(Predicate)
?List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
?boolean b = list.stream().allMatch(x -> x > 3);
?System.out.println(b);
?------------------輸出--------------------
?false
?//因為不是所有的數都大于3
?anyMatch----檢查是否有匹配至少一個元素//anyMatch()里面的時斷言型接口(Predicate)
?List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
?boolean b = list.stream().anyMatch(x -> x > 3);
?System.out.println(b);
? ------------------輸出--------------------
?true
?//只要有大于3的數就返回true
?noneMatch----檢查是否沒有匹配的元素//noneMatch()里面的時斷言型接口(Predicate)
List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
boolean b = list.stream().noneMatch(x -> x > 3);
System.out.println(b);
?------------------輸出--------------------
?false
?//雙重否定,返回false就是有匹配的元素
?findFirst----返回第一個元素List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
Optional<Integer> first = list.stream().findFirst();
System.out.println(first.get());
-----------------輸出----------------
1
?findAny----返回當前流中的任意一元素List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
Optional<Integer> first = list.stream().findAny();
System.out.println(first.get());
-----------------輸出----------------
1
?count-----返回流中元素的總數List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
long count = list.stream().count();
System.out.println(count);
-----------------輸出----------------
7
?max----返回流中最大值 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
?Optional<Integer> max = list.stream().max(Integer::compareTo);
?System.out.println(max.get());
?-----------------輸出----------------
9
?min----返回流中的最小值List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
Optional<Integer> min = list.stream().min(Integer::compareTo);
System.out.println(min.get());
?-----------------輸出----------------
1
?forEach----遍歷流中的元素 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
?list.stream().forEach(System.out::println);
?-----------------輸出----------------
1
3
2
6
8
3
9
//注意:forEach的迭代操作是由Stream API完成的稱為內部迭代
//借助于iterator的方式為外部迭代
??
②歸約?
reduce(T identity,BinaryOperator)—可以將流中元素反復結合起來得到一個值,返回T List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
?Integer reduce = list.stream().reduce(0, (x, y) -> x + y);
?System.out.println(reduce);
?-----------------輸出----------------
?32
?//根據2元運算將所有的數加起來
?//首先以0為x,1為y,結果為1,然后1為x,取3為y,結果為4,以4為x...以此類推
?reduce(BinaryOpreator)----可以將流中元素反復結合起來,返回Optional< T > List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
?Optional<Integer> reduce = list.stream().reduce((x, y) -> x + y);
?System.out.println(reduce.get());
? -----------------輸出----------------
?32
?//原理同上,只是這里沒有初始值,直接取1為x
?//所以ist就有可能為空,當返回的值可能為空時,結果存儲在Optional容器中,避免空指針異常
??
③收集?
collect----將流轉換為其他形式,接收一個Collector接口的實現,用于給Stream中元素做匯總的方法?
?
?Colloector 接口中方法的實現決定了如何對流執行手機操作(如收集到List、Set、Map中)但是Collectots實用類提供了很多靜態方法,可以方便的創建常見收集器實例?
?
接下來進行詳細介紹 首先創建一個實體類?
public class User {
? ? private String name;
? ? private Integer age;
? ? private double salary;
?
? ? public User(String name, Integer age, double salary) {
? ? ? ? this.name = name;
? ? ? ? this.age = age;
? ? ? ? this.salary = salary;
? ? }
?
? ? public String getName() {
? ? ? ? return name;
? ? }
?
? ? public void setName(String name) {
? ? ? ? this.name = name;
? ? }
?
? ? public Integer getAge() {
? ? ? ? return age;
? ? }
?
? ? public void setAge(Integer age) {
? ? ? ? this.age = age;
? ? }
?
? ? public double getSalary() {
? ? ? ? return salary;
? ? }
?
? ? public void setSalary(double salary) {
? ? ? ? this.salary = salary;
? ? }
?
? ? @Override
? ? public String toString() {
? ? ? ? return "User{" +
? ? ? ? ? ? ? ? "name='" + name + '\'' +
? ? ? ? ? ? ? ? ", age=" + age +
? ? ? ? ? ? ? ? ", salary=" + salary +
? ? ? ? ? ? ? ? '}';
? ? }
?
? ? @Override
? ? public boolean equals(Object o) {
? ? ? ? if (this == o) return true;
? ? ? ? if (o == null || getClass() != o.getClass()) return false;
? ? ? ? User user = (User) o;
? ? ? ? return Double.compare(user.salary, salary) == 0 &&
? ? ? ? ? ? ? ? Objects.equals(name, user.name) &&
? ? ? ? ? ? ? ? Objects.equals(age, user.age);
? ? }
?
? ? @Override
? ? public int hashCode() {
? ? ? ? return Objects.hash(name, age, salary);
? ? }
}
?
在測試類中準備好數據?
public class StreamTest {
? ? ?List<User> user = Arrays.asList(new User("張三",12,1000.00),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new User ("李四",32,4000),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new User ("王五",40,4000),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new User ("王五",40,4000));
}
?
根據名稱生成一個新的List?
?List<String> list = user.stream().map(User::getName).collect(Collectors.toList());
?list.forEach(System.out::println);
?-----------------輸出--------------
?張三
?李四
?王五
?王五
?
根據名稱生成一個新的Set?
?Set<String> set = user.stream().map(User::getName).collect(Collectors.toSet());
?set.forEach(System.out::println);
?-----------------輸出--------------
?張三
?李四
?王五
?
根據名稱生成一個新的HashSet?
?HashSet<String> hashSet = user.stream().map(User::getName).collect(Collectors.toCollection(HashSet::new));
?hashSet.forEach(System.out::println);
?-----------------輸出--------------
?李四
?張三
?王五
?
獲取流中的元素總數?
Long count = user.stream().collect(Collectors.counting());
System.out.println(count);
-----------------輸出--------------
4
?
根據工資獲取平均值?
Double avg = user.stream().collect(Collectors.averagingDouble(User::getSalary));
System.out.println(avg);
-----------------輸出--------------
3250.0
?
根據工資獲取總和?
Double sum = user.stream().collect(Collectors.summingDouble(User::getSalary));
System.out.println(sum);
-----------------輸出--------------
13000.0
?
根據工資獲取組函數?
?DoubleSummaryStatistics sum = user.stream().collect(Collectors.summarizingDouble(User::getSalary));
?System.out.println(sum);
?-----------------輸出--------------
?DoubleSummaryStatistics{count=4, sum=13000.000000, min=1000.000000, average=3250.000000, max=4000.000000}
?
根據工資獲取最大值?
?Optional<User> max = user.stream().collect(Collectors.maxBy(Comparator.comparingDouble(User::getSalary)));
?System.out.println(max.get());
?-----------------輸出--------------
?User{name='李四', age=32, salary=4000.0}
?
根據工資獲取最小值?
?Optional<User> min = user.stream().collect(Collectors.minBy(Comparator.comparingDouble(User::getSalary)));
?System.out.println(min.get());
?-----------------輸出--------------
?User{name='張三', age=12, salary=1000.0}
?
分組?
Map<Double, List<User>> map = user.stream().collect(Collectors.groupingBy(User::getSalary));
System.out.println(map);
-----------------輸出--------------
{4000.0=[User{name='李四', age=32, salary=4000.0}, User{name='王五', age=40, salary=4000.0}, User{name='王五', age=40, salary=4000.0}], 1000.0=[User{name='張三', age=12, salary=1000.0}]}
?
多級分組?
Map<Double, Map<String, List<User>>> collect = user.stream().collect(Collectors.groupingBy(User::getSalary, Collectors.groupingBy(
? ? ? ? ? ? ? ? u -> {
? ? ? ? ? ? ? ? ? ? if ( u.getAge() <= 12) {
? ? ? ? ? ? ? ? ? ? ? ? return "青年";
? ? ? ? ? ? ? ? ? ? } else if ( u.getAge() <= 32) {
? ? ? ? ? ? ? ? ? ? ? ? return "中年";
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? return "老年";
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? )));
System.out.println(collect);? ??
-----------------輸出--------------? ??
{4000.0={老年=[User{name='王五', age=40, salary=4000.0}, User{name='王五', age=40, salary=4000.0}], 中年=[User{name='李四', age=32, salary=4000.0}]}, 1000.0={青年=[User{name='張三', age=12, salary=1000.0}]}}
?
分區?
Map<Boolean, List<User>> collect1 = user.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > 3000));
System.out.println(collect1);
-----------------輸出--------------? ?
{false=[User{name='張三', age=12, salary=1000.0}], true=[User{name='李四', age=32, salary=4000.0}, User{name='王五', age=40, salary=4000.0}, User{name='王五', age=40, salary=4000.0}]}
?
連接?
String s = user.stream().map(User::getName).collect(Collectors.joining("--"));
System.out.println(s);
-----------------輸出--------------
張三--李四--王五--王五