Is there any way to manually short circuit a stream (like in findFirst)?
Example:
Imagine a huge dictionary ordered by word size and alphabet:
cat
... (many more)
lamp
mountain
... (many more)
Only ready and compute the file from beginning, return immediately when line size exceeds 4:
read cat, compute cat
...
read tree, compute lamp
read mountain, return
The following code is very concise but does not take into advantage the order of the stream, it has to ready every line:
try (Stream<String> lines = Files.lines(Paths.get(DICTIONARY_PATH))) {
return lines
// filter for words with the correct size
.filter(line -> line.length() == 4)
// do stuff...
.collect(Collectors.toList());
}
Answer based on Limit a stream by a predicate, processing correctly stops when predicate returns false. Hopefully this method comes available in Java 9:
private static List<String> getPossibleAnswers(int numberOfChars, char[][] possibleChars) throws IOException {
try (Stream<String> lines = Files.lines(Paths.get(DICTIONARY_PATH)) {
return takeWhile(lines, line -> line.length() <= numberOfChars)
// filter length
.filter(line -> line.length() == numberOfChars)
// do stuff
.collect(Collectors.toList());
}
}
static <T> Spliterator<T> takeWhile(Spliterator<T> splitr, Predicate<? super T> predicate) {
return new Spliterators.AbstractSpliterator<T>(splitr.estimateSize(), 0) { boolean stillGoing = true;
@Override
public boolean tryAdvance(Consumer<? super T> consumer) {
if (stillGoing) {
boolean hadNext = splitr.tryAdvance(elem -> {
if (predicate.test(elem)) {
consumer.accept(elem);
} else {
stillGoing = false;
}
});
return hadNext && stillGoing;
}
return false;
}
};
}
static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> predicate) {
return StreamSupport.stream(takeWhile(stream.spliterator(), predicate), false);
}