7

Is there any stream equivalent to the following

List<Integer> ints;
while (!(ints = this.nextInts()).isEmpty()) {
// do work
}
Pshemo
  • 122,468
  • 25
  • 185
  • 269
Jan Tajovsky
  • 1,162
  • 2
  • 13
  • 34
  • 5
    Expose `nextInts` through an `Iterator` interface and it can be done – bowmore Jun 22 '17 at 12:57
  • 2
    In Java 9 you can do `Stream> ints = Stream.iterate(nextInts(), l -> !l.isEmpty(), l -> nextInts());` – Flown Jun 22 '17 at 13:00
  • use foreach loop of java to iterate over the list. – kk. Jun 22 '17 at 13:00
  • 2
    Yes, it’s possible. – Holger Jun 22 '17 at 13:16
  • Your code is barely legible: just use `while(true) { List ints = nextInts(); if (ints.isEmpty()) break; }`. It's better because it's more readable and you can debug this way easier! – Olivier Grégoire Jun 22 '17 at 13:53
  • @OlivierGrégoire I would say `List ints = nextInts(); while(! ints.isEmpty()) { doWork(); ints = nextInts(); }` - repetition of `nextInts()` is slightly non-DRY, but it's a well established pattern. – slim Jun 22 '17 at 14:03
  • 1
    @slim Yeah, it's called a for-loop which I would have used second, after my pattern. But I would have used `for(...;...;...) {}` instead, just for readability. – Olivier Grégoire Jun 22 '17 at 14:04

1 Answers1

8

first, thanks for the @Olivier Grégoire comments. it change my answer to a new knowledge.

write your own Spliterator for the unknown size nextInts, then you can using StreamSupport#stream to create a stream for nextInts. for example:

generateUntil(this::nextInts, List::isEmpty).forEach(list -> {
    //do works
});

import static java.util.stream.StreamSupport.stream;

<T> Stream<T> generateUntil(final Supplier<T> generator, Predicate<T> stop) {
    long unknownSize = Long.MAX_VALUE;

    return stream(new AbstractSpliterator<T>(unknownSize, Spliterator.ORDERED) {
        @Override
        public boolean tryAdvance(Consumer<? super T> action) {
            T value = generator.get();

            if (stop.test(value)) {
                return false;
            }

            action.accept(value);
            return true;
        }
    }, false);
}
holi-java
  • 29,655
  • 7
  • 72
  • 83
  • Just remove the first part: it's clunky as hell and will induce everybody in error when they try to remove the `limit(int)` clause (because they certainly will, but I doubt they'll read your warning). – Olivier Grégoire Jun 22 '17 at 13:58
  • @OlivierGrégoire yeah. I'll add some comments on it. thanks sir. – holi-java Jun 22 '17 at 13:59
  • 2
    What you could do is provide directly the stream in a separate method. Something like ` Stream generateUntilEmpty(Supplier>)`. People know streams, people know suppliers. Very few people know `Spliterator`. – Olivier Grégoire Jun 22 '17 at 14:03
  • @OlivierGrégoire sir. how about is now? is it what you mean? – holi-java Jun 22 '17 at 14:14
  • @Holger yeah. after thinking. I remove the first approach. – holi-java Jun 22 '17 at 14:15
  • 3
    @holi-java Not really: you still give a `Spliterator` as intermediary usage. Just get rid of it and use the method signature I provided. It's really the easiest for the final user: "hey, I generate a stream until I get an empty list". Here, you're still forcing the end-user into checking for other methods and don't provide a stream directly. Also, use the term `generate` just like `Stream.generate` exists. It eases understand what your method does. – Olivier Grégoire Jun 22 '17 at 14:17
  • thanks for @OlivierGrégoire and Holger comments. Indeed the final code is easy to use now. – holi-java Jun 22 '17 at 14:24
  • 2
    Much better and usable. Finally get my +1. Though for the naming, I still think `generateUntil...` is better because it's similar to `Stream.generate`. – Olivier Grégoire Jun 22 '17 at 14:28
  • @OlivierGrégoire thanks for your help very much, sir. It really simpler and expressiveness than mine. – holi-java Jun 22 '17 at 14:29
  • @OlivierGrégoire how about to introduce an additional `Predicate`, sir? this will makes it context independent. – holi-java Jun 22 '17 at 14:31
  • 2
    That was my first thought, but it's easy to mess up, so if you go that route, make sure to use `generateUntil`, which does what you currently do, and `generateWhile` which has the opposite conditions. This way the user can still express whatever he/she wants using only the supplier and `List::isEmpty` (instead of having to write `list -> !list.isEmpty()`. – Olivier Grégoire Jun 22 '17 at 14:34
  • 1
    @OlivierGrégoire after of your suggestion, I refactoring the code like as yours. and I introduce a `Predicate` now. thanks for your suggestion again. and I thanks you for somewhere. – holi-java Jun 22 '17 at 14:37
  • @Holger sir, the code after refactoring, I think the `NONNULL` characteristic is unnecessary. Am I right? – holi-java Jun 22 '17 at 14:54
  • 2
    @holi-java: `NONNULL` never was required; it’s only a hint to potential optimizations (which do not happen today anyway), but indeed, now that you can’t guaranty the elements to be non-`null`, you should remove the `NONNULL` characteristic. – Holger Jun 22 '17 at 14:57
  • @Holger my first answer is just answer the OP's question. I don't think it any more. thanks for your help along the way. I learn it more by helping of yours. :) – holi-java Jun 22 '17 at 15:00