提前中止Java Stream forEach的优雅解决方案

1.概述

Java Stream foreach 是一种声明式的,整洁的遍历循环。但是当我们满足某个条件想要中止这个循环的时候,通常却十分繁琐,比如使用异常,但通常这不是一种很好的实现方案

2.Java 9 Stream.takeWhile()

Stream.of("cat", "dog", "elephant", "fox", "rabbit", "duck")
	.takeWhile(n - > n.length()%2 !=0)
  .forEach(System.out::println)

运行结果

cat
dog

3.定制Spliterator

如果版本还是Java8的情况

首先,从我们的流中拿一个Spliterator,提供一个谓词Predicate 去控制break.

  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 class CustomSpliterator<T> extends Spliterators.AbstractSpliterator<T> {

    private Spliterator<T> spliterator;
    private Predicate<T> predicate;
    private boolean isMatched = true;

    public CustomSpliterator(Spliterator<T> spliterator, Predicate<T> predicate) {
        super(spliterator.estimateSize(), 0);
        this.spliterator = spliterator;
        this.predicate = predicate;
    }


    @Override
    public synchronized boolean tryAdvance(Consumer<? super T> consumer) {
        boolean hadNext = spliterator.tryAdvance(element -> {
            if(predicate.test(element) && isMatched){
                consumer.accept(element);
            }else{
                isMatched = false;
            }
        });
        return hadNext && isMatched;
    }
}

写一个测试,只要Stream里面还有元素并且满足我们的谓词的条件就会中止

  @Test
    public void whenCustomTakeWhileIsCalled_ThenCorrectItemsAreReturned(){
        Stream<String> initialStream = Stream.of("cat", "dog", "elephant", "fox", "rabbit", "duck");
        List<String> result = CustomTakeWhile.takeWhile(initialStream, x -> x.length() % 2 != 0).collect(Collectors.toList());
        assertEquals(asList("cat", "dog"),result);
    }

4.定制ForEach

不对Stream.spliterator进行包装的方法

public class CustomForEach {

    public static class Breaker{
        private 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(element -> {
                consumer.accept(element, breaker);
            });
        }
    }
}
   @Test
    public void whenCustomTakeWhileIsCalled_ThenCorrectItemsAreReturned2(){
        Stream<String> initialStream = Stream.of("cat", "dog", "elephant", "fox", "rabbit", "duck");
        List<String> result = new ArrayList<>();

        CustomForEach.forEach(initialStream,(element,breaker)->{
            if(element.length() % 2 == 0){
                breaker.stop();
            } else{
                result.add(element);
            }
        });

        assertEquals(asList("cat", "dog"),result);
    }
posted @ 2023-03-04 11:30  meta-treasure  阅读(711)  评论(0编辑  收藏  举报