您可以强制 reduce 执行此操作。逻辑是减少false,如果遇到任何有用的数据,将值设置为true。
reduce 的结果是false,然后没有遇到任何项目。如果遇到任何项目,则结果将是true:
boolean hasItems = stream.reduce(false, (o, i) -> {
itemConsumer.accept(i);
return true;
}, (l, r) -> l | r);
if (!hasItems) {
emptyAction.run();
}
这应该适用于并行流,因为任何遇到项目的流都会将值设置为true。
不过,我不确定我是否喜欢这个,因为它对 reduce 操作的使用略显迟钝。
另一种方法是将AtomicBoolean 用作可变的boolean 容器:
final AtomicBoolean hasItems = new AtomicBoolean(false);
stream.forEach(i -> {
itemConsumer.accept(i);
hasItems.set(true);
});
if (!hasItems.get()) {
emptyAction.run();
}
我不知道我是否更喜欢这个。
最后,你可以让你的itemConsumer记住状态:
class ItemConsumer implements Consumer<Object> {
private volatile boolean hasConsumedAny;
@Override
public void accept(Object o) {
hasConsumedAny = true;
//magic magic
}
public boolean isHasConsumedAny() {
return hasConsumedAny;
}
}
final ItemConsumer itemConsumer = new ItemConsumer();
stream.forEach(itemConsumer::accept);
if (!itemConsumer.isHasConsumedAny()) {
emptyAction.run();
}
这看起来有点整洁,但可能不实用。所以也许是装饰器模式 -
class ItemConsumer<T> implements Consumer<T> {
private volatile boolean hasConsumedAny;
private final Consumer<T> delegate;
ItemConsumer(final Consumer<T> delegate) {
this.delegate = delegate;
}
@Override
public void accept(T t) {
hasConsumedAny = true;
delegate.accept(t);
}
public boolean isHasConsumedAny() {
return hasConsumedAny;
}
}
final ItemConsumer<Object> consumer = new ItemConsumer<Object>(() -> /** magic **/);
TL;DR: something 必须记住你在消费Stream 的过程中是否遇到过任何事情,是这样的:
-
Stream 本身在reduce 的情况下;
-
AtomicBoolean;或
- 消费者
从逻辑的角度来看,我认为消费者可能处于最佳位置。