Java 8 辣么大(lambda)表達式不慌之—–(五)示例-Collectors中的統計、分組、排序等
summarizingInt 按int類型統計
maxBy取最大/minBy取最小
averagingInt /averagingLong/averagingDouble取平均值
counting計數
partitioningBy分隔/groupingBy分組
sorted 排序
還是先定義好后面做示例要用的數據:
List<User> listUser = new ArrayList<>();
listUser.add(new User("李白", 20, true));
listUser.add(new User("杜甫", 40, true));
listUser.add(new User("李清照", 18, false));
listUser.add(new User("李商隱", 23, true));
listUser.add(new User("杜牧", 39, true));
listUser.add(new User("蘇小妹", 16, false));
1
2
3
4
5
6
7
這個User就是一個普通的Bean對象,有name(姓名)、age(年齡)、gender(性別)三個屬性及對應的set/get方法。
summarizingInt 按int類型統計
IntSummaryStatistics summaryStatistics = listUser.stream().collect(Collectors.summarizingInt(User::getAge));
System.out.println("年齡平均值:" + summaryStatistics.getAverage()); // 年齡平均值:26.0
System.out.println("人數:" + summaryStatistics.getCount()); // 人數:6
System.out.println("年齡最大值:" + summaryStatistics.getMax()); // 年齡最大值:40
System.out.println("年齡最小值:" + summaryStatistics.getMin()); // 年齡最小值:16
System.out.println("年齡總和:" + summaryStatistics.getSum()); // 年齡總和:156
1
2
3
4
5
6
一個方法把統計相關的基本上都搞定了,美滋滋。這里是按int統計,同樣他也有 summarizingLong、summarizingDouble方法,跟這個類似。
嫌這個方法多余的話,也有單個的統計方法。
maxBy取最大/minBy取最小
方法定義如下:
public static <T> Collector<T, ?, Optional<T>>
maxBy(Comparator<? super T> comparator) {
return reducing(BinaryOperator.maxBy(comparator));
}
1
2
3
4
參數傳的是一個Comparator,舉例說明:
// 根據指定條件取最大值: 取年紀最大的人
Optional<User> optional = listUser.stream().collect(Collectors.maxBy(Comparator.comparing((user) -> {
return user.getAge();
})));
if (optional.isPresent()) { // 判斷是否有值
User user = optional.get();
System.out.println("最大年紀的人是:" + user.getName()); // 輸出==》 最大年紀的人是:杜甫
}
1
2
3
4
5
6
7
8
取最小的與取最大的是一樣的道理:
// 根據指定條件取最小值: 取年紀最小的人
Optional<User> optional = listUser.stream().collect(Collectors.minBy(Comparator.comparing((user) -> {
return user.getAge();
})));
if (optional.isPresent()) { // 判斷是否有值
User user = optional.get();
System.out.println("最小年紀的人是:" + user.getName()); // 輸出==》 最小年紀的人是:蘇小妹
}
1
2
3
4
5
6
7
8
averagingInt /averagingLong/averagingDouble取平均值
方法定義:
public static <T> Collector<T, ?, Double>
averagingInt(ToIntFunction<? super T> mapper) {
return new CollectorImpl<>(
() -> new long[2],
(a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; },
(a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
}
1
2
3
4
5
6
7
8
傳一個ToIntFunction類型的參數,這里說一下ToIntFunction。前面說過Function<T, R>的定義,T是入參的類型R是返回值的類型,與Function<T, R>相應的有IntFunction,他規定死入參類型是int,返回類型自定義;然后一個ToIntFunction他的入參類型是自定義,返回類型定死了是int。同理其他的Long類型的,Double類型的一樣。
所以我們此處的averagingInt這樣寫:
ToIntFunction<User> mapper = (user)->{
return user.getAge();
};
Double averageAge = listUser.stream().collect(Collectors.averagingInt(mapper ));
System.out.println("平均年齡是:" + averageAge); // 輸出--》 平均年齡是:26.0
1
2
3
4
5
或者
Double averageAge = listUser.stream().collect(Collectors.averagingInt(User::getAge));
System.out.println("平均年齡是:" + averageAge); // 輸出--》 平均年齡是:26.0
1
2
counting計數
counting方法很簡單,直接上例子:
int count = listUser.stream().collect(Collectors.counting()); // count其實就等於listUser.size();
1
此處單純數個數沒什么用,相當於listUser.size(); 。但是可以結合其他方法使用,如結合filter使用求男性數量:
Long count = listUser.stream().filter(user -> user.getGender()).collect(Collectors.counting());
System.out.println("男性個數:" + count); // 輸出--》 男性個數:2
1
2
partitioningBy分隔/groupingBy分組
partitioningBy 方法的定義:
groupingBy方法的定義:
通過定義可以看到,partitioningBy的第一個參數是一個Predicate,而groupingBy的第一個參數是一個Function<T,R>,Predicate返回的是Boolean類型而Function<T,R>返回的是自己定義的類型。所以當分組的依據是Boolean類型的時候這兩個方法使用效果一樣,如:
// 將List中的人按性別分組
Predicate<User> predicate = (user) -> {
return user.getGender();
};
Map<Boolean, List<User>> partition = listUser.stream().collect(Collectors.partitioningBy(predicate));
Function<User, Boolean> classifier = (user) -> {
return user.getGender();
};
Map<Boolean, List<User>> groupby = listUser.stream().collect(Collectors.groupingBy(classifier));
1
2
3
4
5
6
7
8
9
10
上面2個方法得到的結果是一樣的,因為從上面的2個函數predicate和classifier的定義可以看到,2個函數的實現是一樣的。但是如果想要按其他類型的數據(如String)來進行分組的話 partitioningBy就要略遜一籌了,如按User的姓名來分組,partitioningBy就不好寫了,groupingBy可以稍微改一下就行:
Function<User, String> classifier = (user) -> {
return user.getName();
};
Map<String, List<User>> groupby = listUser.stream().collect(Collectors.groupingBy(classifier));
1
2
3
4
sorted 排序
這個方法不是Collectors的方法,是Stream接口里面的一個方法。作用就是將Stream里面的元素排序,但是有個前提是里面的內容是Comparable的(或者說實現過Comparable接口的),否則會拋出異常。
如上的listUser,如果直接寫:
List<User> sorted = listUser.stream().sorted().collect(Collectors.toList());
1
就會拋出Exception in thread "main" java.lang.ClassCastException: User cannot be cast to java.lang.Comparable異常。
所以要先讓User對象實現一下Comparable接口並重寫compareTo方法:
@Override
public int compareTo(User user) {
return this.getAge().compareTo(user.getAge());
}
1
2
3
4
這樣上面的sorted()方法就能按年齡來排序了。
或者User對象不實現一下Comparable接口,就直接寫:
List<User> sorted3 = listUser.stream()
.sorted((x, y) -> (x.getAge() < y.getAge()) ? -1 : ((x.getAge() > y.getAge()) ? 1 : 0))
.collect(Collectors.toList());
1
2
3
道理是一樣的,寫法不一樣罷了。
————————————————
版權聲明:本文為CSDN博主「DWT_CCFK」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u012843361/article/details/83094827