Java中的RAII ......资源处理总是那么难看?

pae*_*bal 15 java design-patterns raii resource-management

我刚刚玩了Java文件系统API,并提供了以下函数,用于复制二进制文件.最初的源代码来自Web,但我添加了try/catch/finally子句,以确保在出现错误之前,在退出函数之前缓冲流将被关闭(因此,我的操作系统资源被释放).

我减少了功能以显示模式:

public static void copyFile(FileOutputStream oDStream, FileInputStream oSStream) throw etc...
{
   BufferedInputStream oSBuffer = new BufferedInputStream(oSStream, 4096);
   BufferedOutputStream oDBuffer = new BufferedOutputStream(oDStream, 4096);

   try
   { 
      try
      { 
         int c;

         while((c = oSBuffer.read()) != -1)  // could throw a IOException
         {
            oDBuffer.write(c);  // could throw a IOException
         }
      }
      finally
      {
         oDBuffer.close(); // could throw a IOException
      }
   }
   finally
   {
      oSBuffer.close(); // could throw a IOException
   }
}
Run Code Online (Sandbox Code Playgroud)

据我所知,我不能把这两个close()放在finally子句中,因为第一个close()可以抛出,然后,第二个不会被执行.

我知道C#有Dispose模式,可以使用using关键字来处理这个问题.

我甚至知道更好的C++代码(使用类似Java的API):

void copyFile(FileOutputStream & oDStream, FileInputStream & oSStream)
{
   BufferedInputStream oSBuffer(oSStream, 4096);
   BufferedOutputStream oDBuffer(oDStream, 4096);

   int c;

   while((c = oSBuffer.read()) != -1)  // could throw a IOException
   {
      oDBuffer.write(c);  // could throw a IOException
   }

   // I don't care about resources, as RAII handle them for me
}
Run Code Online (Sandbox Code Playgroud)

我缺少一些东西,或者我是否真的必须在Java中生成丑陋和臃肿的代码才能处理close()缓冲流方法中的异常?

(请告诉我,我错了...)

编辑:是我,还是在更新此页面时,我看到问题和所有答案在几分钟内减少了一分?有人在享受匿名的同时享受太多自己吗?

编辑2:McDowell提供了一个非常有趣的链接,我觉得我必须在这里提到:http: //illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of-stream.html

编辑3:在麦克道尔的链接之后,我向Java 7提出了类似于使用模式的模式的建议:http://tech.puredanger.com/java7/#resourceblock.我明确地描述了我的问题.显然,即使使用Java 7 do,问题仍然存在.

McD*_*ell 18

在大多数情况下,try/finally模式是处理Java 6及更低版本的流的正确方法.

有些人主张默默关闭流.由于以下原因,请小心这样做: Java:如何不弄乱流处理


Java 7引入了try-with-resources:

/** transcodes text file from one encoding to another */
public static void transcode(File source, Charset srcEncoding,
                             File target, Charset tgtEncoding)
                                                             throws IOException {
    try (InputStream in = new FileInputStream(source);
         Reader reader = new InputStreamReader(in, srcEncoding);
         OutputStream out = new FileOutputStream(target);
         Writer writer = new OutputStreamWriter(out, tgtEncoding)) {
        char[] buffer = new char[1024];
        int r;
        while ((r = reader.read(buffer)) != -1) {
            writer.write(buffer, 0, r);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

AutoCloseable 类型将自动关闭:

public class Foo {
  public static void main(String[] args) {
    class CloseTest implements AutoCloseable {
      public void close() {
        System.out.println("Close");
      }
    }
    try (CloseTest closeable = new CloseTest()) {}
  }
}
Run Code Online (Sandbox Code Playgroud)