玩转Java 8 Stream系列一map、filter、collect、Collectors.toList、Collectors.groupingBy、sorted

前沿

当我写这篇文章的时刻,jdk的最新版本已经是jdk 18了,jdk的版本真是快,大部分互联网公司还在jdk8的时候,官方已经出到了18,但是jdk8的更新算是一个比较大版本跌倒,新出来了好多方便的Api,例如这片文章我们要说的Steam系列操作,让使用者对集合的操作在逻辑上和写法上更加方便,同时减少了bug的出现

正文

准备数据

创建一个类:Member(成员)

Member

@Data
public class Member {
   /**
     * ID
     */
    private Integer id;
    /**
     * 名称
     */
    private String memberName;
    /**
     * 性别
     */
    private String sex;
    /**
     * 积蓄
     */
    private BigDecimal totalMoney;
    /**
     * 属于哪个家庭
     */
    private Integer familyId;
    
}

解析:@Data帮助我们生成get、set等方法,使代码看起来更加简洁

初始化数据

public static void main(String[] args) {
        Random random = new Random(10);

        List<Member> memberList = new ArrayList<>();
        for (int i = 0; i < 10;) {
            Member member = new Member();
            member.setId(++i);
            member.setMemberName("小花" + i);
            member.setMemberAmount(random.nextInt(50));
            member.setTotalMoney(new BigDecimal(random.nextInt(40) + 10));
            member.setSex(member.getId() % 2 == 0 ? "男" : "女");
            member.setFamilyId(random.nextInt(5) + 1);
            memberList.add(member);
        }
        System.out.println(JSONObject.toJSONString(memberList));
    }

memberList数据类似于

[{
    "familyId": 4,
    "id": 1,
    "memberAmount": 13,
    "memberName": "小花1",
    "sex": "女",
    "totalMoney": 30
}, {
    "familyId": 2,
    "id": 2,
    "memberAmount": 40,
    "memberName": "小花2",
    "sex": "男",
    "totalMoney": 16
}, {
    "familyId": 2,
    "id": 3,
    "memberAmount": 47,
    "memberName": "小花3",
    "sex": "女",
    "totalMoney": 18
}, {
    "familyId": 5,
    "id": 4,
    "memberAmount": 14,
    "memberName": "小花4",
    "sex": "男",
    "totalMoney": 13
}, {
    "familyId": 1,
    "id": 5,
    "memberAmount": 41,
    "memberName": "小花5",
    "sex": "女",
    "totalMoney": 18
}, {
    "familyId": 4,
    "id": 6,
    "memberAmount": 30,
    "memberName": "小花6",
    "sex": "男",
    "totalMoney": 16
}, {
    "familyId": 4,
    "id": 7,
    "memberAmount": 23,
    "memberName": "小花7",
    "sex": "女",
    "totalMoney": 48
}, {
    "familyId": 4,
    "id": 8,
    "memberAmount": 9,
    "memberName": "小花8",
    "sex": "男",
    "totalMoney": 45
}, {
    "familyId": 5,
    "id": 9,
    "memberAmount": 35,
    "memberName": "小花9",
    "sex": "女",
    "totalMoney": 39
}, {
    "familyId": 1,
    "id": 10,
    "memberAmount": 20,
    "memberName": "小花10",
    "sex": "男",
    "totalMoney": 38
}]

开始

如何创建一个Steam?

如果是像我们上面的memberList这种list或者setj集合,那么直接使用member.stream()方法,那么返回的就是一个Stream,如果是一个对象,那么可以通过Steam.of(Object ...values) 方法来来生成一个steam对象。有人会问,生成一个steam有啥用吗?答案是必须有用,因为后面的方法都是基于steam是操作。

forEach操作

类似于一下遍历写法

for (Member member : memberList){
    //操作Member对象
}

但是通过forEach会使得代码更加简洁,如下所示

memberList.forEach(k->{

扫描二维码关注公众号,回复: 15279725 查看本文章

//操作k

});

 2着的区别:

1、传统的写法可以使用break退出,但是stream是不能退出的

2、传统的写法通过continue跳过当前执行逻辑,执行下一次循环,stream通过return跳过当前逻辑

3、在效率方面,如果数据量小,第一种会高点

map操作

获取需要的字段值,例如有个逻辑,需要将memberList集合中的姓名字段筛选出来

第一种写法:

List<String> memberNameList = new ArrayList<>();
for (Member member : memberList){
    //操作Member对象
    memberNameList.add(member.getMemberName());
}

第二种写法

List<String> memberNameList = memberList.stream().map(Member::getMemberName).collect(Collectors.toList());

如果这里还是看不出来使用stream的便利性,那么再往下看

我们要将 积蓄(memberAmount)大于25的成员名字筛选出来

第一种写法

 List<String> memberNameList = new ArrayList<>();
for (Member member : memberList){
    //操作Member对象
    if (member.getMemberAmount() > 20) {
        memberNameList.add(member.getMemberName());
    }
}

第二种写法

List<String> memberNameList = memberList.stream().filter(k->k.getMemberAmount() > 25).map(Member::getMemberName).collect(Collectors.toList());

还是一行代码搞定

filter操作

 过滤操作,是过滤掉不符合我们条件的数据,剩下符合我们条件的数据,在上面中已经用到了,

我们要过滤成员积蓄大于25的数据,即要把成员积蓄小于等于20的数据过滤掉,k代表集合中的对象

List<String> memberNameList = memberList.stream().filter(k->k.getMemberAmount() > 25).map(Member::getMemberName).collect(Collectors.toList());

 collect操作

名如其作用,是收集的意思,将前面的操作数据收集起来,在上面的例子中已经使用到了,将大于25的继续数据筛选出来,然后通过map,获取到需要的字段,例如上面的memberName

括号中通过Collectors对象,进一步明确数据以那种方式进行输出,例如List集合、Set集合、Map集合等,上述是以List集合的形式返回。

distinct操作

去重,我们要筛选出memberName字段的值,并且不能有重复的

以一种写法

 List<String> memberNameList = new ArrayList<>();
for (Member member : memberList){
    //操作Member对象
    if (!memberNameList.contains(member.getMemberName())) {
        memberNameList.add(member.getMemberName());
    }
}

第二种写法

memberNameList = memberList.stream().map(Member::getMemberName).distinct().collect(Collectors.toList());

使用distinct方法,对其结果进行去重

group by 操作

如同sql语句的group by  以某个字段进行分组,对familyId进行分组

第一种写法

Map<Integer, List<Member>> familyMap = new HashMap();
for (Member member : memberList) {
    //操作Member对象
    List<Member> members = familyMap.get(member.getFamilyId());
    if (CollectionUtils.isEmpty(members)) {
        members = new ArrayList<>();
    }
    members.add(member);
    familyMap.put(member.getFamilyId(), members);
}

第二种写法

familyMap =  memberList.stream().collect(Collectors.groupingBy(Member::getFamilyId));

这次能感受到stream的便利性吧,越是复杂的逻辑,越能体现出steam的便利性

sorted排序

第一种写法借助于Collections工具类进行,例如先对memberAmount进行从大到小排序,如果相同则按照familyId从小到大进行排序

Collections.sort(memberList, new Comparator<Member>() {
    @Override
    public int compare(Member o1, Member o2) {
        if (o2.getMemberAmount() - o1.getMemberAmount() == 0){
            return o1.getFamilyId() - o2.getFamilyId();
        }
        return o2.getMemberAmount() - o1.getMemberAmount();
    }
});

第二种写法 

memberList = memberList.stream().sorted(Comparator.comparingInt(Member::getMemberAmount).reversed().thenComparingInt(Member::getFamilyId)).collect(Collectors.toList());

reversed()是逆序

对集合基本操作差不多就这些,下篇文章我们介绍一些高级的用法,例如累加、分组后对List集合的操作等。

猜你喜欢

转载自blog.csdn.net/zanpengfei/article/details/125042795