Java 为什么未处理的IOException会在stream.forEach()中触发,而不是在普通for循环中触发
未处理的Java 为什么未处理的IOException会在stream.forEach()中触发,而不是在普通for循环中触发,java,for-loop,foreach,java-8,ioexception,Java,For Loop,Foreach,Java 8,Ioexception,未处理的IOException在以下代码中触发: ZipOutputStream zos = new ZipOutputStream(outputStream); testIds.stream().forEach(testId->{ zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
IOException
在以下代码中触发:
ZipOutputStream zos = new ZipOutputStream(outputStream);
testIds.stream().forEach(testId->{
zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
zos.write(files.get(testId));
zos.closeEntry();
});
ZipOutputStream zos = new ZipOutputStream(new ByteArrayOutputStream());
for (Integer testId : testIds) {
zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
zos.write(files.get(testId));
zos.closeEntry();
}
但以下代码中的情况并非如此:
ZipOutputStream zos = new ZipOutputStream(outputStream);
testIds.stream().forEach(testId->{
zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
zos.write(files.get(testId));
zos.closeEntry();
});
ZipOutputStream zos = new ZipOutputStream(new ByteArrayOutputStream());
for (Integer testId : testIds) {
zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
zos.write(files.get(testId));
zos.closeEntry();
}
看起来您正在关闭循环中的流。第二次,流被关闭。看起来您正在关闭循环中的流。第二次,流关闭。它不是特定于
forEach
检查lambda主体中抛出的异常,而不检查lambda主体中抛出的异常。
15.27.3。Lambda表达式的类型 可在lambda主体中引发的已检查异常 表达式可能导致编译时错误,如§11.2.3所述 此时,您可以阅读: 11.2.3。异常检查 如果lambda主体可以引发一些异常,则这是一个编译时错误 类E,当E是一个已检查的异常类且E不是 目标函数类型的throws子句中声明的某个类 通过lambda表达式
foreach()
接受一个Consumer
,您可以看到中定义的accept()
没有声明任何异常:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
...
}
因此,编译很好,因为选中的异常已“处理”:您将抛出它。出于解释原因,同样的事情不适用于lambda。
作为解决方法,您有两种方法:
- 不使用流。你应该考虑这一点,因为它在你的用例 中没有很多附加值。
- 捕捉异常
ZipOutputStream zos = new ZipOutputStream(outputStream);
testIds.stream().forEach(testId->{
try{
zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
zos.write(files.get(testId));
zos.closeEntry();
} catch(IOException e) {
throw new RuntimeException(e)
}
}
关于第二点,由于不能从lambda主体抛出IOException
,因此必须使用catch
语句来处理它。如果异常应该传播到客户端,则可以重新抛出一个
RuntimeException
,该异常将实际异常包装为运行时异常,因为运行时异常与lambda正文中的已检查异常没有相同的限制:
ZipOutputStream zos = new ZipOutputStream(outputStream);
testIds.stream().forEach(testId->{
try{
zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
zos.write(files.get(testId));
zos.closeEntry();
}
catch(IOException e){
// log the exception
throw new RuntimeException(e);
// or throw a custom RuntimeException class if it makes more sense
}
});
它不特定于
forEach
检查lambda主体中抛出的异常,而不检查lambda主体中抛出的异常。
15.27.3。Lambda表达式的类型 可在lambda主体中引发的已检查异常 表达式可能导致编译时错误,如§11.2.3所述 此时,您可以阅读: 11.2.3。异常检查 如果lambda主体可以引发一些异常,则这是一个编译时错误 类E,当E是一个已检查的异常类且E不是 目标函数类型的throws子句中声明的某个类 通过lambda表达式
foreach()
接受一个Consumer
,您可以看到中定义的accept()
没有声明任何异常:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
...
}
因此,编译很好,因为选中的异常已“处理”:您将抛出它。出于解释原因,同样的事情不适用于lambda。
作为解决方法,您有两种方法:
- 不使用流。你应该考虑这一点,因为它在你的用例 中没有很多附加值。
- 捕捉异常
ZipOutputStream zos = new ZipOutputStream(outputStream);
testIds.stream().forEach(testId->{
try{
zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
zos.write(files.get(testId));
zos.closeEntry();
} catch(IOException e) {
throw new RuntimeException(e)
}
}
关于第二点,由于不能从lambda主体抛出IOException
,因此必须使用catch
语句来处理它。如果异常应该传播到客户端,则可以重新抛出一个
RuntimeException
,该异常将实际异常包装为运行时异常,因为运行时异常与lambda正文中的已检查异常没有相同的限制:
ZipOutputStream zos = new ZipOutputStream(outputStream);
testIds.stream().forEach(testId->{
try{
zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
zos.write(files.get(testId));
zos.closeEntry();
}
catch(IOException e){
// log the exception
throw new RuntimeException(e);
// or throw a custom RuntimeException class if it makes more sense
}
});
这是因为
.forEach()
(消费者
)中使用的接口中的方法签名没有声明引发异常
ZipOutputStream zos = new ZipOutputStream(outputStream);
testIds.stream().forEach(testId->{
try{
zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
zos.write(files.get(testId));
zos.closeEntry();
} catch(IOException e) {
throw new RuntimeException(e)
}
}
签名如下所示:
public interface Consumer<T> {
void accept(T t); // <-- no throws declaration
}
public void method() throws IOException{ // <-- throws declaration here
ZipOutputStream zos = new ZipOutputStream(new ByteArrayOutputStream());
for (Integer testId : testIds) {
zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
zos.write(files.get(testId));
zos.closeEntry();
}
}
公共接口使用者{
void accept(T);//这是因为.forEach()
(消费者
)中使用的接口的方法签名没有声明引发异常
ZipOutputStream zos = new ZipOutputStream(outputStream);
testIds.stream().forEach(testId->{
try{
zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
zos.write(files.get(testId));
zos.closeEntry();
} catch(IOException e) {
throw new RuntimeException(e)
}
}
签名如下所示:
public interface Consumer<T> {
void accept(T t); // <-- no throws declaration
}
public void method() throws IOException{ // <-- throws declaration here
ZipOutputStream zos = new ZipOutputStream(new ByteArrayOutputStream());
for (Integer testId : testIds) {
zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
zos.write(files.get(testId));
zos.closeEntry();
}
}
公共接口使用者{
void accept(T);//异常将从lambda内抛出,这意味着lambda的调用方需要捕获/检查异常。我假设您的代码段外有一个try catch
或throws
子句
由于forEach
没有为您检查异常,因此IOException
未处理。您必须处理它。最简单的方法是捕获异常并将其包装(例如在运行时异常中)
异常将从lambda内抛出,这意味着lambda的调用方需要捕获/检查异常。我假设您的代码段外有try-catch
或throws
子句
由于forEach
没有为您检查异常,因此IOException
未处理。您必须处理它。最简单的方法是捕获异常并将其包装(例如在运行时异常中)
两个代码段在未处理的异常方面都有相同的问题。@Tom为您附上屏幕截图。即使屏幕截图也不包含明显重要的方法头。在屏幕截图中,您可以清楚地看到stream.forEach代码段出现编译时错误,但其他代码段的情况不同。是的,正如我所说的方法头抛出s例外。不,你没有说过。无论是在问题中,在问题的编辑中,还是在这个问题下的评论中。这两个代码段对于未处理的例外都有相同的问题。@Tom为你附上屏幕截图。甚至屏幕截图也没有包含明显重要的方法标题。在屏幕截图中,你可以清楚地看到这一点stream.forEach代码段给出了编译时错误,但与其他代码段的情况不同。是的,正如我所说的,方法头抛出异常。不,您没有说过。在问题中,在