如果没有元素,则流的特殊行为

sla*_*dan 5 java java-stream

如何使用java8流式API表达这一点?

我想为itemConsumer流中的每个项目执行。如果没有要执行的项目emptyAction

当然,我可以这样写:

Consumer<Object> itemConsumer = System.out::println;
Runnable emptyAction = () -> {System.out.println("no elements");};

Stream<Object> stream = Stream.of("a","b"); // or Stream.empty()
List<Object> list = stream.collect(Collectors.toList());
if (list.isEmpty())
    emptyAction.run();
else
    list.stream().forEach(itemConsumer);
Run Code Online (Sandbox Code Playgroud)

但我宁愿避免任何Lists。

我还考虑过在peek方法中设置标志-但该标志将是非最终的,因此是不允许的。使用布尔型容器似乎也不过是一种解决方法。

Bor*_*der 3

你可以强迫reduce这样做。逻辑是减少 on ,如果遇到任何有用的数据,false则将值设置为。true

结果reducefalse没有遇到任何项目。如果遇到任何项目,那么结果将是true

boolean hasItems = stream.reduce(false, (o, i) -> {
    itemConsumer.accept(i);
    return true;
}, (l, r) -> l | r);
if (!hasItems) {
    emptyAction.run();
}
Run Code Online (Sandbox Code Playgroud)

这对于并行流应该可以正常工作,因为遇到项目的任何流都会将值设置为true

然而,我不确定我是否喜欢这个,因为该reduce操作的使用有点迟钝。

另一种方法是用作AtomicBoolean可变boolean容器:

final AtomicBoolean hasItems = new AtomicBoolean(false);
stream.forEach(i -> {
    itemConsumer.accept(i);
    hasItems.set(true);
});
if (!hasItems.get()) {
    emptyAction.run();
}
Run Code Online (Sandbox Code Playgroud)

但我不知道我是否或多或少喜欢这样。

最后,你可以得到你的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();
}
Run Code Online (Sandbox Code Playgroud)

这看起来更简洁,但可能不实用。所以也许是一个装饰器模式 -

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 **/);
Run Code Online (Sandbox Code Playgroud)

TL;DR:某些东西必须记住您在使用期间是否遇到过任何事情Stream,无论是:

  • Stream本身的情况reduce
  • AtomicBoolean; 或者
  • 消费者

我认为从逻辑的角度来看,消费者可能处于最佳位置。