假设我有一个抛出运行时异常的方法。我使用Stream对列表中的项调用此方法。
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.)。但有本土化的方法吗?如果没有,是否有其他方法干净地实现它?
发布于 2015-05-08 07:24:13
在这种简单的情况下,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;
});但是,如果您的需求更复杂,并且您更喜欢使用标准库,那么CompletableFuture可以用来表示“成功或失败”(尽管有一些缺陷):
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);
});
}发布于 2015-05-08 07:08:17
Java已经有了一些实现。例如,我找到了更好-java8-monad库。使用它,您可以使用以下样式编写。
假设您想要映射您的值并跟踪所有异常:
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 我个人不喜欢这个库是如何设计的,但它可能会适合你。
下面是一个完整示例的要旨。
发布于 2015-05-08 07:05:29
这是一个关于映射到异常的主题的变化。
从您现有的doStuff方法开始。注意,这符合函数接口Consumer<MyObject>。
public void doStuff(MyObject myObj) {
if (...) {
throw new IllegalStateException("Fire! Fear! Foes! Awake!");
}
// do stuff...
}现在编写一个高阶函数,将其包装起来,并将其转换为一个函数,该函数可能返回或不返回异常。我们希望从flatMap中调用它,所以表示“可能或不可能”的方式是返回包含异常或空流的流。这里我将使用RuntimeException作为异常类型,但当然可以是任何类型。(实际上,在检查异常的情况下使用此技术可能是有用的。)
<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);
}https://stackoverflow.com/questions/30117134
复制相似问题