前沿
当我写这篇文章的时刻,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集合的操作等。