Optional和Stream的组合使用

一、介绍

之间文章提到过,Optional的核心是帮助我们减少空指针异常的出现,它和Stream一起使用时,可以达到 减少空指针异常,又能简化代码 的效果。

二、定义Approve实体

java 复制代码
import lombok.*;

import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Approve {
    private String approveId;
    private List<NodeInfo> nodeList;
    private CreateApprove createInfo;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class NodeInfo implements Comparable<NodeInfo> {
    private String nodeId;
    private String nodeName;
    private int sort;
    private List<NodeProcessor> nodeProcessorList;

    //按照 sort 进行升序排序
    @Override
    public int compareTo(NodeInfo o) {
        return Integer.compare(getSort(), o.getSort());
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class NodeProcessor {
    private String processorId;
    private String handlerUser;
    private String state;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class CreateApprove {
    private String creator;
    private LocalDateTime createTime;
}

三、提供创建Approve的工具类

java 复制代码
import java.util.ArrayList;
import java.util.List;

public class ApproveProvider {
    public static List<NodeInfo> buildNodeList() {
        List<NodeInfo> nodeList = new ArrayList<NodeInfo>();
        List<NodeProcessor> nodeProcessorA = new ArrayList<>();
        nodeProcessorA.add(new NodeProcessor("processorId-A1", "处理人小红", "处理完成"));
        nodeProcessorA.add(new NodeProcessor("processorId-A2", "处理人小张", "处理中"));
        nodeProcessorA.add(new NodeProcessor("processorId-A3", "处理人小白", "处理中"));
        // 节点A
        NodeInfo nodeInfoA = new NodeInfo("nodeId-A", "节点A", 0, nodeProcessorA);

        List<NodeProcessor> nodeProcessorB = new ArrayList<>();
        nodeProcessorB.add(new NodeProcessor("processorId-B", "处理人小兰", "处理中"));
        //节点B
        NodeInfo nodeInfoB = new NodeInfo("nodeId-B", "节点B", 7, nodeProcessorB);

        List<NodeProcessor> nodeProcessorC = new ArrayList<>();
        nodeProcessorC.add(new NodeProcessor("processorId-C", "处理人小黑", "未处理"));
        //节点C
        NodeInfo nodeInfoC = new NodeInfo("nodeId-C", "节点C", 5, nodeProcessorC);

        //节点D
        NodeInfo nodeInfoD = new NodeInfo("nodeId-D", "节点D", 2, null);

        nodeList.add(nodeInfoA);
        nodeList.add(nodeInfoB);
        nodeList.add(nodeInfoC);
        nodeList.add(nodeInfoD);
        return nodeList;
    }
}

四、简单Demo

需求一:收集A节点里处理中的数据

需求二:筛选出节点A中状态为"处理中"的数据,并判断处理人是否为小白

需求三:对象中的nodeList数据,按照 sort 进行排序

java 复制代码
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Optional 和 Stream
 */
public class OptionalAndStreamDemo {
    public static void main(String[] args) {
        Approve approveHasNode = new Approve();
        approveHasNode.setNodeList(ApproveProvider.buildNodeList());

        //获取所有节点的处理人信息-1
        List<List<NodeProcessor>> processorList1 = Optional.of(approveHasNode)    //包装顶层对象
                .map(Approve::getNodeList)      //提取节点列表
                .map(Collection::stream)        // Collection::stream 等价于 nodeInfoList -> nodeInfoList.stream()
                .orElse(Stream.empty())         //兜底,就算节点列表为null ,也会返回一个空流,保证流程不会异常
                .map(NodeInfo::getNodeProcessorList)  //提取所有节点的处理人列表
                .collect(Collectors.toList());   //收集结果

        //获取所有节点的处理人信息-2 [扁平化流]
        List<NodeProcessor> processorList2 = Optional.of(approveHasNode)    //包装顶层对象
                .map(Approve::getNodeList)      //提取节点列表
                .map(Collection::stream)        //节点列表nodeList 转 Stream流
                .orElse(Stream.empty())         //兜底,就算节点列表为null ,也返回一个空流
                .map(NodeInfo::getNodeProcessorList)  //提取所有节点的 nodeProcessorList
                .filter(Objects::nonNull)       //过滤,仅保留每个节点下,不为 null的nodeProcessorList
                .flatMap(Collection::stream)    //扁平化流:将所有节点的nodeProcessorList流合并为单个nodeProcessorList流
                .collect(Collectors.toList());  //收集结果

        //需求一:收集A节点里处理中的数据 [扁平化流]
        List<NodeProcessor> processorList3 = Optional.of(approveHasNode)    //包装顶层对象
                .map(Approve::getNodeList)      //提取节点列表
                .map(Collection::stream)        //节点列表NodeList 转 Stream流
                .orElse(Stream.empty())         //兜底,就算节点列表为null ,也返回一个空流
                .filter(nodeInfo -> nodeInfo.getNodeId().equals("nodeId-A")) //过滤,仅保留节点列表中nodeId为 "nodeId-A"的节点
                .map(NodeInfo::getNodeProcessorList)  //因为链式加载的原因,所以肯定是提取节点A下面的数据,而不是提取所有节点
                .filter(Objects::nonNull)       //过滤,仅保留A节点下,不为null的nodeProcessorList
                .flatMap(Collection::stream)    //扁平化流:将节点A的nodeProcessorList流合并为单个nodeProcessorList流
                .filter(processor -> processor.getState().equals("处理中"))
                .collect(Collectors.toList());  //收集结果

        //需求二:筛选出节点A中状态为"处理中"的数据,并判断处理人是否为小白
        boolean result = Optional.of(approveHasNode)    //包装顶层对象
                .map(Approve::getNodeList)      //提取节点列表
                .map(Collection::stream)        //节点列表NodeList 转 Stream流
                .orElse(Stream.empty())         //兜底,就算节点列表为null ,也返回一个空流
                .filter(nodeInfo -> nodeInfo.getNodeId().equals("nodeId-A")) //过滤,仅保留节点列表中nodeId为 "nodeId-A"的节点
                .map(NodeInfo::getNodeProcessorList)  //因为链式加载的原因,所以肯定是提取节点A下面的数据,而不是提取所有节点
                .filter(Objects::nonNull)       //过滤,仅保留A节点下,不为null的nodeProcessorList
                .flatMap(Collection::stream)    //扁平化流:将节点A的nodeProcessorList流合并为单个nodeProcessorList流
                //过滤,仅保留节点A中,处理状态是处理中的NodeProcessor数据
                .filter(processor -> processor.getState().equals("处理中"))
                //过滤出来的NodeProcessor数据,只要包含有一个"处理人小白",就返回true,否则返回false
                .anyMatch(processor -> processor.getHandlerUser().equals("处理人小白"));
        System.out.println("判断结果为:" + result);

        //需求三:对象中的nodeList数据,按照 sort 进行排序
        List<NodeInfo> nodeInfos = Optional.of(approveHasNode)
                .map(Approve::getNodeList)      //提取节点列表
                .map(Collection::stream)        //节点列表NodeList 转 Stream流
                .orElse(Stream.empty())         //兜底,就算节点列表为null ,也返回一个空流
                .sorted(NodeInfo::compareTo)   //升序排序
                .collect(Collectors.toList());
        System.out.println("排序结果为:" + nodeInfos);
    }
}

举个例子,我甚至可以NodeList不传值,这代码也不会出现空指针异常,并且anyMatch方法判断的时候,仍然会返回 false

如果不使用Stream流,肯定要做一堆判断,比如先要判断 nodeList集合是否为空,再判断 nodeProcessorList 集合是否为空,这样才能保证避免空指针,最后才可以添加筛选条件。

相关推荐
xiaohaiAIgeo36 分钟前
【2026年】HG/T 20656-2024化工暖通空调设计规范:新版标准的变化与影响
java·前端·javascript·科普知识
小强库计算机毕业设计1 小时前
基于 Spring Boot + Vue3 的校园管理系统
java·spring boot·后端·项目实战·管理系统·技术分享·校园管理系统实战
霸道流氓气质1 小时前
Java中信号量(Semaphore):从本地到分布式
java·开发语言·分布式
怪奇云呼军1 小时前
G.711、Opus 和重采样会拖慢识别吗?闪电智能VoiceAgent 的音频入口怎么选
java·人工智能·python·算法·云计算·音视频
编程令我快乐1 小时前
maven部分构建参数讲解
java·maven
ZC跨境爬虫1 小时前
LeetCode 27. 移除元素(双指针详解 + Java Python 多解法对比)
java·python·leetcode
kisbad2 小时前
Day 036|OpenAI Agents SDK 快速开始:今天跑通第一个 Agent
java·前端·javascript
憧憬成为java架构高手的小白2 小时前
langchain4j框架学习
java
0x532 小时前
Java网络编程(四)
java·网络
ly76893 小时前
Java 设计模式详解:从原则到 23 种经典模式
java·开发语言·设计模式