我正在玩弄将一组对象写入文件的方法。为什么使用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()); }
答案 0 :(得分:10)
前体:The Catch or Specify Requirement。
让我们将lambda写为匿名类:
objects.forEach(new Consumer<Object>() {
public void accept(Object o) {
bw.write(o.toString());
}
});
我们正在处理吗?应该很清楚,我们不是。
当我们写一个lambda表达式时,我们正在声明一个方法的主体。我们也不能为lambda声明throws
子句。
围绕它的唯一方式&#34;将做类似以下的事情:
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
保证在该示例中包装和抛出异常有效:
操作引发的异常被转发给调用者。
但是,最好避免在抛出已检查异常的上下文中使用forEach
,或者在lambda主体中捕获并处理异常。
答案 1 :(得分:6)
如果您只关心将字符串打印到文件,请使用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
的{{1}}。我们必须声明我们自己的功能接口:
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);
}
};
}
答案 2 :(得分:2)
问题是接口accept
中的方法Consumer
未声明为抛出异常。因此,您不能使用在lambda中抛出已检查异常的方法。
解决方案是使用a代替每个循环。
答案 3 :(得分:1)
一般情况下,如果发生任何异常,我们不会将数据写入文件。牢记这一点,我们可以写下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());
}
}
}