怎么break java8 stream的foreach

怎么break java8 stream的foreachjava

简介

咱们一般须要在java stream中遍历处理里面的数据,其中foreach是最最经常使用的方法。git

可是有时候咱们并不想处理完全部的数据,或者有时候Stream可能很是的长,或者根本就是无限的。github

一种方法是先filter出咱们须要处理的数据,而后再foreach遍历。ide

那么咱们如何直接break这个stream呢?今天本文重点讲解一下这个问题。this

使用Spliterator

上篇文章咱们在讲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]

自定义forEach方法

除了使用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
相关文章
相关标签/搜索