Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a class in java 8 that implements a "null-terminated" stream without having to roll my own?

Or is there a better way to do this that I'm missing? I'd like to create a stream based on a Supplier (which are normally infinite), but have the stream terminate when the supplier returns null. I made this myself, but it seems like a fair amount of work to accomplish a pretty simple concept.

public class NullTerminatedStreamFactory {

    static int characteristics = Spliterator.ORDERED | Spliterator.DISTINCT;

    public static<T> Stream<T> makeNullTerminatedStream(Supplier<T> supplier) {
        return StreamSupport.stream(new NullTerminatedSpliteratorFromSupplier<>(supplier, Long.MAX_VALUE, characteristics), false);
    }

    static class NullTerminatedSpliteratorFromSupplier<T> extends Spliterators.AbstractSpliterator<T> {

        public NullTerminatedSpliteratorFromSupplier(Supplier<T> supplier, long est, int additionalCharacteristics) {
            super(est, additionalCharacteristics);
            this.supplier = supplier;
        }

        public Supplier<T> supplier;

        @Override
        public boolean tryAdvance(Consumer<? super T> action) {
            T next = supplier.get();
            if (next != null) {
                action.accept(next);
                return true;
            }
            return false;
        }
    }
}

For the record, I'm using it like this, to basically create a Stream from a BlockingQueue:

NullTerminatedStreamFactory.makeNullTerminatedStream(() -> {
            try {
                BlockingQueue<Message> queue = getBlockingQueue();
                return queue.poll(1, TimeUnit.SECONDS);
            } catch (Exception e) {
                log.error("Exception while trying to get message from queue", e);
            }
            return null;
        });
like image 587
Paul Whalen Avatar asked Dec 08 '15 18:12

Paul Whalen


1 Answers

You've already found a perfectly valid hand-made implementation.

As mentioned in the comments, Java 9 seems to add a takeWhile(Predicate) method. Until then, you could use a third-party library that implements something like takeWhile():

jOOλ

jOOλ has limitWhile(), which does the same thing:

Seq.generate(supplier).limitWhile(Objects::nonNull);

(disclaimer, I work for the company behind jOOλ)

Javaslang

Javaslang implemented their own Stream class, which is inspired by the Scala collections, and thus has takeWhile()

Stream.gen(supplier).takeWhile(Objects::nonNull);

Functional Java

Functional Java also ship with their own Stream implementation, that has a takeWhile() method:

Stream.fromFunction(i -> supplier.get()).takeWhile(o -> o != null);
like image 196
Lukas Eder Avatar answered Oct 31 '22 06:10

Lukas Eder