Althought the above answers are perfectly valid, they require to collect and/or pre-fetch the elements before processing them (both can be an issue if the Stream is very long).
For my needs, I therefore adapted Louis's answer to the question pointed out by Julian and adapted it to keep the stop/break item. See the keepBreak
parameter ::
public static <T> Spliterator<T> takeWhile(final Spliterator<T> splitr, final Predicate<? super T> predicate, final boolean keepBreak) {
return new Spliterators.AbstractSpliterator<T>(splitr.estimateSize(), 0) {
boolean stillGoing = true;
@Override
public boolean tryAdvance(final Consumer<? super T> consumer) {
if (stillGoing) {
final boolean hadNext = splitr.tryAdvance(elem -> {
if (predicate.test(elem)) {
consumer.accept(elem);
} else {
if (keepBreak) {
consumer.accept(elem);
}
stillGoing = false;
}
});
return hadNext && (stillGoing || keepBreak);
}
return false;
}
};
}
public static <T> Stream<T> takeWhile(final Stream<T> stream, final Predicate<? super T> predicate, final boolean keepBreak) {
return StreamSupport.stream(takeWhile(stream.spliterator(), predicate, keepBreak), false);
}
Usage:
public List<String> values = Arrays.asList("some", "words", "before", "BREAK", "AFTER");
@Test
public void testStopAfter() {
Stream<String> stream = values.stream();
//how to filter stream to stop at the first BREAK
stream = stream.filter(makeUntil(s -> "BREAK".equals(s)));
final List<String> actual = stream.collect(Collectors.toList());
final List<String> expected = Arrays.asList("some", "words", "before", "BREAK");
assertEquals(expected, actual);
}
Disclaimer: I am not 100% sure this will work on parallel (the new Stream is certainly not parallel) or non-sequential streams. Please comment/edit if you have some hints on this.