怎麼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