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

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

问题描述

我刚刚玩过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)//可以抛出一个IOException
{
oDBuffer.write(c); //可以抛出一个IOException
}
}
finally
{
oDBuffer.close(); //可以抛出一个IOException
}
}
finally
{
oSBuffer.close(); //可以抛出一个IOException
}
}

据我所知因为第一个 close()可以抛出,我不能把两个 close()然后,第二个将不会被执行。



我知道C#有使用<$ c $处理这种情况的 Dispose 模式c>使用关键字。



我甚至知道更好的C ++代码将会像(使用Java类API): p>

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

int c;

while((c = oSBuffer.read())!= -1)//可以抛出一个IOException
{
oDBuffer.write(c); //可以抛出一个IOException
}

//我不关心资源,因为RAII处理它们为
}

我错过了一些东西,或者我真的要在Java中产生丑陋和blo肿的代码,只是为了处理 close中的异常()缓冲流的方法



(请告诉我我在某个地方出错...)



编辑:是我,还是更新这个页面,我看到问题和所有的答案在几分钟内下降了一点?是否有人在匿名的同时享受自己?



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



编辑3:在McDowell的链接之后,我发现Java 7的一个模式类似于C#使用模式: http://tech.puredanger.com/java7/#resourceblock 。我的问题被明确描述。显然,即使Java 7 ,仍然存在问题。

解决方案

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



有些主张默默关闭流。为此,请谨慎行事: Java:如何不让乱码流处理






Java 7引入 try-with-resources

  / **将文本文件从一个编码转码为另一个* / 
public static void transcode(文件源,Charset srcEncoding,
文件目标,Charset tgtEncoding)
throws IOException {
try(InputStream in = new FileInputStream(source);
Reader读者=新的InputStreamReader(in,srcEncoding);
OutputStream out = new FileOutputStream(target);
Writer writer = new OutputStreamWriter(out,tgtEncoding)){
char [] buffer = new炭[1024];
int r;
while((r = reader.read(buffer))!= -1){
writer.write(buffer,0,r);
}
}
}

自动关闭 类型将自动关闭:

  public class Foo {
public static void main(String [] args){
class CloseTest实现AutoCloseable {
public void close(){
System.out.println(Close);
}
}
try(CloseTest closeable = new CloseTest()){}
}
}


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

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.

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

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
}

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: Is it me, or when updating this page, I saw both the question and all the answers decreased by one point in a couple of minutes? Is someone enjoying himself too much while remaning anonymous?

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

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.

解决方案

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

Some are advocating silently closing streams. Be careful doing this for these reasons: Java: how not to make a mess of stream handling


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 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天全站免登陆