看看下面的代码片段,它试图将字符串列表转换为类对象列表:
public static List<Class<?>> f1(String... strings) {
return
Stream.of(strings)
.map(s -> {
try {
return Class.forName(s);
}
catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
}
return null;
})
.collect(Collectors.toList());
}
由于 Java 处理流中已检查异常的方式(已详细讨论 here - 我也公然从中窃取了我的示例片段),您必须在 try-catch block 之后有额外的 return 语句。这将导致将不需要的空引用添加到 List
为了避免这种额外的空引用,我提出了以下函数,使用普通的旧过程循环获得了更好的结果:
public static List<Class<?>> f2(String... strings) {
List<Class<?>> classes = new ArrayList<>();
for (String s : strings) {
try {
classes.add(Class.forName(s));
}
catch (ClassNotFoundException e) {
// Handle exception here
}
}
return classes;
}
这个观察是否允许我以最佳实践建议的形式得出结论,可以像下面这样表达?
如果您需要调用一个在流中抛出异常的函数并且您不能使用 stream.parallel()
,最好使用循环,因为:
无论如何,您都需要 try-catch block (尽管涉及在上述讨论中提供的抛出函数周围的某种包装器的棘手解决方案)
你的代码不会不够简洁(主要是因为1.)
如果出现异常,您的循环不会中断
你怎么看?
最佳答案
您可以在不引入必须在后续步骤中过滤的元素的情况下执行此操作:
public static List<Class<?>> f1(String... strings) {
return Arrays.stream(strings)
.flatMap(s -> {
try { return Stream.of(Class.forName(s)); }
catch(ClassNotFoundException e) { return null; }
})
.collect(Collectors.toList());
}
不过,这并不比循环解决方案更简洁。
但需要注意的是,这与checked exceptions无关。您希望在异常(exception)情况下继续,忽略失败的元素。 始终 要求您捕获
异常以实现此替代行为(默认情况下是将异常传播给调用者),无论异常是已检查还是未检查。已勾选的案例具有提醒您必须执行此操作的优点。
换句话说,Stream API 不允许您以简单的方式实现将检查异常传播给调用者的行为,但这无论如何不是您想要的。如果 Class.forName(String)
被设计为仅抛出未经检查的异常,则在 map
中省略 try … catch
block 将导致整个操作在异常情况下通过将异常转发给调用者来中止。但是,如前所述,这不是您想要的。
关于java - 如何以简洁的方式收集抛出异常的 Java 流操作的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49537265/