Special flow behavior if there are no elements

How can I express this using java8 streaming-API?

I want to execute itemConsumerfor each stream item. If there are no items that I want to execute emptyAction.

Of course, I could write something like this:

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);

But I would prefer to avoid any Lists.

I also thought about setting a flag in the method peek, but this flag will be invalid and therefore will not be allowed. Using a logical container also seems like a great deal of workaround.

+4
source share
5 answers

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: - , - Stream, :

  • Stream reduce;
  • AtomicBoolean;

, , , .

+3

- :

stream.peek(itemConsumer).reduce((a, b) -> a).orElseGet(() -> {
    emptyAction.run();
    return null;
});

, , itemConsumer (, forEach, forEachOrdered). , null.

+2

Theres :

Spliterator<Object> sp=stream.spliterator();
if(!sp.tryAdvance(itemConsumer))
    emptyAction.run();
else
    sp.forEachRemaining(itemConsumer);

, :

Spliterator<Object> sp=stream.parallel().spliterator();
if(!sp.tryAdvance(itemConsumer))
    emptyAction.run();
else
    StreamSupport.stream(sp, true).forEach(itemConsumer);

-, reduce.

+1

:

if(stream.peek(itemConsumer).count() == 0){
    emptyAction.run();
}

, count , peek, Stream Java 9 (. ), , , , :

if(stream.peek(itemConsumer).mapToLong(e -> 1).sum() == 0){
    emptyAction.run();
}
+1

:

    Stream<Object> stream = Stream.of("a","b","c");
    //Stream<Object> stream = Stream.empty();


    Runnable defaultRunnable = () -> System.out.println("empty Stream");
    Consumer<Object> printConsumer = System.out::println;

    Runnable runnable = stream.map(x -> toRunnable(x, printConsumer)).reduce((a, b) -> () -> {
        a.run();
        b.run();
    }).orElse(defaultRunnable);

    runnable.run(); // prints a, b, c (or empty stream when it is empty)


    // for type inference
    static <T> Runnable toRunnable(T t, Consumer<T> cons){ 
        return ()->cons.accept(t);
    }

peek(), Javadoc " "

0

Source: https://habr.com/ru/post/1630079/


All Articles