Java8 Stream(11)Collectors 案例详解
Java8 Stream最为优秀且便捷的当属它的收集器,Collectors实现了很多有用的方法。
学习并熟练运用Collectors能大大提高开发效率。
先早点数据
pigs.add(new Pig(1, "猪爸爸", 31, "M", false));
pigs.add(new Pig(2, "猪妈妈", 28, "F", true));
pigs.add(new Pig(3, "乔治", 2, "M", false));
pigs.add(new Pig(4, "佩奇", 5, "F", false));
pigs.add(new Pig(5, null, 1, "F", false));
一、获得对象中某1个属性集合
1. toList 获取id的List集合
List<Integer> idList = pigs.stream()
.map(Pig::getId)
.collect(Collectors.toList());
2. toSet 获取gender的Set集合
Set<String> genderSet = pigs.stream()
.map(Pig::getGender)
.collect(Collectors.toSet());
二、List 转 Map
1. toMap 将List的值转成 id -> name的Map
Map<Integer, String> idNameMap = pigs.stream()
.collect(
Collectors.toMap(
Pig::getId,
Pig::getName
)
);
因为id=5的name是null,所以报错NullPointerException。
通过下面判断name是否为null,来解决该问题
Map<Integer, String> idNameMap = pigs.stream()
.collect(
Collectors.toMap(
Pig::getId,
pig -> pig.getName() == null ? "" : pig.getName()
)
);
2. 解决key重复后异常
如果key重复,会报异常,这个时候得指定重复用哪一个,得加上(oldValue, newValue) -> newValue)
Map<String, String> genderNameMap = pigs.stream()
.collect(
Collectors.toMap(
Pig::getGender,
pig -> pig.getName() == null ? "" : pig.getName(),
(oldValue, newValue) -> newValue)
);
三、求和 最大值 最小值 平均值
1. 求age最大的对象
Optional<Pig> maxAgePig = pigs.stream()
.filter(a -> a.getAge() != null)
.collect(
Collectors.maxBy(
Comparator.comparing(Pig::getAge)
)
);
2. 求age的平局值
Double avgAge = pigs.stream()
.filter(a -> a.getAge() != null)
.collect(
Collectors.averagingInt(Pig::getAge)
);
3. 求age总和
Integer sumAge = pigs.stream()
.collect(
Collectors.summingInt(Pig::getAge)
);
4. 求统计信息
IntSummaryStatistics statisticsAge = pigs.stream()
.collect(
Collectors.summarizingInt(Pig::getAge)
);
System.out.println("sumAge = " + statisticsAge);
结果如下:
sumAge = IntSummaryStatistics{count=5, sum=67, min=1, average=13.400000, max=31}
四、joining 拼接字符串
String ids = pigs.stream()
.map(a -> String.valueOf(a.getId()))
.collect(Collectors.joining(","));
System.out.println("ids = " + ids);
结果如下:
ids = 1,2,3,4,5
五、groupingBy 分组
1. 一级分组
根据Gender分组
//一级分组
Map<String, List<Pig>> groupByGender = pigs.stream()
.collect(
Collectors.groupingBy(Pig::getGender)
);
结果如下:
F -> [Pig(id=2, name=猪妈妈, age=28, gender=F, valid=true), Pig(id=4, name=佩奇, age=5, gender=F, valid=false), Pig(id=5, name=null, age=1, gender=F, valid=false)]
M -> [Pig(id=1, name=猪爸爸, age=31, gender=M, valid=false), Pig(id=3, name=乔治, age=2, gender=M, valid=false)]
2. 一级分组,且统计count
统计每个性别的个数
Map<String, Long> groupByGenderThenCount = pigs.stream()
.collect(
Collectors.groupingBy(
Pig::getGender,
Collectors.counting()
)
);
结果如下:
F -> 3
M -> 2
3. collectingAndThen 分组后再比较
按照性别分组后,再求各自中年级最小的
Map<String, Pig> groupByGenderThenMinAge = pigs.stream()
.collect(
Collectors.groupingBy(
Pig::getGender,
Collectors.collectingAndThen(
Collectors.minBy(
Comparator.comparingInt(Pig::getAge)
),
Optional::get
)
)
);
4. 二级分组
先gender分组,后valid分组
Map<String, Map<Boolean, List<Pig>>> groupByGenderAndValid = pigs.stream()
.collect(
Collectors.groupingBy(
Pig::getGender,
Collectors.groupingBy(Pig::isValid)
)
);
结果如下:
F -> {false=[Pig(id=4, name=佩奇, age=5, gender=F, valid=false), Pig(id=5, name=null, age=1, gender=F, valid=false)], true=[Pig(id=2, name=猪妈妈, age=28, gender=F, valid=true)]}
M -> {false=[Pig(id=1, name=猪爸爸, age=31, gender=M, valid=false), Pig(id=3, name=乔治, age=2, gender=M, valid=false)]}
六、partitioningBy 分区
1. 按照是否age>20来分区
Map<Boolean, List<Pig>> partByAge = pigs.stream()
.collect(
Collectors.partitioningBy(a -> a.getAge() > 20)
);
结果如下:
false -> [Pig(id=3, name=乔治, age=2, gender=M, valid=false), Pig(id=4, name=佩奇, age=5, gender=F, valid=false), Pig(id=5, name=null, age=1, gender=F, valid=false)]
true -> [Pig(id=1, name=猪爸爸, age=31, gender=M, valid=false), Pig(id=2, name=猪妈妈, age=28, gender=F, valid=true)]
2. 按照是否age>20来分区,再统计count
Map<Boolean, Long> partByAgeThenCount = pigs.stream()
.collect(
Collectors.partitioningBy(
a -> a.getAge() > 20,
Collectors.counting()
)
);
结果如下:
false -> 3
true -> 2