);
userList.add(user);
第一种方式:遍历用户对象的集合进行获取
List<String> nameList = new ArrayList<>();
userList.stream().forEach(user -> nameList.add(user.getName()));
第二种方式:使用流方式提前数据(推荐)
List<String> nameList = userList.stream().map(User::getName).collect(Collectors.toList());
2.对list集合元素过滤取赋值
1)需求:现有一个包含行政区对象的集合,根据父级id获取所有行政区的父级编码,如何去做?
用户对象如下:
列表如下(演示数据):
List<AreaCode> list = new ArrayList<>();
list.add(new AreaCode(1, "湖北省", "101", 0, null));
list.add(new AreaCode(2, "武汉市", "10101", 1, null));
list.add(new AreaCode(3, "黄冈市", "10102", 1, null));
list.add(new AreaCode(4, "洪山区", "1010101", 2, null));
list.add(new AreaCode(5, "江夏区", "1010102", 2, null));
list.add(new AreaCode(6, "江岸区", "1010103", 2, null));
list.add(new AreaCode(6, "阳新县", "1010201", 3, null));
使用get()过滤符合条件的元素
list.stream().forEach(l -> {
String code = "0";
if (l.getParentId() != 0) {
Optional<AreaCode> any = list.stream().filter(s -> s.getId().equals(l.getParentId())).findAny();
if(any.isPresent()){
AreaCode areaCode = any.get();
code = areaCode.getCode();
l.setParentCode(code);
先对整个集合进行遍历,顶级元素除外,过滤出集合中id是当前元素父Id的元素,将其编码赋值给当前元素的对应属性。看起来有些绕,但对于数据的过滤是非常方便的。需要注意的是,这里必须先使用isPresent()方法进行判断是否有符合要求的数据,否则没有符合要求的数据时直接get会抛出空指针异常。
3.判断list集合对象的字段是否存在某个值
1)需求:现有一个用户对象的集合,判断其中是否包含姓名为张三的用户,如何去做?
用户对象如下:
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
private String phone;
列表如下(演示数据):
List<User> userList = new ArrayList<>();
userList.add(new User(1, "张三丰", "15645854585"));
userList.add(new User(2, "张三", "15645857858"));
userList.add(new User(3, "李四", "15945854566"));
userList.add(new User(4, "王五", "15755554585"));
userList.add(new User(5, "张三", "15852254585"));
使用isPresent()进行判断
boolean exist1 = userList.stream().filter(user -> "张三".equals(user.getName())).findAny().isPresent();
其返回boolean类型,包含时返回true,不包含时返回false。
当然可以使用get()方法获取此元素的值,其返回的值是第一个符合条件的元素:
User user = userList.stream().filter(user -> "张三".equals(user.getName())).findAny().get();
这里的user内容就是集合元素中的第2个元素(id为2的用户信息)。
4.对集合元素进行分组
stream是java8的新特性,其就包含分组的方法。
4.1分组案例一
1)先送上示例需要的数据结构
学生表student
10202
10103
10203
20106
10109
班级表clazz
计算机1班(本科)
计算机2班(本科)
计算机1班(专科)
需要是查询当前学生信息及班级名称信息。(仅写java的业务代码)
2)新手写法
public List<StudentVO> getList() {
//查询学生列表 实际是需要带查询条件,这里做演示不做条件查询
List<StudentVO> list = studentDao.selectList();
if (!CollectionUtils.isEmpty(list)) {
list.stream().forEach(studentVO -> {
// 根据班级编码查询班级信息
ClazzVO clazzVO = clazzService.selectByCode(studentVO.getClazzCode());
if (clazzVO != null) {
//设置班级名称
studentVO.setClazzName(clazzVO.getClazzName());
return list;
在这种写法中,每个学生都需要去查询一次数据库的班级信息,而且有很多学生是同一个班的,其实没必要同一个班级的学生都去查询一次数据库,查询一次就可以了,可以减轻数据库的压力。虽然数据量不会特别大,对数据库的影响也不是很大,但确实值得优化,重要的是有这种思维。
3)优化后的写法
优化的方式也不少,比如每查询一次班级信息后将信息存入缓存,后续可直接从缓存中获取;又或者先查询出所有的班级信息,然后利用stream的分组特性或filter特性.....
这里以stream的分组特性进行说明:
public List<StudentVO> getList() {
//查询学生列表 实际是需要带查询条件,这里做演示不做条件查询
List<StudentVO> list = studentDao.selectList();
if (!CollectionUtils.isEmpty(list)) {
//查询所有班级信息
List<ClazzVO> clazzList = clazzService.selectAll();
Map<String, List<ClazzVO>> clazzMap = null;
if (!CollectionUtils.isEmpty(clazzList)) {
// 以clazzCode为key进行分组
clazzMap = clazzList.stream().collect(Collectors.groupingBy(e -> e.getClazzCode()));
Map<String, List<ClazzVO>> finalClazzMap = clazzMap;
list.stream().forEach(studentVO -> {
if (finalClazzMap != null) {
//根据编码从内存获取班级信息
List<ClazzVO> clazzVOS = finalClazzMap.get(studentVO.getClazzCode());
if (!CollectionUtils.isEmpty(clazzVOS)) {
//设置班级名称
studentVO.setClazzName(clazzVOS.get(0).getClazzName());
return list;
虽然代码比优化前多,但相比效率和性能,是值得的。stream分组将班级信息按照编辑编码为key,班级信息为value放入内存中,在遍历学生列表时,可根据班级编码直接从内存中获取班级名称,前后只查询了1次数据库,极大提高了效率,节省了数据库资源。这只是一个示例,说明的是编程的思想,当遇到其他类似的情况时就可以举一反三,一个项目下来可以减少多次不必要的数据库连接,从而提高系统的性能。
4.2分组案例二
上述是对元素进行了分组,实际上也可以对分组后的数据添加序号等等。
下面采用上一小节学生信息进行说明,需求是按照学生班级进行分组,并标注相同班级中每个学生是第几次出现,以及同一个班级中学生的个数。
这里为了演示方便,模拟数据库数据,数据如下:
10202
10103
10203
20106
10109
10104
10203
10105
20106
10107
呈上最终的结果
StudentVO(id=1, stuNo=10202, stuName=张三丰, clazzCode=A02, sex=男, time=1, total=3)
StudentVO(id=2, stuNo=10103, stuName=李能, clazzCode=A01, sex=男, time=1, total=5)
StudentVO(id=3, stuNo=10203, stuName=赵三五, clazzCode=A02, sex=男, time=2, total=3)
StudentVO(id=4, stuNo=20106, stuName=黄家豪, clazzCode=C01, sex=男, time=1, total=2)
StudentVO(id=5, stuNo=10109, stuName=张慧, clazzCode=A01, sex=女, time=2, total=5)
StudentVO(id=6, stuNo=10104, stuName=赵敏, clazzCode=A01, sex=女, time=3, total=5)
StudentVO(id=7, stuNo=10203, stuName=朱倩倩, clazzCode=A02, sex=女, time=3, total=3)
StudentVO(id=8, stuNo=10105, stuName=刘明华, clazzCode=A01, sex=男, time=4, total=5)
StudentVO(id=9, stuNo=20106, stuName=周强, clazzCode=C01, sex=男, time=2, total=2)
StudentVO(id=10, stuNo=10107, stuName=何欢欢, clazzCode=A01, sex=女, time=5, total=5)
其中time代表同一个班级中出现的顺序,total代表同一个班级的学生总数。
实现方式如下
public List<StudentVO> listSort() {
//查询学生列表 实际是需要带查询条件,这里做演示不做条件查询
List<StudentVO> list = studentDao.selectList();
if (!CollectionUtils.isEmpty(list)) {
// 以clazzCode为key进行分组,收集结果
Map<String, List<StudentVO>> listMap = list.stream().collect(Collectors.groupingBy(e -> e.getClazzCode()));
//分组统计个数
Map<String, Long> count = list.stream().collect(Collectors.groupingBy(e -> e.getClazzCode(), Collectors.counting()));
for (Map.Entry<String, List<StudentVO>> entry : listMap.entrySet()) {
Long i = 1L;
String key = entry.getKey();
List<StudentVO> values = entry.getValue();
for (StudentVO value : values) {
value.setTotal(count.get(key)); // 总数
value.setTime(i++); // 次数
return list;
我比较好奇的是,对于集合分组后,操作分组后的集合数据会影响到原时的集合,这样也简单的不少,但还未弄明白这其中的原理。
5.对集合元素进行排序
当对多个字段进行排序时,可直接在sql中进行排序,也可以在代码中利用stream进行排序。
下面就对用户信息进行排序,要求是根据更新时间降序,姓名和性别升序排序:
其中实体类为
public List<User> getList() {
//查询用户列表 实际是需要带查询条件,这里做演示不做条件查询 根据更新时间降序,姓名和性别升序排序
List<User> list = userDao.selectList();
List<User> sortList = new ArrayList<>();
if (!CollectionUtils.isEmpty(list)) {
// 按某些字段进行排序
// 需要注意的是list.stream()对数据进行操作后,原list不会发现变化,要么不使用.stream()方法,要么使用新的集合接收
sortList = list.stream().sorted(
Comparator.comparing(User::getUpdateTime, Comparator.reverseOrder())
.thenComparing(User::getName)
.thenComparing(User::getSex)
).collect(Collectors.toList());
return sortList;
使用代码根据对象的某些属性排序时,使用stream的sorted方法,再结合 java.util.Comparator
的comparing()
方法,默认是按升序排序,降序时采用reverseOrder()
方法即可
就是这么简单,你学废了吗?感觉有用的话,给笔者点个赞吧 !