Java 中的 RAII ......资源处理总是那么丑陋吗? [英] RAII in Java... is resource disposal always so ugly?

查看:15
本文介绍了Java 中的 RAII ......资源处理总是那么丑陋吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚玩过Java文件系统API,得到了以下函数,用于复制二进制文件.原始来源来自 Web,但我添加了 try/catch/finally 子句以确保如果发生错误,缓冲流将在退出函数之前关闭(从而释放我的操作系统资源).

I just played with Java file system API, and came down with the following function, used to copy binary files. The original source came from the Web, but I added try/catch/finally clauses to be sure that, should something wrong happen, the Buffer Streams would be closed (and thus, my OS ressources freed) before quiting the function.

我修剪了函数以显示模式:

I trimmed down the function to show the pattern:

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
   }
}

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

As far as I understand it, I cannot put the two close() in the finally clause because the first close() could well throw, and then, the second would not be executed.

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

I know C# has the Dispose pattern that would have handled this with the using keyword.

我什至更清楚 C++ 代码应该是这样的(使用类似 Java 的 API):

I even know better a C++ code would have been something like (using a Java-like 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
}

我遗漏了什么,还是我真的必须在 Java 中生成丑陋和臃肿的代码来处理缓冲流的 close() 方法中的异常?

I am missing something, or do I really have to produce ugly and bloated code in Java just to handle exceptions in the close() method of a Buffered Stream?

(请告诉我我哪里错了...)

(Please, tell me I'm wrong somewhere...)

是我,还是在更新此页面时,我看到问题和所有答案都在几分钟内减少了一个点?有人在保持匿名的同时过分享受自己吗?

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

EDIT 2: McDowell offered a very interesting link I felt I had to mention here: http://illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of-stream.html

编辑 3:按照 McDowell 的链接,我偶然发现了一个类似于 C# 模式的 Java 7 提案,使用模式:http://tech.puredanger.com/java7/#resourceblock.我的问题得到了明确的描述.显然,即使使用 Java 7 do,问题仍然存在.

EDIT 3: Following McDowell's link, I tumbled upon a proposal for Java 7 of a pattern similar to the C# using pattern: http://tech.puredanger.com/java7/#resourceblock . My problem is explicitly described. Apparently, even with the Java 7 do, the problems remain.

推荐答案

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

The try/finally pattern is the correct way to handle streams in most cases for Java 6 and lower.

有些人提倡静默关闭流.由于以下原因,请小心执行此操作:Java:如何不把流处理弄得一团糟

Java 7 引入了try-with-resources:

Java 7 introduces 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);
        }
    }
}

AutoCloseable 类型将自动关闭:

AutoCloseable types will be automatically closed:

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()) {}
  }
}

这篇关于Java 中的 RAII ......资源处理总是那么丑陋吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆