如何处理 Iterable.forEach 中的 IOException?
Posted
技术标签:
【中文标题】如何处理 Iterable.forEach 中的 IOException?【英文标题】:How to handle IOException in Iterable.forEach? 【发布时间】:2015-07-03 13:35:18 【问题描述】:我正在尝试将一组对象写入文件的方法。为什么下面使用 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 和 Iterable 文档,但似乎都没有建议如何解决这个问题。
【问题讨论】:
可以通过命令行编译吗?什么版本的eclipse? 【参考方案1】:前身:The Catch or Specify Requirement.
让我们把 lambda 写成一个匿名类:
objects.forEach(new Consumer<Object>()
public void accept(Object o)
bw.write(o.toString());
);
我们正在处理它吗?很明显我们不是。
当我们编写一个 lambda 表达式时,我们是在声明一个方法的主体。我们也不能为 lambda 声明 throws
子句。
唯一的“解决方法”是执行以下操作:
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 的主体中捕获并处理异常。
【讨论】:
这就是我想要的。谢谢!【参考方案2】:如果您只关心将字符串打印到文件中,请使用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
【讨论】:
【参考方案3】:问题是接口Consumer
中的方法accept
没有声明抛出异常。因此,您不能使用在 lambda 中引发检查异常的方法。
解决方案是使用 for each 循环。
【讨论】:
唉,这是当前 lambda 实现的缺点之一,我不止一次地撞到我的头! :)【参考方案4】:如果发生任何异常,我们通常不会将数据写入文件。记住这一点,我们可以写我们的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 中的 IOException?的主要内容,如果未能解决你的问题,请参考以下文章