现在有一个hero.txt的文件,如下
......
要求使用stream流完成以下问题.
1. 找到武将中武力前三的hero对象, 提示流也可以排序
2. 按出生地分组
3. 找出寿命前三的武将
4. 女性寿命最高的
5. 找出武力排名前三 100, 99, 97 97 ==> 4个人 吕布", "张飞", "关羽", "马超
6. 按各个年龄段分组: 0~20, 2140, 41~60, 60以上
7. 按武力段分组: >=90, 80~89, 70~79, <70
8. 按出生地分组后,统计各组人数
//首先把每行数据读出来,映射成一个hero对象
List<Hero> list = Files.lines(Paths.get("heroes.txt")).map(line->{
String[] a = line.split("\t");
return new Hero(Integer.parseInt(a[0]),
a[1],
a[2],
a[3],
Integer.parseInt(a[4]),
Integer.parseInt(a[5]),
Integer.parseInt(a[6]));
}).collect(Collectors.toList());
1. 找到武将中武力前三的hero对象, 提示流也可以排序
List<String> list1 = list.stream().sorted((a, b) -> b.getPower() - a.getPower())
.limit(3).map((h) -> h.getName()).collect(Collectors.toList());
2. 按出生地分组
Map<String, List<Hero>> map1 = list.stream().collect(Collectors.groupingBy(h -> h.getLoc()));
3. 找出寿命前三的武将
List<String> list2 = list.stream().sorted((a, b) -> ((b.getDeath() - b.getBirth()) - (a.getDeath() - a.getBirth())))
.limit(3).map(h -> h.getName()).collect(Collectors.toList());
4. 女性寿命最高的
System.out.println(list.stream().filter(h -> h.getSex().equals("女"))
.max((a, b) -> ((a.getDeath() - a.getBirth()) - (b.getDeath() - b.getBirth()))).map(h->h.getName()));//Optional[辛宪英]
遇到的问题:
没有加map之前,输出的是地址值Optional[homework.Hero@1b2c6ec2]
原因:
max结果返回可能是空,所以为了避免空指针,stream api返回了一个optional对象,要避免异常,选择首先验证是否有值
解决方法:
(1)用 optional.ifPresent() 判断是否不为空,不为空再get(). ifPresent() 方法除了执行检查,还接受一个Consumer(消费者) 参数,如果对象不是空的,就对执行传入的 Lambda 表达式
list.stream().filter(h -> h.getSex().equals("女"))
.max((a, b) -> ((a.getDeath() - a.getBirth()) - (b.getDeath() - b.getBirth()))).ifPresent(h-> System.out.println(h.getName()));//辛宪英
(2)map 也可以,因为optional.map内部也判断了是不是为空,为空不做操作了
5. 找出武力排名前三 100, 99, 97 97 ==> 4个人 吕布", "张飞", "关羽", "马超
思路:先找到最高的三个武力值,100, 99,97;谁的武力跟这三个相等就筛选出来
Set<Integer> top3 = list.stream().map((h) -> h.getPower()).distinct().sorted((a, b) -> b - a).limit(3).collect(Collectors.toSet());
System.out.println(top3);//[97, 98, 100]
List<String> list2 = list.stream().filter((h) -> top3.contains(h.getPower())).map(h -> h.getName()).collect(Collectors.toList());
System.out.println(list2);//[关羽, 张飞, 马超, 吕布]
6. 按各个年龄段分组: 0~20, 2140, 41~60, 60以上
优化一:年龄封装在hero对象中,年龄可以看成hero的一个属性,private int age;
构造hero对象的时候,已知出生日期和死亡日期, this.age = death - birth; 给age一个get()方法,就可以把年龄返回了
优化二:把求年龄段的方法放在hero里
Map<String, List<Hero>> map2 = list.stream().collect(Collectors.groupingBy(h -> h.ageRange()));
// key 就是分组后的年龄段, value 是list表示组内的hero成员
map2.forEach((key,value)->{
List<String> names = value.stream().map(h -> h.getName()).collect(Collectors.toList());
System.out.println(key + " " + names);
});
7. 按武力段分组: >=90, 80~89, 70~79, <70 (同上)
Map<String, List<Hero>> map3 = list.stream().collect(Collectors.groupingBy(h -> h.powerRange()));
map3.forEach((key,value)->{
List<String> names = value.stream().map(h -> h.getName()).collect(Collectors.toList());
System.out.println(key + " " + names);
});
8. 按出生地分组后,统计各组人数
方式一:
// key 是出生地 , value 是list
Map<String, List<Hero>> map2 = list.stream().collect(Collectors.groupingBy(h -> h.getLoc()));
map2.forEach((key, value)-> {
System.out.println(key + " " +value.size() );
});
方式二:
// 下游收集器
// 分组 , counting 就是求每个组内的元素个数
// key 是出生地 value 就是个数
Map<String, Long> map3 = list.stream().collect(Collectors.groupingBy(h -> h.getLoc(), Collectors.counting()));
map3.forEach((key,value)->{
System.out.println(key + " " + value);
});
Hero类如下:
public class Hero {
private int id;
private String name;
private String loc;
private String sex;
private int birth;
private int death;
private int power;
private int age;
public int getAge() {
return age;
}
// 把年龄转成年龄段
public String ageRange() {
if(age >=0 && age <=20) {
return "0~20";
} else if( age >= 21 && age <= 40) {
return "21~40";
} else if( age >= 41 && age <= 60) {
return "41~60";
} else {
return "60以上";
}
}
//把武力转成武力段 >=90, 80~89, 70~79, <70
public String powerRange(){
if(power >=90){
return ">=90";
}else if(power >= 80 && power <= 89){
return "80~89";
}else if(power >=70 && power<=79){
return "70~79";
}else {
return "<70";
}
}
public Hero(int id, String name, String loc, String sex, int birth, int death, int power) {
this.id = id;
this.name = name;
this.loc = loc;
this.sex = sex;
this.birth = birth;
this.death = death;
this.power = power;
this.age = death - birth;
}
//省略getXXX()和setXXX()
}