当前位置: 首页 > 知识库问答 >
问题:

Java 8流中的聚合运行时异常

施宏大
2023-03-14

假设我有一个抛出运行时异常的方法。我正在使用对列表中的项调用此方法。

class ABC {

    public void doStuff(MyObject myObj) {
        if (...) {
            throw new IllegalStateException("Fire! Fear! Foes! Awake!");
        }
        // do stuff...
    }

    public void doStuffOnList(List<MyObject> myObjs) {
        try {
            myObjs.stream().forEach(ABC:doStuff);
        } catch(AggregateRuntimeException??? are) {
            ...
        }             
    }
}

现在我希望列表中的所有项目都被处理,并且单个项目上的任何运行时异常都被收集到一个“聚合”运行时异常中,该异常将在最后抛出。

在我的真实代码中,我正在进行第三方API调用,这可能会引发运行时异常。我想确保所有项目都得到处理,并且在最后报告任何错误。

我可以想出一些方法来解决这个问题,比如一个map()函数,它捕获并返回异常(... shudder...)。但是有没有一种原生的方法来做到这一点呢?如果没有,有没有另一种干净利落的实现方式?

共有3个答案

白星海
2023-03-14

下面是关于映射到异常主题的一个变体。

从现有的doStuff方法开始。请注意,这符合功能接口<代码>消费者

public void doStuff(MyObject myObj) {
    if (...) {
        throw new IllegalStateException("Fire! Fear! Foes! Awake!");
    }
    // do stuff...
}

现在编写一个高阶函数来包装它,并将其转换为一个可能返回或不返回异常的函数。我们想从平面地图中调用它,所以“可能或可能不”的表达方式是返回一个包含异常或空流的流。我将在这里使用RuntimeExcue作为异常类型,当然它可以是任何类型。事实上,使用这种带有检查异常的技术可能是有用的。)

<T> Function<T,Stream<RuntimeException>> ex(Consumer<T> cons) {
    return t -> {
        try {
            cons.accept(t);
            return Stream.empty();
        } catch (RuntimeException re) {
            return Stream.of(re);
        }
    };
}

现在重写doStuffOnList在流中使用它:

void doStuffOnList(List<MyObject> myObjs) {
    List<RuntimeException> exs =
        myObjs.stream()
              .flatMap(ex(this::doStuff))
              .collect(Collectors.toList());
    System.out.println("Exceptions: " + exs);
}
蒋原
2023-03-14

已经有了一些Trymonad for Java的实现。例如,我找到了更好的java8-monads库。使用它,你可以用下面的风格写作。

假设要映射值并跟踪所有异常:

public String doStuff(String s) {
    if(s.startsWith("a")) {
        throw new IllegalArgumentException("Incorrect string: "+s);
    }
    return s.trim();
}

让我们有一些输入:

List<String> input = Arrays.asList("aaa", "b", "abc  ", "  qqq  ");

现在,我们可以将它们映射到成功的尝试并传递给您的方法,然后分别收集成功处理的数据和失败:

Map<Boolean, List<Try<String>>> result = input.stream()
        .map(Try::successful).map(t -> t.map(this::doStuff))
        .collect(Collectors.partitioningBy(Try::isSuccess));

之后,您可以处理成功的条目:

System.out.println(result.get(true).stream()
    .map(t -> t.orElse(null)).collect(Collectors.joining(",")));

做一些有例外的事情:

result.get(false).stream().forEach(t -> t.onFailure(System.out::println));

输出为:

b,qqq
java.lang.IllegalArgumentException: Incorrect string: aaa
java.lang.IllegalArgumentException: Incorrect string: abc  

我个人不喜欢这个库是如何设计的,但可能它会适合你。

下面是一个完整示例的要点。

闾丘选
2023-03-14

在这种简单的情况下,doStuff方法是void,您只关心例外情况,您可以保持简单:

myObjs.stream()
    .flatMap(o -> {
        try {
            ABC.doStuff(o);
            return null;
        } catch (RuntimeException ex) {
            return Stream.of(ex);
        }
    })
    // now a stream of thrown exceptions.
    // can collect them to list or reduce into one exception
    .reduce((ex1, ex2) -> {
        ex1.addSuppressed(ex2);
        return ex1;
    }).ifPresent(ex -> {
        throw ex;
    });

然而,如果您的需求更复杂,并且您更喜欢使用标准库,完全未来可以用来表示成功或失败(尽管有一些缺点):

public static void doStuffOnList(List<MyObject> myObjs) {
    myObjs.stream()
            .flatMap(o -> completedFuture(o)
                    .thenAccept(ABC::doStuff)
                    .handle((x, ex) -> ex != null ? Stream.of(ex) : null)
                    .join()
            ).reduce((ex1, ex2) -> {
                ex1.addSuppressed(ex2);
                return ex1;
            }).ifPresent(ex -> {
                throw new RuntimeException(ex);
            });
}
 类似资料:
  • 问题内容: 假设我有一个抛出运行时异常的方法。我正在使用a 来对列表中的项目调用此方法。 现在,我希望处理列表中的所有项目,并将单个项目上的所有运行时异常收集到“聚合”运行时异常中,该异常将在最后抛出。 在我的真实代码中,我正在进行第三方API调用,这可能会引发运行时异常。我想确保所有项目都已处理,并在最后报告所有错误。 我可以想到几种破解方法,例如捕获并返回异常的函数( ..shudder ..

  • 假设我有一张房间清单 每个房间都有一份人员名单。 使用java8 streams,我想迭代房间列表,获取所有人员,在每个节点上执行一些方法(doSomething()),并获取所有过滤对象的列表。 这是使用java 8的最佳实践吗?

  • 给java类一些东西 我有一张物品清单 我希望能够对它们进行排序,这样它们就可以按照每个父对象的虚数的累积和排序,然后再按照虚数排序。 所以我最终 我知道用parentKey和sum of noThings映射它是 我想,也许包装我的Something类并获得每个父项的总密钥可能会在某种程度上起作用。 但看起来工作量很大,不太优雅。 如有任何意见/想法,将不胜感激。

  • 我一直在尝试在聚集中添加超时,以避免等待每个流都完成。但是当我添加超时时,它不起作用,因为聚合器等待每个流完成。 E、 在我的流中,其中一个有2秒的延迟,另一个有4秒的延迟 我使用遗嘱执行人。newCachedThreadPool()以并行运行。我想释放包含的每条消息,直到超时完成 我一直在测试的另一种方法是使用默认的gatherer,并在scatterGather中设置GathereTimeou

  • Java 8并行流在consuming子句中抛出异常时如何表现,例如在处理中?例如,以下代码: 它是否立即停止处理的元素?它是否等待已启动的元素完成?它是否等待所有的流完成?它是否在抛出异常后开始处理流元素? 什么时候回来?在异常之后立即?消费者处理完所有/部分元素后? 在并行流引发异常后,是否继续处理元素?(找到了发生这种情况的案例)。 这里有一般规则吗? 编辑(15-11-2016) 试图确定

  • 你能让我知道如何在新的api中使用与数据流运行器的聚合器吗。?