How to break java8 stream foreach
Introduction to the
We usually need to iterate through the data in a Java Stream, with foreach being the most common method.
But sometimes we don’t want to process all the data, or sometimes the Stream can be very long, or it can be infinite at all.
One way is to filter out the data we need to process, and then foreach through it.
So how do we break the stream directly? This article focuses on this problem today.
Using Spliterator
As we mentioned in the previous article when we talked about Spliterator, in the tryAdvance method, if false is returned, the Spliterator will stop processing subsequent elements.
With this idea, we can create a custom Spliterator.
Suppose we have a stream like this:
Stream<Integer> ints = Stream.of(1.2.3.4.5.6.7.8.9.10);
Copy the code
We want to define an operation that stops when x is greater than 5.
Let’s define a generic Spliterator:
public class CustomSpliterator<T> extends Spliterators.AbstractSpliterator<T> {
private Spliterator<T> splitr;
private Predicate<T> predicate;
private volatile boolean isMatched = true;
public CustomSpliterator(Spliterator<T> splitr, Predicate<T> predicate) {
super(splitr.estimateSize(), 0);
this.splitr = splitr;
this.predicate = predicate;
}
@Override
public synchronized boolean tryAdvance(Consumer<? super T> consumer) {
boolean hadNext = splitr.tryAdvance(elem -> {
if (predicate.test(elem) && isMatched) {
consumer.accept(elem);
} else {
isMatched = false; }});returnhadNext && isMatched; }}Copy the code
In the class above, predicate is the judgment condition we’re passing in, and we rewrite the tryAdvance by adding predicate. Test (ELEm) to the judgment condition so that it returns false if the condition is not satisfied.
See how to use it:
@Slf4j
public class CustomSpliteratorUsage {
public static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<T> predicate) {
CustomSpliterator<T> customSpliterator = new CustomSpliterator<>(stream.spliterator(), predicate);
return StreamSupport.stream(customSpliterator, false);
}
public static void main(String[] args) {
Stream<Integer> ints = Stream.of(1.2.3.4.5.6.7.8.9.10);
List<Integer> result =
takeWhile(ints, x -> x < 5) .collect(Collectors.toList()); log.info(result.toString()); }}Copy the code
We define a takeWhile method that accepts the Stream and predicate conditions.
The predicate condition only continues when the predicate condition is satisfied. Let’s see the output:
[main] INFO com.flydean.CustomSpliteratorUsage - [1.2.3.4]
Copy the code
Customize forEach methods
In addition to using Spliterator, we can also customize the forEach method to use our own traversal logic:
public class CustomForEach {
public static class Breaker {
private volatile boolean shouldBreak = false;
public void stop(a) {
shouldBreak = true;
}
boolean get(a) {
returnshouldBreak; }}public static <T> void forEach(Stream<T> stream, BiConsumer<T, Breaker> consumer) {
Spliterator<T> spliterator = stream.spliterator();
boolean hadNext = true;
Breaker breaker = new Breaker();
while(hadNext && ! breaker.get()) { hadNext = spliterator.tryAdvance(elem -> { consumer.accept(elem, breaker); }); }}}Copy the code
In the example above, we used an external variable in forEach to determine whether to enter the spliterator.tryadvance method.
See how to use it:
@Slf4j
public class CustomForEachUsage {
public static void main(String[] args) {
Stream<Integer> ints = Stream.of(1.2.3.4.5.6.7.8.9.10);
List<Integer> result = new ArrayList<>();
CustomForEach.forEach(ints, (elem, breaker) -> {
if (elem >= 5 ) {
breaker.stop();
} else{ result.add(elem); }}); log.info(result.toString()); }}Copy the code
Above, we use the new forEach method and reset the judgment flag through the judgment condition, so as to achieve the purpose of break stream.
conclusion
Break a stream break a stream break a stream
Examples of this article github.com/ddean2009/l…
Welcome to pay attention to my public number: procedures those things, more wonderful waiting for you! For more, visit www.flydean.com