怎么break java8 stream的foreachjava
咱们一般须要在java stream中遍历处理里面的数据,其中foreach是最最经常使用的方法。git
可是有时候咱们并不想处理完全部的数据,或者有时候Stream可能很是的长,或者根本就是无限的。github
一种方法是先filter出咱们须要处理的数据,而后再foreach遍历。ide
那么咱们如何直接break这个stream呢?今天本文重点讲解一下这个问题。this
上篇文章咱们在讲Spliterator的时候提到了,在tryAdvance方法中,若是返回false,则Spliterator将会中止处理后续的元素。code
经过这个思路,咱们能够建立自定义Spliterator。get
假如咱们有这样一个stream:it
Stream<Integer> ints = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
咱们想定义一个操做,当x > 5的时候就中止。java8
咱们定义一个通用的Spliterator:ast
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; } }); return hadNext && isMatched; } }
在上面的类中,predicate是咱们将要传入的判断条件,咱们重写了tryAdvance,经过将predicate.test(elem)加入判断条件,从而当条件不知足的时候返回false.
看下怎么使用:
@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()); } }
咱们定义了一个takeWhile方法,接收Stream和predicate条件。
只有当predicate条件知足的时候才会继续,咱们看下输出的结果:
[main] INFO com.flydean.CustomSpliteratorUsage - [1, 2, 3, 4]
除了使用Spliterator,咱们还能够自定义forEach方法来使用本身的遍历逻辑:
public class CustomForEach { public static class Breaker { private volatile boolean shouldBreak = false; public void stop() { shouldBreak = true; } boolean get() { return shouldBreak; } } 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); }); } } }
上面的例子中,咱们在forEach中引入了一个外部变量,经过判断这个外部变量来决定是否进入spliterator.tryAdvance方法。
看下怎么使用:
@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()); } }
上面咱们用新的forEach方法,并经过判断条件来重置判断flag,从而达到break stream的目的。
本文经过两个具体的例子讲解了如何break一个stream,但愿你们可以喜欢。
本文的例子https://github.com/ddean2009/learn-java-streams/tree/master/break-stream-foreach
欢迎关注个人公众号:程序那些事,更多精彩等着您!
更多内容请访问 www.flydean.com