JDK8Stream需要考虑什么异常?

过程中

在一个流中进行多次操作,会不会因为之前的操作过滤光了数据而导致后续发生异常?

测试代码

我们直接用代码去测试,可以使用以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public static void main(String[] args) {
List<Integer> lists=new ArrayList<>();
lists.add(1);
lists.add(2);
lists.add(3);
lists.add(4);
lists.add(5);
lists.add(6);
lists.add(7);
lists.add(8);
lists.add(9);
lists.add(10);
Optional anInt=lists.stream().filter(
a->{
return (int)a >100;
}
).filter(
a->{
System.out.println(a.getClass().getName());
return (int)a >10;
}
).max(new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return Integer.compare((int)o1,(int)o2);
}
}
);
System.out.println(anInt);
}

测试结论

而最终的输出结果会是 Optional.empty ,也就是在操作的过程中无需关心

源码分析

以java.util.ArrayList调用stream()创建的流为样本,查看该类的filter实现,发现核心的逻辑并不复杂,就是根据接口进行验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//ReferencePipeline.java
@Override
public final Stream<P_OUT> filter(Predicate<? super P_OUT> predicate) {
Objects.requireNonNull(predicate);
// 看第一点说明
return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
StreamOpFlag.NOT_SIZED) {
// 看第二点说明
@Override
Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
//看第三点说明
return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
@Override
public void begin(long size) {
downstream.begin(-1);
}

@Override
public void accept(P_OUT u) {
// 符合lambda表达式就通过
if (predicate.test(u))
downstream.accept(u);
}
};
}
};
}
说明一~进行流的传递

new StatelessOp()操作的目的是为了通过将无状态的中间操作附加到现有流中来构造新流。

1
2
3
4
5
6
7
//ReferencePipeline.java
StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
StreamShape inputShape,
int opFlags) {
super(upstream, opFlags);
assert upstream.getOutputShape() == inputShape;
}
说明二~进行数据匹配
1
2
//AbstractPipeline
abstract Sink<E_IN> opWrapSink(int flags, Sink<E_OUT> sink);

接受一个Sink,它接受该操作输入类型的元素,并执行该操作,并返回一个Sink。

说明三~实现匹配逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Sink.java
static abstract class ChainedReference<T, E_OUT> implements Sink<T> {
protected final Sink<? super E_OUT> downstream;

public ChainedReference(Sink<? super E_OUT> downstream) {
this.downstream = Objects.requireNonNull(downstream);
}

@Override
public void begin(long size) {
downstream.begin(size);
}

@Override
public void end() {
downstream.end();
}

@Override
public boolean cancellationRequested() {
return downstream.cancellationRequested();
}
}

包装了一个Sink.ChainedReference并作为Sink的实现,重写了两个方案,begin的重写是为了重置迭代器,accept描述了lambda通过的值就可以添加到Sink中,这个内部类也只是作为默认实现,本身只有空指针的判断处理

在流处理结束后获取会出现什么异常?

处理后

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   // 第一段代码
public static void main(String[] args) {
List<Integer> lists=new ArrayList<>();
lists.add(1);
Optional anInt=lists.stream().filter(
a->{
return (int)a >100;
}
).max(new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return Integer.compare((int)o1,(int)o2);
}
}
);
System.out.println(anInt.get());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   // 第二段代码
public static void main(String[] args) {
List<Integer> lists=new ArrayList<>();
lists.add(null);

Optional anInt=lists.stream().filter(
a->{
return (int)a >100;
}
).max(new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return Integer.compare((int)o1,(int)o2);
}
}
);
System.out.println(anInt.get());
}

测试结论

第一段代码:

Exception in thread “main” java.util.NoSuchElementException: No value present

第二段代码:

Exception in thread “main” java.lang.NullPointerException

原因

NoSuchElementException异常

max/min等最终操作会返回两种结果,一是真正的结果,二是通过以下代码返回

1
2
3
4
5
6
7
8
// Optional.java
private static final Optional<?> EMPTY = new Optional<>();

public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}

NoSuchElementException异常就是因为Optional.EMPTY获取操作出现的

NullPointerException

因为null对象在进行逻辑运算的时候很容易出空指针异常,会直接从流操作中跑出来,本文为(int)null >100