java8的lambda表达式提供了一些方便list操作的方法,主要涵盖分组、过滤、求和、最值、排序、去重。跟之前的传统写法对比,能少写不少代码。
新建实体类
package com.wh.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class User {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "主键")
private Long id;
@ApiModelProperty(value = "员工名称")
private String name;
@ApiModelProperty(value = "性别:1->男;2->女;")
private Integer sex;
@ApiModelProperty(value = "年龄")
private Integer age;
@ApiModelProperty(value = "薪资")
private BigDecimal salary;
@ApiModelProperty(value = "部门id")
private Long deptId;
@ApiModelProperty(value = "状态:1->启用;2->禁用;")
private Integer state;
@ApiModelProperty(value = "手机号")
private String phone;
@ApiModelProperty(value = "备注")
private String remark;
@ApiModelProperty(value = "创建时间")
private LocalDateTime createTime;
@ApiModelProperty(value = "修改时间")
private LocalDateTime updateTime;
}
初始数据
List<User> userList = new ArrayList<>();
[
{"id":1,"name":"肖战","sex":1,"age":28,"salary":11000.00,"deptId":111,"state":1,"phone":"13800000001","remark":"","createTime":"2022-05-06 17:00:23","updateTime":"2022-05-06 17:00:23"},
{"id":2,"name":"杨紫","sex":2,"age":29,"salary":15000.00,"deptId":222,"state":2,"phone":"13800000002","remark":"","createTime":"2022-05-07 15:10:13","updateTime":"2022-05-07 15:10:13"},
{"id":3,"name":"佩奇","sex":null,"age":28,"salary":20000.00,"deptId":333,"state":1,"phone":"13800000003","remark":"","createTime":"2022-06-06 10:03:10","updateTime":"2022-06-06 10:03:10"},
{"id":4,"name":"易烊千玺","sex":1,"age":30,"salary":30000.00,"deptId":111,"state":1,"phone":"13800000004","remark":"","createTime":"2022-07-26 13:00:43","updateTime":"2022-07-26 13:00:43"},
{"id":1,"name":"肖战","sex":1,"age":28,"salary":11000.00,"deptId":111,"state":1,"phone":"13800000001","remark":"","createTime":"2022-05-06 17:00:23","updateTime":"2022-05-06 17:00:23"}
]
1、去重
// 通过distinct去重
userList = userList.stream().distinct().collect(toList());
2、根据组合去重
// 员工列表根据“姓名;手机号”组合去重
List<User> newUserList = UserList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() ->
new TreeSet<>(Comparator.comparing(r -> r.getName() + ";" + r.getPhone()))), ArrayList::new));
3、分组
通过groupingBy可以分组指定字段
// 根据部门分组
Map<Long, List<User>> userMapByDeptId = userList.stream().collect(Collectors.groupingBy(User::getDeptId));
4、过滤
通过filter方法可以过滤某些条件
// filter过滤(取所有男员工)
userList = userList.stream().filter(user -> user.getSex() == 1).collect(Collectors.toList());
5、遍历赋值
批量设置列表字段为同一个值。若此时userList为null会报空指针异常java.lang.NullPointerException
// 遍历赋值。
userList.forEach(user -> {
user.setRemark("哈哈");
});
6、map取某字段
// 取员工姓名并去重
List<String> userNames = userList.stream().map(User::getName).distinct().collect(Collectors.toList());
// 取启用员工id
List<Long> sysUserIds = userList.stream().filter(user -> user.getState() == 1).map(user -> user.getId()).collect(Collectors.toList());
7、Collectors.joining(",")将数组转为逗号分隔字符串
String nameStr = userNames.stream().collect(Collectors.joining(","));
8、sorted或sort正序排列
list 的 sort 方法返回的是对已经存在的列表进行操作,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。(sort是在原位重新排列列表,而sorted()是产生一个新的列表。)
// sorted按照创建时间正序排列
userList = userList.stream().sorted(Comparator.comparing(User::getCreateTime)).collect(Collectors.toList());
// sort单字段排序,根据id排序
userList.sort(Comparator.comparing(User::getId));
// sort多字段排序,根据id,年龄排序
userList.sort(Comparator.comparing(User::getId).thenComparing(User::getAge));
9、sorted倒叙排列
// 根据创建时间倒叙排序
userList = userList.stream().sorted(Comparator.comparing(User::getCreateTime).reversed()).collect(Collectors.toList());
10、根据条件过滤取第一条数据
// 需求:取手机号为13800000001的第一条数据的名字。
// 取手机号为13800000001的第一条数据,如果不存在则返回null
String name = null;
User user = userList.stream().filter(u -> "13800000001".equals(u.getPhone())).findFirst().orElse(null);
if (user != null){
name = user.getName();
}
// 也可以通过Optional.isPresent判断是否存在
Optional<User> first = userList.stream().filter(u -> "13800000001".equals(u.getPhone())).findFirst();
if (first.isPresent()) {
name= first.get().getName();
}
// 过滤后,通过map取名字,如果数据不存在则返回空
name = userList.stream().filter(u -> "13800000001".equals(u.getPhone())).findFirst().map(User::getName).orElse(StringUtils.EMPTY);
11、截取数据
limit作用就是从流中截取maxSize个元素放到新流中返回
// 截取前三名员工
userList = userList.stream().limit(3).collect(Collectors.toList());
12、求和
分基本类型和大数类型求和,基本类型先mapToInt,然后调用sum方法,大数类型使用reduce调用BigDecimal::add方法
//求和
//基本类型
int sumAge = userList.stream().mapToInt(User::getAge).sum();
//BigDecimal求和(需过滤掉bigDecimal对象为null的情况,否则可能会报空指针)
BigDecimal sumSalary = userList.stream().map(User::getSalary).filter(s -> s != null).reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal sumSalary = userList.stream().map(User::getSalary).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
判断对象空
stream.filter(x -> x!=null)
stream.filter(Objects::nonNull)
判断字段空
stream.filter(x -> x.getDateTime()!=null)
13、最值
求最小与最大,使用min max方法
// 最大更新时间
LocalDateTime maxUpdateTime = userList.stream().map(User::getUpdateTime).filter(r -> r != null).max(LocalDateTime::compareTo).orElse(null);
// 最大更新时间
LocalDateTime maxUpdateTime = userList.stream().filter(r -> r.getUpdateTime() != null).max(Comparator.comparing(User::getUpdateTime)).map(User::getUpdateTime).orElse(null);
// 最小同理,将.max换成.min
14、List 转map
/**
* List -> Map
* 需要注意的是:
* toMap 如果集合对象有重复的key,会报错Duplicate key ....
* user1,user2的id都为1。
* 可以用 (k1,k2)->k1 来设置,如果有重复的key,则保留key1,舍弃key2
*/
Map<Long, User> userMap = userList.stream().collect(Collectors.toMap(User::getId, a -> a,(k1,k2)->k1));
15、遍历数组的同时创建另一个数组
List<DeptVO> deptVOList = userList.stream().filter(user -> user.getDeptId == 111L).collect(ArrayList::new, (list, object) -> {
DeptVO vo = new deptVO();
vo.setPhone(object.getPhone());
vo.setSalary(object.getSalary());
list.add(vo);
}, List::addAll);
// 或者
List<DeptVO> deptVOList = userList.stream().filter(user -> user.getDeptId == 111L).map(user -> {
DeptVO vo = new deptVO();
vo.setPhone(user.getPhone());
vo.setSalary(user.getSalary());
return vo;
}).collect(Collectors.toList());
16、anyMatch、allMatch、noneMatch
anyMatch只要有一条数据满足条件即返回true;
allMatch必须全部都满足条件才会返回true;
noneMatch全都不满足条件才会返回true。
userList数组中3男一女。
// anyMatch存在一条满足条件的数据,返回true:是否存在性别为男的员工
boolean flag = userList.stream().anyMatch(user -> user.getSex() == 1);
// 返回true;
// allMatch所有数据都满足条件时,返回true:是否所有员工性别都为男
boolean flag = userList.stream().allMatch(user -> user.getSex() == 1);
// 返回false
// noneMatch所有数据都不满足条件时,返回true:是否不存在性别为男的员工
boolean flag = userList.stream().noneMatch(user -> user.getSex() == 1);
// 返回false
17、对比修改前和修改后的两个数组,查修改后新增及删除的数据。
// 场景:批量修改部门下员工,存在新勾选某个员工,取消勾选某个员工的情况。保存时,需取出本次新增的,和本次删除的。
// userListDB为数据库查出修改前部门下员工,userListParam为前端传过来的修改后部门下的员工
// 本次删除:对比id,取userListDB有,userListParam没有的数据
List<User> userListToDelete = userListDB.stream().filter(db -> userListParam.stream().noneMatch(param -> param.getId().equals(db.getId()))).collect(toList());
// 本次新增:对比id,取userListParam有,userListDB没有的数据
List<User> userListToSave = userListParam.stream().filter(param -> userListDB.stream().noneMatch(db -> db.getId().equals(param.getId()))).collect(toList());