JDK8中的 Stream流式编程用法优化(工具类在文章最后)

Java从JDK8起提供了Stream流这个功能,于是项目里出现了大量基于Stream流的写法。随着项目的进行,慢慢的代码中铺天盖地的都是下面的写法:

java 复制代码
 List<User> userList = null;
 if (condition) {
      userList = new ArrayList<>();
	  userList.add(User.builder().id(1L).name("张三").age(25).build());
	  userList.add(User.builder().id(2L).name("李四").age(30).build());
	  userList.add(User.builder().id(3L).name("王五").age(40).build());
 }
 ...省略了的业务逻辑...
 List<User> users = userList.stream().filter(it-> it.getAge() > 28).collect(Collectors.toList());
 System.out.println(users);

上面的代码中,构建了一个包含3个User对象的List,然后取出了其中age大于28的User对象构成了新的List。相信如果在日常工作和学习中写过了大量的类似的代码,很容易能看出问题来,userList会出现为空的情况,这时候是很容易触发空指针异常的。所以我们在使用stream前通常都是需要做非空判断的。于是,优化后的代码出现了:

java 复制代码
List<User> userList = null;
if (condition) {
     userList = new ArrayList<>();
	 userList.add(User.builder().id(1L).name("张三").age(25).build());
	 userList.add(User.builder().id(2L).name("李四").age(30).build());
	 userList.add(User.builder().id(3L).name("王五").age(40).build());
}
 ...省略了的业务逻辑...
if (userList != null) {
	 List<User> users = userList.stream().filter(it-> it.getAge() > 28).collect(Collectors.toList());
	 System.out.println(users);
}

更近一步,还可以这样写:

java 复制代码
List<User> userList = null;
if (condition) {
     userList = new ArrayList<>();
	 userList.add(User.builder().id(1L).name("张三").age(25).build());
	 userList.add(User.builder().id(2L).name("李四").age(30).build());
	 userList.add(User.builder().id(3L).name("王五").age(40).build());
}
 ...省略了的业务逻辑...
List<User> users = Optional.of(userList).orElse(List.of()).stream().filter(it-> it.getAge() > 28).collect(Collectors.toList());
System.out.println(users);

到了这里,这已经是一段比较常规的业务代码了,但是它真的很丑有没有。作为一个业务研发人员,我为什么要考虑这么多呢?我不需要关注List是怎么转换成stream的,同样的,我也不关心为什么在使用完stream以后还要collect。于是,我将上面的流式代码封装成了工具类,上面的代码可以简化为:

java 复制代码
List<User> userList = null;
if (condition) {
     userList = new ArrayList<>();
	 userList.add(User.builder().id(1L).name("张三").age(25).build());
	 userList.add(User.builder().id(2L).name("李四").age(30).build());
	 userList.add(User.builder().id(3L).name("王五").age(40).build());
}
 ...省略了的业务逻辑...
List<User> users = Streams.filter(userList, it-> it.getAge() > 28);
System.out.println(users);

同样的,也支持其他操作:

java 复制代码
//返回年龄大于28的用户列表
List<User> filterUsers = Streams.filter(userList, it -> it.getAge() > 28);

//返回年龄大于28的用户的姓名列表
List<String> filterNames = Streams.toList(userList, it -> it.getAge() > 28, User::getName);

//返回年龄大于28的用户的姓名作为key, 年龄只作为value的map
Map<String, Integer> filterNameAndAgeMap = Streams.toMap(userList, it -> it.getAge() > 28, User::getName, User::getAge);

//返回所有用户的姓名列表
List<String> allUserNames = Streams.toList(userList, User::getName);

//返回所有用户的姓名作为key, 用户信息只作为value的map
Map<String, User> allUserMap = Streams.mappingToMap(userList, User::getName);

//返回所有用户的姓名作为key, 年龄作为value的map
Map<String, Integer> nameAndAgeMap = Streams.toMap(userList, User::getName, User::getAge);

//返回年龄大于28的第一个用户, 如果找不到则使用默认值
User user = Streams.findFirstOrElse(userList, it-> it.getAge() > 28, new User());

//返回年龄大于28的第一个用户, 如果找不到则抛出异常
User user2 = Streams.findFirstOrThrow(userList, it-> it.getAge() > 28, "未找到符合条件的数据");

最后附上工具类源码供各位取用:

java 复制代码
package com.zlyx.common.util;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class Streams {
    
    public static <T> List<T> filter(List<T> dataList, Predicate<T> filter) {
        return Optional.of(dataList).orElse(List.of()).stream().filter(filter).collect(Collectors.toList());
    }

    public static <T> Set<T> filter(Set<T> dataList, Predicate<T> filter) {
        return Optional.of(dataList).orElse(Set.of()).stream().filter(filter).collect(Collectors.toSet());
    }

    public static <T> T findFirstOrThrow(List<T> dataList) throws Exception {
        return findFirstOrThrow(dataList, "未找到符合条件的数据");
    }

    public static <T> T findFirstOrThrow(List<T> dataList, String errorMsg) throws Exception {
        return findFirstOrThrow(dataList, Objects::nonNull, errorMsg);
    }

    public static <T> T findFirstOrThrow(List<T> dataList, Predicate<T> filter, String errorMsg) throws Exception {
        return Optional.of(dataList).orElse(List.of()).stream().filter(filter).findFirst().orElseThrow(() -> new Exception(errorMsg));
    }

    public static <T> T findFirstOrElse(List<T> dataList, T defaultValue) {
        return findFirstOrElse(dataList, Objects::nonNull, defaultValue);
    }

    public static <T> T findFirstOrElse(List<T> dataList, Predicate<T> filter, T defaultValue) {
        return Optional.of(dataList).orElse(List.of()).stream().filter(filter).findFirst().orElse(defaultValue);
    }

    public static <T, R> R findAnyOrNull(List<T> dataList, Function<T, R> mapper) {
        return Optional.of(dataList).orElse(List.of()).stream().map(mapper).filter(Objects::nonNull).findAny().orElse(null);
    }

    public static <T, R> R findAnyOrThrow(List<T> dataList, Function<T, R> mapper, String errorMsg) throws Exception {
        return Optional.of(dataList).orElse(List.of()).stream().map(mapper).filter(Objects::nonNull).findAny().orElseThrow(() -> new Exception(errorMsg));
    }

    public static <T, R> Set<R> toSet(List<T> dataList, Function<T, R> mapper) {
        return toSet(dataList, Objects::nonNull, mapper);
    }

    public static <T, R> Set<R> toSet(List<T> dataList, Predicate<T> filter, Function<T, R> mapper) {
        return Optional.of(dataList).orElse(List.of()).stream().filter(filter).map(mapper).collect(Collectors.toSet());
    }

    public static <T, R> List<R> toList(List<T> dataList, Function<T, R> mapper) {
        return toList(dataList, Objects::nonNull, mapper);
    }

    public static <T, R> List<R> toList(List<T> dataList, Predicate<T> filter, Function<T, R> mapper) {
        return Optional.of(dataList).orElse(List.of()).stream().filter(filter).map(mapper).distinct().collect(Collectors.toList());
    }

    public static <T, K> Map<K, T> mappingToMap(List<T> dataList, Function<T, K> keyMapper) {
        return mappingToMap(dataList, Objects::nonNull, keyMapper);
    }

    public static <T, K> Map<K, T> mappingToMap(List<T> dataList, Predicate<T> filter, Function<T, K> keyMapper) {
        return Optional.of(dataList).orElse(List.of()).stream().filter(filter).collect(Collectors.toMap(keyMapper, it -> it, (v1, v2) -> v2));
    }

    public static <T, K, V> Map<K, V> toMap(List<T> dataList, Function<T, K> keyMapper, Function<T, V> valueMapper) {
        return toMap(dataList, Objects::nonNull, keyMapper, valueMapper);
    }

    public static <T, K, V> Map<K, V> toMap(List<T> dataList, Predicate<T> filter, Function<T, K> keyMapper, Function<T, V> valueMapper) {
        return Optional.of(dataList).orElse(List.of()).stream().filter(filter).collect(Collectors.toMap(keyMapper, valueMapper));
    }
}
相关推荐
Z_W_H_23 分钟前
【springboot】IDEA手动创建SpringBoot简单工程(无插件)
java·spring boot·intellij-idea
HeXDev26 分钟前
【SkyWalking】服务端部署与微服务无侵入接入实战指南
java·微服务·架构·skywalking·链路追踪·微服务治理
探索java1 小时前
Java 深入解析:JVM对象创建与内存机制全景图
java·jvm
Sylvia-girl1 小时前
Java---IDEA
java·开发语言·intellij-idea
Z_W_H_1 小时前
【Springboot】Bean解释
java·开发语言
Otaku love travel2 小时前
老系统改造增加初始化,自动化数据源配置(tomcat+jsp+springmvc)
java·tomcat·初始化·动态数据源
DKPT2 小时前
Java设计模式之行为型模式(责任链模式)介绍与说明
java·笔记·学习·观察者模式·设计模式
L_autinue_Star2 小时前
手写vector容器:C++模板实战指南(从0到1掌握泛型编程)
java·c语言·开发语言·c++·学习·stl
晨岳2 小时前
CentOS 安装 JDK+ NGINX+ Tomcat + Redis + MySQL搭建项目环境
java·redis·mysql·nginx·centos·tomcat
执笔诉情殇〆3 小时前
前后端分离(java) 和 Nginx在服务器上的完整部署方案(redis、minio)
java·服务器·redis·nginx·minio