如何在Java 8 Stream.flatMap(..)中捕获异常

时间:2019-01-08 16:40:35

标签: java exception java-8 java-stream

给定一个Stream和一个为不同的参数返回Stream作为数据源的方法,我正在寻找一种通过flatMap(..)合并流并捕获某些{{ 1}}。

让我们看下面的代码片段:

Exceptions

是否有任何方法可以捕获由public class FlatMap { public static void main(final String[] args) { long count; // this might throw an exception count = Stream.of(0.2, 0.5, 0.99).flatMap(chance -> getGenerator(chance, 20)).count(); // trying to catch the exception in flatMap() will not work count = Stream.of(0.2, 0.5, 0.99).flatMap(chance -> { try { return getGenerator(chance, 20); } catch (final NullPointerException e) { return Stream.empty(); } }).count(); System.out.println(count); } // !! we cannot change this method, we simply get a Stream static Stream<Object> getGenerator(final double chance, final long limit) { return Stream.generate(() -> { if (Math.random() < chance) return new Object(); throw new NullPointerException(); }).limit(limit); } } 创建的每个单独Stream的异常,并简单地抑制getGenerator(..),将“损坏的” Exception替换为是空的还是跳过特定生成器Stream中的那些元素?

3 个答案:

答案 0 :(得分:2)

可以使用StreamSpliterator包装到另一个。此方法通过捕获Stream并保存此状态来保护给定的Exception

    static <T> Stream<T> protect(final Stream<T> stream) {
        final Spliterator<T> spliterator = stream.spliterator();
        return StreamSupport.stream(
                new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE,
                           spliterator.characteristics() & ~Spliterator.SIZED) {

                    private boolean corrupted = false;

                    @Override
                    public boolean tryAdvance(final Consumer<? super T> action) {
                        if (!corrupted) try {
                            return spliterator.tryAdvance(action);
                        } catch (final Exception e) {
                            // we suppress this one, stream ends here
                            corrupted = true;
                        }
                        return false;
                    }
                }, false);
    }

然后,我们可以包装Stream方法并安全地将其传递到flatMap(..)中:

// we protect the stream by a wrapper Stream
count = Stream.of(0.2, 0.5, 0.99)
              .flatMap(chance -> protect(getGenerator(chance, 20)))
              .count();

答案 1 :(得分:2)

一种解决方法是强制由Stream创建的getGeneratorflatMap方法实现中进行评估。这迫使NullPointerException被抛出到try-catch块中,因此可以被处理。

为此,您可以collect Stream(例如List):

getGenerator(chance, 20).collect(Collectors.toList()).stream()

将其合并到您的原始代码段中:

public class FlatMap {

    public static void main(final String[] args) {
        long count;

        // trying to catch the exception in flatMap() will not work
        count = Stream.of(0.2, 0.5, 0.99)
            .flatMap(chance -> {
                try {
                    return getGenerator(chance, 20).collect(Collectors.toList()).stream();
                } 
                catch (final NullPointerException e) {
                    return Stream.empty();
                }
            })
            .count();

        System.out.println(count);
    }

    // !! we cannot change this method, we simply get a Stream
    static Stream<Object> getGenerator(final double chance, final long limit) {
        return Stream.generate(() -> {
            if (Math.random() < chance) return new Object();
            throw new NullPointerException();
        }).limit(limit);
    }
}

警告:如果getGenerator Stream可以更好地进行惰性评估,则此方法可能会降低性能。

答案 2 :(得分:0)

尝试一下:

static <T> Supplier<T> getOrNull(Supplier<T> supplier) {
    return () -> {
        try {
            return supplier.get();
        } catch (Throwable e) {
            return null;
        }
    };
}

static Stream<Object> getGenerator(final double chance, final long limit) {
    return Stream.generate(
                      getOrNull(
                          () -> {
                              if (Math.random() < chance) return new Object();
                              throw new NullPointerException(); 
                              // You can throw any exception here
                          })) 
                .limit(limit)
                .filter(Objects::isNull);
}

然后只需调用getGenerator

count = Stream.of(0.2, 0.5, 0.99)
              .flatMap(chance -> getGenerator(chance, 20))
              .count();
相关问题