如何处理 Iterable.forEach 中的 IOException?
How to handle IOException in Iterable.forEach?
我正在研究将一组对象写入文件的方法。为什么以下使用 Iterable.forEach() 的实现无法编译?在 Eclipse 中,我收到一条消息,指出未处理 IOException。这特别令人困惑,因为我似乎确实在处理 IOExceptions。
public void write(Iterable<?> objects) {
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("out.txt"), "UTF-8"));) {
objects.forEach((o) -> bw.write(o.toString())); //Unhandled exception type IOException
} catch (IOException e) {
//handle exception
}
}
显然,下面的方法有效。我对为什么上述方法不起作用以及如何解决它很感兴趣。
for (Object o : objects) { bw.write(o.toString()); }
问题是接口Consumer
中的方法accept
没有声明抛出异常。因此,您不能使用在 lambda 中抛出已检查异常的方法。
解决方案是改为使用 for each 循环。
先行者:The Catch or Specify Requirement.
让我们将 lambda 写成匿名的 class:
objects.forEach(new Consumer<Object>() {
public void accept(Object o) {
bw.write(o.toString());
}
});
我们在处理吗?应该清楚我们不是。
当我们写一个 lambda 表达式时,我们是在声明一个方法的主体。我们也不能为 lambda 声明 throws
子句。
唯一的 "way around it" 是做如下的事情:
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("out.txt"), "UTF-8"));) {
objects.forEach((o) -> {
try {
bw.write(o.toString()));
} catch(IOException kludgy) {
throw new UncheckedIOException(kludgy);
}
});
} catch (UncheckedIOException kludgy) {
IOException cause = kludgy.getCause();
// handle exception
}
(另见 UncheckedIOException
。)
Iterable.forEach
保证像该示例中那样包装和抛出异常:
Exceptions thrown by the action are relayed to the caller.
但是,最好避免在抛出已检查异常的上下文中使用 forEach
,或者在 lambda 主体中捕获并处理异常。
如果您只关心将字符串打印到文件中,请使用 PrintStream
或 PrintWriter
而不是其他 Writer
类。 PrintStream
和 PrintWriter
的显着特点是它们的打印操作不会抛出 IOException
。他们还自动调用对象上的 toString
,这让事情变得非常方便:
public void write1(Iterable<?> objects) {
try (PrintStream ps = new PrintStream("printout.txt", "UTF-8")) {
objects.forEach(ps::println);
} catch (IOException ioe) {
// handle
}
}
如果您担心错误,您可以调用 PrintStream.checkError
,尽管这不会告诉您有关可能发生的任何错误的任何细节。
不过,普遍的问题仍然存在,如果您想从不允许它的上下文(例如 forEach
)中调用抛出异常的方法,该怎么办。这只是烦人的处理,尽管只是适度的。但是,它确实需要一些设置。假设我们想写一个 Consumer
抛出 IOException
。我们必须声明我们自己的功能接口:
interface IOConsumer<T> {
void accept(T t) throws IOException;
}
现在我们需要编写一个函数,将 IOConsumer
转换为 Consumer
。它通过将它捕获的任何 IOException
转换为一个 UncheckedIOException
,一个为此目的创建的异常来做到这一点。
static <T> Consumer<T> wrap(IOConsumer<? super T> ioc) {
return t -> {
try {
ioc.accept(t);
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
};
}
有了这些,我们现在可以重写原来的例子如下:
public void write2(Iterable<?> objects) {
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("out.txt"), "UTF-8"))) {
objects.forEach(wrap(o -> bw.write(o.toString())));
} catch (IOException|UncheckedIOException e) {
//handle exception
}
}
一般情况下,如果出现任何异常,我们不会将数据写入文件。牢记这一点,我们可以写 own consumer which will wrap the checked exception into an unchecked exception
。这样你就可以摆脱编译时错误。
请尝试下面的代码
import java.io.*;
import java.util.*;
public class HelloWorld{
public static void main(String []args){
write(Arrays.asList(1,2,3));
}
public static void write(Iterable<?> objects) {
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("c:\out.txt"), "UTF-8"))) {
objects.forEach(o->myConsumerThrowsRuntimeException(bw,o.toString())); //Unhandled exception type IOException
} catch (Exception e) {
//handle exception
}
}
public static void myConsumerThrowsRuntimeException(Writer writer , String data){
try{
writer.write(data);
}catch(IOException e){
throw new RuntimeException("Cannot write Data error is "+e.getMessage());
}
}
}
我正在研究将一组对象写入文件的方法。为什么以下使用 Iterable.forEach() 的实现无法编译?在 Eclipse 中,我收到一条消息,指出未处理 IOException。这特别令人困惑,因为我似乎确实在处理 IOExceptions。
public void write(Iterable<?> objects) {
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("out.txt"), "UTF-8"));) {
objects.forEach((o) -> bw.write(o.toString())); //Unhandled exception type IOException
} catch (IOException e) {
//handle exception
}
}
显然,下面的方法有效。我对为什么上述方法不起作用以及如何解决它很感兴趣。
for (Object o : objects) { bw.write(o.toString()); }
问题是接口Consumer
中的方法accept
没有声明抛出异常。因此,您不能使用在 lambda 中抛出已检查异常的方法。
解决方案是改为使用 for each 循环。
先行者:The Catch or Specify Requirement.
让我们将 lambda 写成匿名的 class:
objects.forEach(new Consumer<Object>() {
public void accept(Object o) {
bw.write(o.toString());
}
});
我们在处理吗?应该清楚我们不是。
当我们写一个 lambda 表达式时,我们是在声明一个方法的主体。我们也不能为 lambda 声明 throws
子句。
唯一的 "way around it" 是做如下的事情:
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("out.txt"), "UTF-8"));) {
objects.forEach((o) -> {
try {
bw.write(o.toString()));
} catch(IOException kludgy) {
throw new UncheckedIOException(kludgy);
}
});
} catch (UncheckedIOException kludgy) {
IOException cause = kludgy.getCause();
// handle exception
}
(另见 UncheckedIOException
。)
Iterable.forEach
保证像该示例中那样包装和抛出异常:
Exceptions thrown by the action are relayed to the caller.
但是,最好避免在抛出已检查异常的上下文中使用 forEach
,或者在 lambda 主体中捕获并处理异常。
如果您只关心将字符串打印到文件中,请使用 PrintStream
或 PrintWriter
而不是其他 Writer
类。 PrintStream
和 PrintWriter
的显着特点是它们的打印操作不会抛出 IOException
。他们还自动调用对象上的 toString
,这让事情变得非常方便:
public void write1(Iterable<?> objects) {
try (PrintStream ps = new PrintStream("printout.txt", "UTF-8")) {
objects.forEach(ps::println);
} catch (IOException ioe) {
// handle
}
}
如果您担心错误,您可以调用 PrintStream.checkError
,尽管这不会告诉您有关可能发生的任何错误的任何细节。
不过,普遍的问题仍然存在,如果您想从不允许它的上下文(例如 forEach
)中调用抛出异常的方法,该怎么办。这只是烦人的处理,尽管只是适度的。但是,它确实需要一些设置。假设我们想写一个 Consumer
抛出 IOException
。我们必须声明我们自己的功能接口:
interface IOConsumer<T> {
void accept(T t) throws IOException;
}
现在我们需要编写一个函数,将 IOConsumer
转换为 Consumer
。它通过将它捕获的任何 IOException
转换为一个 UncheckedIOException
,一个为此目的创建的异常来做到这一点。
static <T> Consumer<T> wrap(IOConsumer<? super T> ioc) {
return t -> {
try {
ioc.accept(t);
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
};
}
有了这些,我们现在可以重写原来的例子如下:
public void write2(Iterable<?> objects) {
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("out.txt"), "UTF-8"))) {
objects.forEach(wrap(o -> bw.write(o.toString())));
} catch (IOException|UncheckedIOException e) {
//handle exception
}
}
一般情况下,如果出现任何异常,我们不会将数据写入文件。牢记这一点,我们可以写 own consumer which will wrap the checked exception into an unchecked exception
。这样你就可以摆脱编译时错误。
请尝试下面的代码
import java.io.*;
import java.util.*;
public class HelloWorld{
public static void main(String []args){
write(Arrays.asList(1,2,3));
}
public static void write(Iterable<?> objects) {
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("c:\out.txt"), "UTF-8"))) {
objects.forEach(o->myConsumerThrowsRuntimeException(bw,o.toString())); //Unhandled exception type IOException
} catch (Exception e) {
//handle exception
}
}
public static void myConsumerThrowsRuntimeException(Writer writer , String data){
try{
writer.write(data);
}catch(IOException e){
throw new RuntimeException("Cannot write Data error is "+e.getMessage());
}
}
}