JDK1.8 Stream & Optional

JDK1.8 Stream & Optional

Stream

流 -Stream

構造方法

list.stream();//通過list獲得
Stream.of(T t...); // 通過Stream.of 獲得與 Arrays.asList() 累死
Stream.if(T[]);//通過Stream.of 數組獲得

相當於迭代器,其不可逆,串行執行。後面可以接多個 Intermediate (中間)操作、Terminal (終端)及short-circuiting操作。stream操作後的元素其本體也會跟着變化。後文會對每個各個操作進行解釋。其操作都以 lambda 表達式呈現。

各種操作的列表如下:

  1. Intermediate(中間):
操作 含義
map (mapToInt, flatMap 等) 對象屬性刷選
filter 條件過濾
distinct 去重
sorted 排序
peek 循環處理元素
limit 獲取前n個元素
skip 刪除前n個元素
parallel stream轉爲並行流
sequential stream轉爲串行流
unordered 將流無序化,
用於對順序無要求的Stream
例如並行流其可以提升性能
  1. Terminal(中間):
操作 含義
forEach 循環處理元素
forEachOrdered 有序循環處理元素
toArray 流轉爲數組
reduce 邏輯計算返回一個對象
collect 集合操作
min 獲得最小
max 獲得最大
count 獲得條數
anyMatch 只要有一個滿足則返回true
allMatch 全部滿足則返回true
noneMatch 全部不滿足則返回true
findFirst 獲得流的第一個元素
findAny 獲得流的任意一元素
iterator 返回流的迭代器
  1. Short-circuiting:
操作 含義
anyMatch
noneMatch
findAny
allMatch
findFirst
limit

注意:
Stream不具有複用性,使用一次下次若再次使用會報錯stream has already been operated upon or closed

​ Strem中 如果沒有Terminal 語句Intermediate 語句將不會運行,沒有終端去輸出,過程將不會運行

並行處理流 -parallelStream

構造方法

List.parallelStream();//通過List獲得
Stream.of(T t...).parallel();//將Stream轉爲並行流

可以做到將一個Stream轉爲並行的多個stream流,其開闢線程數默認和CPU 核數一致。其默認通過JDK1.7的ForJoinPool來實現的多線程任務。

System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism","12")可以做到修改其線程數,不推薦修改。

e.g.:

System.out.println("the list size is ["+engineers.size()+"]");
long beginTime = System.currentTimeMillis();
engineers.parallelStream().forEach(engineer -> engineer.setAge(20));
long endTime = System.currentTimeMillis();
System.out.println("the stream run time is ["+(endTime-beginTime)+"]");
System.out.println("******************");
engineers.parallelStream().forEach(engineer -> System.out.println(engineer));

//爲了更好的體現結果將 enginner.setAge 的運行每次都等待1秒
 public void setAge(Integer age) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.age = age;
}

運行結果:

the list size is [9] //集合長度爲 9
the stream run time is [3082] //運行時長≈ 3秒  如果是全爲串行執行此結果因 ≈ 9秒
****************** //觀察下述結果發現age已全部被更改
Engineer{name='虛竹', age=20, salary=6574}
Engineer{name='喬峯', age=20, salary=7600}
Engineer{name='虛竹', age=20, salary=9327}
Engineer{name='張三', age=20, salary=2057}
Engineer{name='趙六', age=20, salary=2754}
Engineer{name='李四', age=20, salary=5907}
Engineer{name='王五', age=20, salary=2863}

注意:

  1. 在使用Stream.parallel()得到並行流以後。其兩者本質還是使用的同一個流,如果本體被使用複製體也將會收到影響。

Intermediate 組


Map;mapToInt;mapToDouble;…

其可以對Stream進行數據的刷選映射到另一個Stream對象上去(新對象爲新創建),新的Stream對象的類型與提取值得類型有關。其內置了Int、Double和Long三個Map。

用法

//通過 lambda去提取值,如果對提取值有更多處理可用此方式
Stream stream1 = stream.mapToInt(engineers -> engineers.getAge()); 
//通過 Function 函數去獲取參數值。
Stream stream2 = stream.mapToInt(Engineer::getAge);

e.g.:

Stream<Engineer> stream = engineers.parallelStream();
IntStream intStream = stream.mapToInt(engineers -> engineers.getAge());
intStream.forEach(e -> System.out.println(e));

運行結果:

the age is =>20
the age is =>18
the age is =>15
the age is =>14

map函數也可以用於 Optional.但是兩者用法不一樣;其用於對對象中的某個參數進行校驗。返回的爲這個對象的參數的Optional 如下:

注意: Optional的map是對整個引入的對象做的判斷

Optional Optin = Optional.ofNullable(engineer)
	.map(enginnerTest -> enginnerTest.getAget());
Integer integer1 = Optin.orElseGet(() -> 10000);

e.g.:

// -------獲取enginner 的 age 如果爲空則設置值爲100
Engineer engineer = engineers.get(0);
Optional<Integer> integer = Optional.ofNullable(engineer).map(enginnerTest -> {
		System.out.println("the age original is =>"+enginnerTest);
        //故意設置爲Null
		return null;
	});
Integer integer1 = integer.orElseGet(() -> 100);//如果optional爲空則採用orElseGet中的值
System.out.println("the age last is =>"+integer1);

運行結果:

the age original is =>Engineer{name='張三', age=12, salary=6206}
the age last is =>100

filter

其可以對Stream中的對象進行條件過濾,輸出過濾後的結果

用法

Stream<T> stream = = stream.filter(Predicate<T>); //傳入一個Predicate 函數 其會要求返回一個boolean值
Stream<T> stream = = stream.filter(engineer -> engineer.getAge() >= 18);//直接使用lambda進行

Predicate源碼

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

e.g.:

// ------- 獲取age 大於等於18的 對象
Stream<Engineer> stream = engineers.stream(); //獲得stream流
//過濾enginner取出age大於等於18的轉爲stream流
Stream<Engineer> engineerStream = stream.filter(engineer -> engineer.getAge() >= 18);
//循環輸出
engineerStream.forEach(engineer -> System.out.println(engineer));

運行結果:

Engineer{name='陳七', age=18, salary=2244}
Engineer{name='段譽', age=20, salary=7386}
Engineer{name='虛竹', age=21, salary=5648}

distinct

數據去重,與mysql的DISTINCT() 函數等意。其會根據hashCode 進行去重和Set類似

用法:

Stream<T> distinctStream = Stream.distinct();

e.g.:

//將integer去重
Stream<Integer> intStream = Stream.of(1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 8, 9, 10).parallel();
Stream<Integer> distinct = intStream.distinct();
distinct.forEach(t -> System.out.println("result =>"+t));

運行結果:

result =>7
result =>6
result =>2
result =>3
result =>1
result =>8
result =>4
result =>9
result =>10
result =>5

sorted

數據排序,其會根據Compare進行排序。也可以自行重寫排序規則

用法:

Stream<Engineer> sorted = stream.storted((e1,e2) -> Comparator<T>);//要求Comparator 返回一個Integer

注意: stored因涉及多參數的比較,故不要使用並行流 ParallelStream來進行操作

Comparator函數源碼如下:

@FunctionalInterface
public interface Comparator<T> {
	int compare(T o1, T o2);
}

e.g.:

Stream<Engineer> stream = engineers.stream();
Stream<Engineer> sorted = stream.sorted((e1, e2) -> {
		return e1.getAge() - e2.getAge();
	});
sorted.forEach(engineer -> System.out.println(engineer));

運行結果:

Engineer{name='段譽', age=20, salary=4581}
Engineer{name='王五', age=15, salary=1210}
Engineer{name='陳七', age=18, salary=3001}
Engineer{name='趙六', age=17, salary=7450}
Engineer{name='虛竹', age=21, salary=6098}
Engineer{name='喬峯', age=23, salary=8972}
Engineer{name='虛竹', age=21, salary=1554}

peek

循環處理元素與ForEach類似,區別是ForEach操作是屬於Terminal操作,元素將會被消費,其後無法進行任何元素的邏輯。

用法

stream.peek(e -> {});
stream.peek(e -> peek(Consumer<T> action)); //接一個Consumer表達式

e.g.:

Stream<Engineer> stream = engineers.stream();
Stream<Engineer> peek =stream.sorted((e1, e2) -> (e1.getAge() - e2.getAge()))
    .peek(e -> {
        System.out.println("peek -->" + e);
        e.setAge(1000); //測試 peek 對象循環修改會真實修改對象
    }); //有返回值 Stream
Integer ageSum = peek.map(Engineer::getAge).reduce(Integer::sum).get(); //消費了 stream
System.out.println("ageSum -->"+ageSum);
try {
    stream.forEach(e -> System.out.println(e)); //此處會報錯因爲stream已被消費再次使用會出現錯誤
} catch (Exception e) {
    e.printStackTrace();
}
engineers.stream().forEach(e -> System.out.println("forEach -->"+e)); //無返回值

返回結果:

peek -->Engineer{name='張三', age=12, salary=4863}
peek -->Engineer{name='李四', age=14, salary=6538}
peek -->Engineer{name='王五', age=15, salary=7757}
peek -->Engineer{name='趙六', age=17, salary=406}
ageSum -->4000
java.lang.IllegalStateException: stream has already been operated upon or closed
.
. 縮減篇幅
.
ntellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
forEach -->Engineer{name='張三', age=1000, salary=4863}
forEach -->Engineer{name='李四', age=1000, salary=6538}
forEach -->Engineer{name='王五', age=1000, salary=7757}
forEach -->Engineer{name='趙六', age=1000, salary=406}

limit | skip

limt 獲得前面指定個數元素,skip 刪除前面指定個數元素

用法:

stream.limit(Num);//獲得0-num個元素
stream.skip(Num);//刪除0-num個元素

注意: limit或skip不可小於0,否則會拋出異常IllegalArgumentException

e.g.:

Stream<Engineer> engineerStream = engineers.stream();
engineerStream.sorted((e1,e2) -> e1.getAge() -e2.getAge())
        .forEach(e -> System.out.println(e));
System.out.println("*****************************");
engineerStream = engineers.stream();
engineerStream.sorted((e1,e2) -> e1.getAge() -e2.getAge())
        .limit(3).forEach(e -> System.out.println(e));//獲得前面4個元素
System.out.println("*****************************");
engineerStream = engineers.stream();
engineerStream.sorted((e1,e2) -> e1.getAge() -e2.getAge())
        .skip(3).forEach(e -> System.out.println(e));//扔掉前面4個元素

返回結果:

Engineer{name='張三', age=12, salary=4013}
Engineer{name='李四', age=14, salary=1152}
Engineer{name='王五', age=15, salary=4836}
Engineer{name='趙六', age=17, salary=835}
*****************************
Engineer{name='張三', age=12, salary=4013}
Engineer{name='李四', age=14, salary=1152}
Engineer{name='王五', age=15, salary=4836}
*****************************
Engineer{name='趙六', age=17, salary=835}

Terminal 組


forEachOrdered

有序遍歷,對並行流parallelStream 依然有效

e.g.:

Stream<Engineer> engineerStream = engineers.parallelStream();
engineerStream.sorted((e1, e2) -> e1.getAge() - e2.getAge())        
			  .peek(engineer -> System.out.println("peek ->"+engineer))
              .forEachOrdered(System.out::println);

輸出結果:

peek ->Engineer{name='李四', age=14, salary=4729}
Engineer{name='李四', age=14, salary=4729}
peek ->Engineer{name='王五', age=15, salary=586}
Engineer{name='王五', age=15, salary=586}
peek ->Engineer{name='趙六', age=17, salary=7339}
peek ->Engineer{name='張三', age=21, salary=1555}
Engineer{name='趙六', age=17, salary=7339}
Engineer{name='張三', age=21, salary=1555}

toArray

將Stream輸出成數組

用法

Stream.toArray(T::new);//T::new 等同於  new T()

e.g.:

Stream<Engineer> stream = engineers.stream();
Engineer[] engineers = stream.peek(engineer -> engineer.setAge(200)).toArray(Engineer[]::new);
for (Engineer engineer : engineers) {
     System.out.println(engineer);
}

返回結果:

Engineer{name='張三', age=200, salary=7416}
Engineer{name='李四', age=200, salary=491}
Engineer{name='王五', age=200, salary=3507}
Engineer{name='趙六', age=200, salary=5509}

reduce

計算彙總,可以對流進行數據的計算邏輯從而得到一個結果

用法:

sequential(串型)流中

/**
取出流中的頭兩個元素然後通過後述的lambda表達式,算出記爲 新的t1,緊接着取出流中的第三個元素記爲t2。最終將值返回,含義如下:
stream 			-> v1,v2,v3,v4,v...
第一步運行 reduce->  v1(t1),v2(t2) 算出等於vTemp
第二步運行 reduce->  vTemp(t1),v3(t2) 算出等於vTemp
第三步運算 reduce->  vTemp(t1),v4(t2) 算出等於vTemp
.
.
.
**/
Optional opt = seqStream.reduce((t1,t2) -> { return T});//返回值爲opt,可以使用.orElseGet(() -> lambda)判斷後獲得結果

//---------------------------------------------------------------------------------
/**
取出startT 和流的第一個元素通過後述的lambda表達式,算出記爲 新的t1,緊接着取出流中的第二個元素記爲t2。最終將值返回,含義如下:
stream 			-> v1,v2,v3,v4,v...
第一步運行 reduce->  startT(t1),v1(t2) 算出等於vTemp
第二步運行 reduce->  vTemp(t1),v2(t2) 算出等於vTemp
第三步運算 reduce->  vTemp(t1),v3(t2) 算出等於vTemp
**/
T t = seqStream.reduce(startT,(t1,t2) -> {return T}); //返回值爲 T

parallel(並型)流中

/**
取出流中的兩個元素然後通過後述的lambda表達式,算出記爲結果r1,同時另一條線程獲得流中的另外兩個元素通過計算得r2,最後將所有得結果進行遞歸合併得r1+r2+...(注意:此處不可單純認爲是r1+r2..,其類似於JDK1.7得Fork/join 模式將任務分給多個線程去運行然後各個線程內部合併運算後最終外部再進行合併運算),含義如下
原有元素: 		 ->v1,v2,v3,v4,v...
stream--Thread1 	-> v1,v2,...
stream--Thread2 	-> v3,v5,...
stream--Thread3 	-> v4,v5,...
... more 

第一步運行 Thread1 - reduce ->  v1(t1),v2(t2) 算出等於r1
	同時  Thread2 - reduce ->  v3(t1),v5(t2) 算出等於r2
	...more
第二步運行 Thread1 - reduce ->  v18(t1),r1(t2) 算出等於r1 (此處得v18爲假設)
	同時  Thread2 - reduce ->  v9(t1),r2(t2)  算出等於r2 (此處得v5爲假設)
	...more
.
.
.
第n步運算  reduce->  r1(t1),r2(t2) 算出等於 result
**/
Optional opt = parStream.reduce((t1,t2) -> { return T});//返回值爲opt,可以使用.orElseGet(() -> lambda)判斷後獲得結果


//---------------------------------------------------------------------------------
/**
取出流中的1個元素然後與startT通過後述的lambda表達式,算出記爲結果r1,同時另一條線程獲得流中的另外1個元素與startT通過計算得r2,後多條線程又去流中各自獲取一個元素與startT進行運算得出結果r3,r4,r5...,最後將所有得結果進行遞歸合併得r1+r2+...(注意:此處不可單純認爲是r1+r2..,其類似於JDK1.7得Fork/join 模式將任務分給多個線程去運行然後各個線程內部合併運算後最終外部再進行合併運算),含義如下
原有元素: 		 ->v1,v2,v3,v4,v...
stream--Thread1 	-> v1,v2,...
stream--Thread2 	-> v3,v5,...
stream--Thread3 	-> v4,v5,...
... more 

第一步運行 Thread1 - reduce ->  startT(t1),v2(t2) 算出等於threadResult1[0] = r1
	同時  Thread2 - reduce ->  startT(t1),v3(t2) 算出等於threadResult2[0] = r2
	...more
第二步運行 Thread1 - reduce ->  startT(t1),v18(t2) 算出等於threadResult1[1] = r18
	同時  Thread2 - reduce ->  startT(t1),v5(t2)  算出等於threadResult2[1] = r5
	...more
.
.
.
第n步運算  reduce->  算出等於threadResult1[0]+hreadResult1[1]+...+hreadResult2[0]+hreadResult2[1]... 算出等於 result
**/
T t = parStream.reduce(startT,(t1,t2) -> {return T});//返回值爲 T

區別: 並行流時,起始數將會被計算 stream的長度次。而在串行時其只會被計算一次。由上述過程也可得知,在處理邏輯複雜並涉及到其他元素的結果時請慎重考慮使用並行計算。

上述的(t1,t2) -> {return T} 爲 BinaryOperator lambda函數,源碼如下:

@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T>  {
    /**
     * 從中可以看到其返回值需要和表達式的值一致,傳入內容爲一個  lambda函數
     */
    public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
    }
}

//Comparator表達式
@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);
}

基本類型可使用的函數列表

函數 含義
Number::min 最小
Number::max 最大
Number::sum 求和
String::concat 字符串拼接

串行和並行的效果測試:

e.g.:

 System.out.println("***********************************");
 Stream<Integer> stream = Stream.of(1, 3, 5, 7, 9).sequential();
 Integer sum = stream.reduce((t1, t2) -> {
     System.out.println(t1 + "<=>" + t2);
     return t1 + t2;
 }).orElseGet(() -> Integer.MAX_VALUE); //串行時求和
 System.out.println("求和 (sequential-lambda) ==>" + sum);
 System.out.println("***********************************");
 stream = Stream.of(1, 3, 5, 7, 9).parallel();
 sum = stream.reduce((t1, t2) -> {
     System.out.println(t1 + "<=>" + t2);
     return t1 + t2;
 }).orElseGet(() -> Integer.MAX_VALUE); //並行時求和
 System.out.println("求和 (parallel-lambda) ==>" + sum);
 System.out.println("***********************************");
 stream = Stream.of(1, 3, 5, 7, 9).sequential();
 sum = stream.reduce(5, (t1, t2) -> {
     System.out.println(t1 + "<=>" + t2);
     return t1 + t2;
 });//有起始數,並行時求和
 System.out.println("求和 begin+5(sequential-lambda) ==>" + sum);
 System.out.println("***********************************");
 stream = Stream.of(1, 3, 5, 7, 9).parallel();
 sum = stream.reduce(5, (t1, t2) -> {
     System.out.println(t1 + "<=>" + t2);
     return t1 + t2;
 });//有起始數,串行時求和
 System.out.println("求和 begin+5(parallel-lambda) ==>" + sum);

返回結果:

***********************************
1<=>3
4<=>5
9<=>7
16<=>9
求和 (sequential-lambda) ==>25
***********************************
7<=>9
5<=>16
1<=>3
4<=>21
求和 (parallel-lambda) ==>25
***********************************
5<=>1
6<=>3
9<=>5
14<=>7
21<=>9
求和 begin+5(sequential-lambda) ==>30
***********************************
5<=>5
5<=>7
5<=>3
5<=>9
5<=>1
6<=>8
12<=>14
10<=>26
14<=>36
求和 begin+5(parallel-lambda) ==>50

內置函數:

e.g.:

Double[] doubles = new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
Integer[] integers = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
Stream<Double> stream = Stream.of(doubles).parallel();
Double min = stream.reduce(Double.MAX_VALUE, Double::min);
System.out.println("最小值 ===>" + min);
stream = Stream.of(doubles).parallel();
Double max = stream.reduce(Double.MIN_VALUE, Double::max);
System.out.println("最大值 ===>" + max);
Stream<Integer> streamInteger = Stream.of(integers).parallel();
Integer sum = streamInteger.reduce(10, Integer::sum);
System.out.println("求和 ===>" + sum);
Stream<String> streamStr = Stream.of("a", "b", "c", "d").parallel();
String concatStr = streamStr.reduce("BEGIN-", String::concat);
System.out.println("字符串拼接 ==>" + concatStr);

返回結果:

最小值 ===>1.0
最大值 ===>9.0
求和 ===>135
字符串拼接 ==>BEGIN-aBEGIN-bBEGIN-cBEGIN-d

collect

stream轉成集合

用法

stream.collect(Collectors c);//內部可以接java.util.stream.Collectors 中的方法

已知方法列表:

函數 含義
toList stream轉List集合
toSet stream轉Set集合
toMap stream轉Map集合
joining 分隔符拼接
maxBy 獲取最大值
minBy 獲取最小值
summing 獲取特殊值(均值、最大值、最小值…)
averaging 獲取平均值
counting 獲取長度
groupBy 指定key進行分組
partitioningBy 根據true|false進行分組
mapping 指定key轉爲Map
reducing 數據彙總
collectingAndThen 操作後接着怎麼做

e.g.:

System.out.println("**************************");
Stream<Engineer> stream = engineers.stream();
Set<Engineer> collectSet = stream.collect(Collectors.toSet());
System.out.println("流轉[Set]集合==>"+collectSet);
System.out.println("**************************");
stream = engineers.stream();
List<Engineer> collectList = stream.collect(Collectors.toList());
System.out.println("流轉[List]集合==>"+collectList);
System.out.println("**************************");
stream = engineers.stream();
Map<String, Engineer> collect6 = stream.collect(Collectors.toMap(Engineer::getName, Function.identity()));
System.out.println("流轉[Map]集合根據key:name ==>"+collect6);
System.out.println("**************************");
stream = engineers.stream();
String collect7 = stream.map(Engineer::getName).collect(Collectors.joining("&"));
System.out.println("使用[Joining]進行拼接 ==>"+collect7);
System.out.println("***********************");
stream = engineers.stream();
Optional<Engineer> collect8 = stream.collect(Collectors.maxBy((e1, e2) -> e1.getAge() - e2.getAge()));
System.out.println("使用[maxBy]進行拼接 按照[age]取大 ==>"+collect8.get());
System.out.println("***********************");
stream = engineers.stream();
collect8 = stream.collect(Collectors.minBy((e1, e2) -> e1.getAge() - e2.getAge()));
System.out.println("使用[minBy]進行拼接,按照[age]取小 ==>"+collect8.get());
System.out.println("***********************");
stream = engineers.stream();
IntSummaryStatistics collect9 = stream.collect(Collectors.summarizingInt(Engineer::getAge));
System.out.println("使用[summarizing]進行[min]取小 ==>"+collect9.getMin());
System.out.println("使用[summarizing]進行[max]取小 ==>"+collect9.getMax());
System.out.println("使用[summarizing]進行[count]取條數 ==>"+collect9.getCount());
System.out.println("使用[summarizing]進行[average]取平均 ==>"+collect9.getAverage());
System.out.println("使用[summarizing]進行[sum]取和 ==>"+collect9.getSum());
System.out.println("***********************");
stream = engineers.stream();
Double collect10 = stream.collect(Collectors.averagingDouble((e1) -> e1.getSalary().doubleValue()));
System.out.println("使用[averaging]進行[salary]的均值 ==>"+collect10);
System.out.println("***********************");
stream = engineers.stream();
Long collect = stream.collect(Collectors.counting());
System.out.println("使用[counting]獲得[stream]長度 ==>"+collect);
System.out.println("***********************");
stream = engineers.stream();
Map<Integer, List<Engineer>> collect1 = stream.collect(Collectors.groupingBy(Engineer::getAge));
collect1.forEach((k,v) -> System.out.println("使用[groupBy]根據[age]進行元素分組 ==>"+k+"<===>"+v));
System.out.println("***********************");
stream = engineers.stream();
//groupingBy 分組統計人名
Map<Integer, Set<String>> collect5 = stream.collect(Collectors.groupingBy(Engineer::getAge,
        Collectors.mapping(Engineer::getName, Collectors.toSet())));
collect5.forEach((k,v) -> System.out.println("使用[groupBy]根據[age]分組,value爲每組Set<人名> ==>"+k+"<===>"+v));
System.out.println("***********************");
stream = engineers.stream();
Map<Boolean, List<Engineer>> collect11 = stream.collect(Collectors.partitioningBy(e -> e.getSalary().doubleValue() >= 3000));
collect11.forEach((k,v) -> System.out.println("使用[partitioningBy]根據[Salary>= 3000]進行元素分組 ==>"+k+"<===>"+v));
System.out.println("***********************");
stream = engineers.stream();
Map<Boolean, List<String>> collect2 = stream.collect(Collectors.partitioningBy(engineers -> engineers.getAge() >= 18,
        Collectors.mapping(Engineer::getName, Collectors.toList())));
collect2.forEach((k,v) -> System.out.println("使用[partitioningBy]根據[age>= 18]分兩組,value每組Set<人名> ==>"+k+"<===>"+v)); //只有兩組 true false
System.out.println("*************************");
stream = engineers.stream();
//Collectors.mapping(v1,v2);v1取出來的數據會按照v2指定的格式進行返回
Set<Integer> collect4 = stream.collect(Collectors.mapping(Engineer::getAge, Collectors.toSet()));
System.out.println("使用[mapping]進行指定對象元素,按照指定規定返回 ==>"+collect4);
System.out.println("*************************");
stream = engineers.stream();
Integer collect3 = stream.map(Engineer::getAge).collect(
        Collectors.reducing(1000, (e1, e2) -> {
            //其規則和reducing中類似,將identity帶入到首次裏面,然後參與後文的計算
            System.out.println(e1 +"<===>"+ e2);
            return e1 - e2;
        }));
System.out.println("使用[reducing]進行在[identity=0]的前提下=>"+collect3);
System.out.println("*************************");
stream = engineers.stream();
Integer integer = stream.map(Engineer::getAge).collect(
        Collectors.reducing((e1, e2) -> {
            //如果不加 identity 首次的e1 和 e2 分別位第一個元素和第二個元素
            System.out.println(e1 + "<===>" + e2);
            return e1 + e2;
        })).get();
System.out.println("使用[reducing]進行 ==>"+integer);
System.out.println("*************************");
stream = engineers.stream();
integer = stream.map(Engineer::getAge).collect(
        Collectors.reducing(0,e -> e+10,(e1, e2) -> {
            //加上identity和第二個元素mapper 後面的運算將會是在取出之前的基礎上先去運行 mapper等式
            System.out.println(e1 + "<===>" + e2);
            return e1 + e2;
        }));
System.out.println("使用[reducing]進行在[identity=0,mapper=(e+10)]的前提下=>"+integer);
// collectingAndThen 的含義是將 前者的集帶入到後者去計算
stream = engineers.stream();
List<String> collect12 = stream.collect(Collectors.collectingAndThen(
        Collectors.groupingBy(Engineer::getAge),
        /**
        groupBy 導致結果變成 —> Map<age:List<Enginner>>
        values取出的結果變成List<List<Enginner>> 使用flatMap變爲多個Stream List<Enginner>
         **/
        e -> e.values().stream().flatMap(List::stream).map(Engineer::getName).collect(Collectors.toList())
));
System.out.println("使用[collectingAndThen]進行==>"+collect12);

返回結果:

流轉[Set]集合==>[Engineer{name='王五', age=15, salary=3000}, Engineer{name='李四', age=14, salary=5000}, Engineer{name='張三', age=14, salary=4000}, Engineer{name='趙六', age=20, salary=20000}]
**************************
流轉[List]集合==>[Engineer{name='李四', age=14, salary=5000}, Engineer{name='張三', age=14, salary=4000}, Engineer{name='王五', age=15, salary=3000}, Engineer{name='趙六', age=20, salary=20000}]
**************************
流轉[Map]集合根據key:name ==>{李四=Engineer{name='李四', age=14, salary=5000}, 張三=Engineer{name='張三', age=14, salary=4000}, 王五=Engineer{name='王五', age=15, salary=3000}, 趙六=Engineer{name='趙六', age=20, salary=20000}}
**************************
使用[Joining]進行拼接 ==>李四&張三&王五&趙六
***********************
使用[maxBy]進行拼接 按照[age]取大 ==>Engineer{name='趙六', age=20, salary=20000}
***********************
使用[minBy]進行拼接,按照[age]取小 ==>Engineer{name='李四', age=14, salary=5000}
***********************
使用[summarizing]進行[min]取小 ==>14
使用[summarizing]進行[max]取小 ==>20
使用[summarizing]進行[count]取條數 ==>4
使用[summarizing]進行[average]取平均 ==>15.75
使用[summarizing]進行[sum]取和 ==>63
***********************
使用[averaging]進行[salary]的均值 ==>8000.0
***********************
使用[counting]獲得[stream]長度 ==>4
***********************
使用[groupBy]根據[age]進行元素分組 ==>20<===>[Engineer{name='趙六', age=20, salary=20000}]
使用[groupBy]根據[age]進行元素分組 ==>14<===>[Engineer{name='李四', age=14, salary=5000}, Engineer{name='張三', age=14, salary=4000}]
使用[groupBy]根據[age]進行元素分組 ==>15<===>[Engineer{name='王五', age=15, salary=3000}]
***********************
使用[groupBy]根據[age]分組,value爲每組Set<人名> ==>20<===>[趙六]
使用[groupBy]根據[age]分組,value爲每組Set<人名> ==>14<===>[李四, 張三]
使用[groupBy]根據[age]分組,value爲每組Set<人名> ==>15<===>[王五]
***********************
使用[partitioningBy]根據[Salary>= 3000]進行元素分組 ==>false<===>[]
使用[partitioningBy]根據[Salary>= 3000]進行元素分組 ==>true<===>[Engineer{name='李四', age=14, salary=5000}, Engineer{name='張三', age=14, salary=4000}, Engineer{name='王五', age=15, salary=3000}, Engineer{name='趙六', age=20, salary=20000}]
***********************
使用[partitioningBy]根據[age>= 18]分兩組,value每組Set<人名> ==>false<===>[李四, 張三, 王五]
使用[partitioningBy]根據[age>= 18]分兩組,value每組Set<人名> ==>true<===>[趙六]
*************************
使用[mapping]進行指定對象元素,按照指定規定返回 ==>[20, 14, 15]
*************************
1000<===>14
986<===>14
972<===>15
957<===>20
使用[reducing]進行在[identity=0]的前提下=>937
*************************
14<===>14
28<===>15
43<===>20
使用[reducing]進行 ==>63
*************************
0<===>24
24<===>24
48<===>25
73<===>30
使用[reducing]進行在[identity=0,mapper=(e+10)]的前提下=>103
使用[collectingAndThen]進行==>[趙六, 李四, 張三, 王五]

min | max

用法:

Optional opt = stream.min((v1,v2) -> return Integer);
Optional opt = stream.max((v1,v2) -> return Integer);

e.g.:

Stream 中只要有一個元素符合傳入的 predicate,返回 trueEngineer engineerMin = engineers.stream().min((e1, e2) -> e1.getAge() - e2.getAge()).get();
System.out.println("[min]獲得最小 ==>"+engineerMin);
Engineer engineerMax = engineers.stream().max((e1, e2) -> e1.getAge() - e2.getAge()).get();
System.out.println("[max]獲得最大 ==>"+engineerMax);

返回結果:

[min]獲得最小 ==>Engineer{name='李四', age=14, salary=5000}
[max]獲得最大 ==>Engineer{name='趙六', age=20, salary=20000}

anyMatch

用法:

stream.anyMatch(T t -> {return true|false});

Stream 中只要有一個元素符合傳入的 Predicate 表達式,則返回 true

e.g.:

final String engineerName="張三";
boolean b = engineers.stream().anyMatch(engineer ->  engineerName.equals(engineer.getName()));
if (b) {
    System.out.println("["+engineerName+"]在集合中");
}

結果:

[張三]在集合中

allMatch | noneMatch

用法:

stream.allMatch(enginner -> {return true|false});//全爲true則返true,否者爲false
stream.noneMatch(enginner -> {return true|false});//全爲false則返回true,否者爲true

e.g.:

Map engineerMap = new HashMap<String,Engineer>(engineers.size());
engineers.forEach(engineer -> engineerMap.put(engineer.getName(),engineer));
Set<String> SetKey =  engineerMap.keySet();
boolean b = engineers.parallelStream().allMatch(engineer -> SetKey.contains(engineer.getName()));
if (b) {
    System.out.println("集合所有元素在新集合中都擁有");
}
//重置map
Set<String> finalSetKey =  new HashMap<String,Engineer>(engineers.size()).keySet();
 b = engineers.parallelStream().noneMatch(engineer -> finalSetKey.contains(engineer.getName()));
if (b) {
    System.out.println("集合所有元素在新集合中都[不]擁有");
}

結果:

集合所有元素在新集合中都擁有
集合所有元素在新集合中都[]擁有

findFirst | findAny

用法:

Optional opt = stream.findFirst();//獲得流的第一個元素返回Optional 
Optional opt = stream.findAny();//獲得流(並行流會有變化)的任意元素返回Optional 

e.g.:

Optional<Engineer> first = engineers.parallelStream().findFirst();
System.out.println("使用[findFirst] ==>"+first.get());
Optional<Engineer> any = engineers.parallelStream().findAny();
System.out.println("使用[findAny] ==>"+any.get());

結果:

使用[findFirst] ==>Engineer{name='李四', age=14, salary=5000}
使用[findAny] ==>Engineer{name='王五', age=15, salary=3000}

Optional

對象校驗的一個包裝類,包地址java.util.Optional

ofNullable | of

Optional 參數的創建需要時用 ofNullable 或者of 方法來創建,兩者都會返回一個 Optional 對象。其區別是:

ofNullable 在校驗對象爲空時不會拋錯,常使用此方式來創建Optional對象,而 of 會直接返回 NullPointerException 異常

e.g.:

Engineer engineer = null;
Optional<Engineer> engineer1 = Optional.ofNullable(engineer);
Optional<Engineer> engineer2 = Optional.of(engineer);

結果:

java.lang.NullPointerException
	at java.util.Objects.requireNonNull(Objects.java:203)
	at java.util.Optional.<init>(Optional.java:96)
	at java.util.Optional.of(Optional.java:108)
    ...

get

獲取Optional的值

e.g.:

Engineer engineer = new Engineer("李四", 14, new BigDecimal("5000"));
Optional<Engineer> engineer1 = Optional.ofNullable(engineer);
System.out.println(engineer1.get());

結果:

Engineer{name='李四', age=14, salary=5000}

ifPresent

如果 Optional 有效則會執行ifPresent 中的方法

optional.ifPresent(T t -> {});//此處的t 是校驗對象

e.g.:

Engineer engineer = new Engineer("李四", 14, new BigDecimal("5000"));
Optional.ofNullable(engineer).ifPresent(engineer1 ->  engineer.setAge(20));
System.out.println(engineer);

結果:

Engineer{name='李四', age=20, salary=5000}

orElse

optional 校驗對象爲空時,其會執行此方法裏面的內容,其返回值要與校驗對象一致

optional.orElse(return T t);

e.g.:

Engineer engineer = null;
engineer = Optional.ofNullable(engineer).orElse(new Engineer("李四", 14, new BigDecimal("5000")));
System.out.println(engineer);

結果:

Engineer{name='李四', age=14, salary=5000}

orElseGet

optional 校驗對象爲空時,其會執行此方法裏面的內容,其返回值要與校驗對象一致.

OrElse 的區別是,orElseGet 接一個lambda表達式,表達式默認不執行只在需要的時候被執行,而 orElse 會註定執行

optional.ofElseGet(Supplier sup);//接Supplier 函數接口

e.g.:

Engineer engineer = null;
engineer = Optional.ofNullable(engineer).orElseGet(() -> new Engineer("張三", 12, new BigDecimal("20.5")));
System.out.println(engineer);

結果:

Engineer{name='張三', age=12, salary=20.5}

orElseThrow

前者沒達到得情況下會激活拋出錯誤.

optional.orElseThrow(() -> return Exception);

e.g.:

Engineer engineer = null;
engineer = Optional.ofNullable(engineer)
			.orElseThrow(
				() -> new RuntimeException("報錯了哦[空指針]!")
			);
System.out.println(engineer);

結果:

java.lang.RuntimeException: 報錯了哦[空指針]!
	at OptionalTest.lambda$test2$1(OptionalTest.java:44)
	at java.util.Optional.orElseThrow(Optional.java:290)

map

filter

過濾器,傳入一個 Predicate 函數接口,成功則會成功返回Optional,否者返回一個空的 Optional

Optional opt = optional.filter(e -> {return true|false});

e.g.:

ArrayList statusList = new ArrayList<String>();
statusList = Optional.ofNullable(statusList)
     //返回一個 null的optional
        .filter(statuses -> !(statuses == null || statuses.isEmpty()))
    //因爲上文返回的null 的optional 則 orElseGet 會被執行填入參數
        .orElseGet(() -> {
            ArrayList arrayList = new ArrayList();
            arrayList.add("張三");
            arrayList.add("李四");
            return arrayList;
        });
System.out.println(statusList);

結果:

[張三, 李四]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章