Stream API的应用

本文详细介绍如何使用Java Stream API处理英雄数据集,包括排序、分组、筛选和聚合操作,如找出武力和寿命最高的英雄,按出生地和武力段分组,并统计各组人数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现在有一个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()
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值