相關鏈接:
java8函數式編程(一)
java8函數式編程(二)
java8函數式編程(三)
其中(一)是在沒有開始瞭解java8新特性之前實際遇到的一個問題,使用for循環實現的代碼很繁瑣,於是嘗試使用新的編碼風格,最後很不完美的實現了需求。在進一步學習後,在(二)中完美實現,並對List常用的操作做了一個總結。最後在(三)中對並行化流與並行化數組的操作簡單歸納。
本節主要是對java8流處理一個總結以及一些細節的補充。另外,學習資料主要參考《Java8實戰》與《Java8函數式編程》兩本書籍。
Stream API
優點:
1 聲明性 – 簡潔、易讀
2 可複合 – 靈活組合
3 可並行 – 高性能
常用操作:
1 篩選
filter 過濾
distinct 去重
limit 截斷
skip 跳過
2 映射
map 轉換
flatMap 扁平化轉換
3 查找與匹配
anyMatch 至少有一個滿足
allMatch 所有都滿足
noneMatch 沒有一個滿足
findAny 返回任意一個
findFrist 返回第一個
4 歸約
reduce 計算
count 元素個數
5 數值流
mapToInt IntStream
mapToDouble DoubleStream
max 最大
min 最小
average 平均
boxed 數值流裝箱
range 範圍內(不包括end)
reageClosed 範圍內(包括end)
6 構建流
of
iterate
generate
7 收集器
collect
數值操作
從1到20間的奇數
IntStream.rangeClosed(1, 20)
.filter(n -> n%2 != 0)
.forEach(System.out::println);
100以內奇數的和
int sum = IntStream.range(1, 100)
.filter(n -> n % 2 != 0)
.sum();
斐波那契數列(前20位)
Stream.iterate(new int[]{0,1}, n -> new int[]{n[1], n[0] + n[1]})
.limit(20)
.map(n -> n[0])
.forEach(System.out::println);
collect收集器
準備數據依然使用List<Frog>,frog的屬性有name名稱,age年齡,color顏色,size體積。
List<Frog> list = new ArrayList<>();
list.add(new Frog("one", 2 , "red", 5.1));
list.add(new Frog("two", 3 , "red", 5.0));
list.add(new Frog("three", 2 , "blue", 5.5));
list.add(new Frog("four", 1 , "blue", 5.3));
list.add(new Frog("five", 5 , "yellow", 5.1));
list.add(new Frog("six", 3 , "yellow", 5.2));
collect方法參數Collector。Collector接口中方法實現對流執行的操作,Collectors實現類提供很多靜態方法,下面是對這些靜態方法的說明。
爲了代碼簡潔,導入Collectors類中所有方法:
import static java.util.stream.Collectors.*;
summaryStatistics
該方法可以一次性獲取到數量、總和、最大值、最小值和平均數
DoubleSummaryStatistics summaryStatistics = frogs.stream()
.collect(summarizingDouble(Frog::getSize));
System.out.println(summaryStatistics);
打印結果
DoubleSummaryStatistics{count=6, sum=31.200000, min=5.000000, average=5.200000, max=5.500000}
也可以直接通過summaryStatistics 的getter方法獲取某一項。
joining
字符串的連接,方法重載
String names = frogs.stream()
.map(Frog::getName)
.collect(joining(" ", "[", "]"));
打印結果
[one two three four five six]
groupingBy
1、分組與多級分組
Map<String, List<Frog>> map = frogs.stream()
.collect(groupingBy(Frog::getColor));
Map<String, Map<Volume, List<Frog>>> map1 = frogs.stream()
.collect(groupingBy(Frog::getColor,
groupingBy(frog -> {
if (frog.getSize() < 5.2) {
return Volume.SMALL;
} else {
return Volume.BIG;
}
})));
public enum Volume {
BIG,
SMALL
}
打印結果
{
red=[Frog{name='one', age=2, color='red', size=5.1}, Frog{name='two', age=3, color='red', size=5.0}],
blue=[Frog{name='three', age=2, color='blue', size=5.5}, Frog{name='four', age=1, color='blue', size=5.3}],
yellow=[Frog{name='five', age=5, color='yellow', size=5.1}, Frog{name='six', age=3, color='yellow', size=5.2}]
}
{
red={
SMALL=[Frog{name='one', age=2, color='red', size=5.1}, Frog{name='two', age=3, color='red', size=5.0}]
},
blue={
BIG=[Frog{name='three', age=2, color='blue', size=5.5}, Frog{name='four', age=1, color='blue', size=5.3}]
},
yellow={
BIG=[Frog{name='six', age=3, color='yellow', size=5.2}],
SMALL=[Frog{name='five', age=5, color='yellow', size=5.1}]
}
}
groupingBy第二個參數可以使用mapping方法。例:
Map<String, HashSet<Volume>> map4 = frogs.stream()
.collect(groupingBy(Frog::getColor,
mapping(frog -> {
if (frog.getSize() < 5.2) {
return Volume.SMALL;
} else {
return Volume.BIG;
}
}, toCollection(HashSet::new))));
2、分組後的數據操作,比如按顏色分組,求每組中size最大的元素
Map<String, Frog> map2 = frogs.stream()
.collect(groupingBy(Frog::getColor,
collectingAndThen(minBy(Comparator.comparingDouble(Frog::getSize)), Optional::get)));
等價的寫法
Map<String, Frog> map3 = frogs.stream()
.collect(toMap(Frog::getColor,
Function.identity(),
BinaryOperator.minBy(Comparator.comparingDouble(Frog::getSize))));
Function.identity():返回一個總是返回其輸入參數的函數
partitioningBy
分區,分組的特殊情況,將數據分爲true和false兩組
Map<Boolean, Long> map = frogs.stream()
.collect(partitioningBy(t -> t.getAge() > 1, counting()));
打印結果
{false=1, true=5}