如何处理 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】:

如果您只关心将字符串打印到文件中,请使用PrintStreamPrintWriter 而不是其他Writer 类。 PrintStreamPrintWriter 的显着特点是它们的打印操作不会抛出 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?的主要内容,如果未能解决你的问题,请参考以下文章

如何处理片段和活动中的后压

[转]如何处理机器学习中的不平衡类别

如何处理 REST api 中的关系

如何处理iphone中的关键事件

如何处理mio中的错误?

如何处理 RecyclerView 中的可变高度图像?