一:java8中集合有兩個方法來生成流
1:stream() --爲集合創建串行流
2:parallelStream() − 爲集合創建並行流。
代碼舉例:
List<String> strings = Arrays.asList("sks", "","bc", "eg", "acd","", "jk");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
打印結果:
[sks, bc, eg, acd, jk]
代碼解析:
1: 將集合對象轉化爲流對象
2:使用filter過濾出來符合條件的子集合
3:使用Stream流的收集方法collect負責收集流,將collect(Collectors.toList()收集爲List。
二:collect是什麼?
collect是Stream中強大的終端操作,使用其幾乎能得到你想要的任意數據的聚合
三:collect中的方法:
1.1求值
Collectors.maxBy和Collectors.minBy,來計算流中的最大或最小值。參數爲Comparator。
Optional<A> max = Stream.of(new A(4),new A(2),new A(8)).collect(maxBy(comparing(A::getNum)));
Optional<A> min = Stream.of(new A(4),new A(2),new A(8)).collect(minBy(comparing(A::getNum)));
max.ifPresent(a->System.out.println(a.getNum()));
min.ifPresent(a->System.out.println(a.getNum()));
Collectors.summingInt
。求和,輸出int 。還有summingLong和SummingDouble方法。
int sum = Stream.of(new A(4),new A(2),new A(8)).collect(summingInt(A::getNum));<!--輸出14-->
Collectors.averagingInt 求平均值。還有averagingLong和averagingDouble。
Double ave = Stream.of(new A(4),new A(2),new A(8)).collect(averagingInt(A::getNum));
summarizingInt方法返回的值中包含了最大值,最小值,和,平均值,數量。還有summarizingLong和summarizingDouble。
IntSummaryStatistics iss = Stream.of(new A(4),new A(2),new A(8)).collect(summarizingInt(A::getNum));
1.2連接字符串
joining工廠方法返回的收集器會把對流中每一個對象應用toString方法得到的所有字符串連接成一個字符串。joining參數爲分隔符。
List<String> list = Arrays.asList("hello","world","stream");
String s = list.stream().collect(joining(", "));
reducing方法,可以有初始值,轉換函數,累加函數。
List<A> list = Arrays.asList(new A(5),new A(2),new A(3));
int i = list.stream().collect(reducing(0, A::getNum,(a,b)->a+b));
2.分組
Collectors.groupingBy可以用於分組。返回Map類型。參數爲function。還有個重載方法參數爲Function和Collector,Collector參數就是對前面分完組的內容進行操作。
List<A> list = Arrays.asList(new A("tom",22),new A("james",22),new A("jack",3));
Map<String, List<A>> map1 = list.stream().collect(groupingBy(A::getName));
多級分組:
List<A> list = Arrays.asList(new A("tom",22),new A("tom",15),new A("jack",3));
Map<String, Map<String,List<A>>> map2 = list.stream().collect(
groupingBy(A::getName,groupingBy(a->{if(a.getAge()<18)return "child";
else return "adult";})));
判斷每個分組有多少數量:
List<A> list = Arrays.asList(new A("tom",22),new A("tom",15),new A("jack",3));
Map<String, Long> map2 = list.stream().collect(
groupingBy(A::getName,counting()));
得到每個分組年齡最大的那個人:
List<A> list = Arrays.asList(new A("tom",22),new A("tom",15),new A("jack",3));
Map<String, Optional<A>> map2 = list.stream().collect(
groupingBy(A::getName,maxBy(comparing(A::getAge))));
Collectors.collectingAndThen 方法可以把結果轉換爲另一種類型。參數爲collector和function。
List<A> list = Arrays.asList(new A("tom",22),new A("tom",15),new A("jack",3));
Map<String, A> map2 = list.stream().collect(
groupingBy(A::getName,collectingAndThen(maxBy(comparing(A::getAge)), Optional::get)));
mapping方法參數爲function和Collector。
List<A> list = Arrays.asList(new A("tom",22),new A("tom",15),new A("jack",3));
Map<String, HashSet<Integer>> map2 = list.stream().collect(
groupingBy(A::getName,mapping(A::getAge, toCollection(HashSet::new))));
Collectors返回集合的方法有toList(),toSet(),toMap(),toConcurrentMap()方法。
3.分區
分區就是分組的特殊情況,分區的鍵值爲boolean類型。參數爲predicate。還有一個重載方法參數爲predicate和Collector。
List<A> list = Arrays.asList(new A("tom",22),new A("tom",15),new A("jack",3));
Map<Boolean,List<A>> map2 = list.stream().collect(partitioningBy(a->a.getAge()>18));
分區的好處在於保留了true和false的兩套列表。
4.Collector接口
Collector接口:
public interface Collector<T, A, R> {
Supplier<A> supplier();
BiConsumer<A, T> accumulator();
BinaryOperator<A> combiner();
Function<A, R> finisher();
Set<Characteristics> characteristics();
}
T爲收集對象的泛型,A是累加器的類型,
累加器是在收集過程中用於累積部分結果的對象。 R是返回對象的類型。
supplier方法定義累加器類型。
accmulator方法把元素添加到累加器。
combiner方法合併兩個結果容器。
finisher方法把累加器轉爲結果容器。
characteristics方法定義收集器行爲,比如流是否可以並行歸約,以及可以使用那些優化。
5.並行流
可以用parallelStream方法把集合轉爲並行流。並行流就是把內容分爲幾個數據塊然後用不同的線程去執行這些數據塊。這樣就可以使用多核處理器的所有內核。
parallel()方法可以把流轉爲並行流。sequential()方法可以把並行流轉爲順序流。
使用並行流的建議:
1.並行流不一定比順序流快,需要檢查流的性能。
2.最好不要裝箱拆箱,可以的話使用IntStream這樣的流。
3.有些操作並行流就會比順序流慢,比如findFirst等等需要元素順序的。
4.考慮流的操作在流水線的總計算成本 ,N爲元素總數,Q爲元素在流水線中的處理成本,Q越大用並行流的效率可能更高。
5. 小的數據量不要用並行流。
6.考慮流背後的數據結構是否易於分解。數組就比較好分解,鏈表就不好分解,range方法產生的流比較好分解,iterate不好分解。