一、介绍
之间文章提到过,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 集合是否为空,这样才能保证避免空指针,最后才可以添加筛选条件。