这是在Java中释放资源的安全方法吗?

这是在Java中释放资源的安全方法吗?,java,Java,通常,当代码需要一些需要发布的资源时,我会这样做: InputStream in = null; try{ in = new FileInputStream("myfile.txt"); doSomethingWithStream(in); }finally{ if(in != null){ in.close(); } } 我不喜欢的是,您必须将变量初始化为null,然后将其设置为另一个值,并在finally块中通过检查是否为null来检查资源是

通常,当代码需要一些需要发布的资源时,我会这样做:

InputStream in = null;
try{
    in = new FileInputStream("myfile.txt");
    doSomethingWithStream(in);
}finally{
    if(in != null){
        in.close();
    }
}
我不喜欢的是,您必须将变量初始化为null,然后将其设置为另一个值,并在finally块中通过检查是否为null来检查资源是否初始化。如果它不为null,则需要释放它。我知道我在吹毛求疵,但我觉得这可以做得更干净

我想做的是:

InputStream in = new FileInputStream("myfile.txt");
try{
    doSomethingWithStream(in);
}finally{
    in.close();
}
在我看来,这几乎和上一次一样安全。如果资源初始化失败并抛出异常,则无需执行任何操作(因为我没有获取资源),因此它不必位于try块内。我唯一担心的是,是否有某种方式(我没有Java认证)可以在操作之间抛出异常或错误

更简单的例子是:

Inputstream in = new FileInputStream("myfile.txt");
in.close();
有没有什么方法可以让流保持打开状态,而try-finally块可以阻止这种情况

编辑:


也许我应该省略最后一个例子,因为它让每个人都感到困惑。这不是一个初学者水平的问题。我知道最后的尝试是什么,我知道在最后一个例子中,如果中间有剂量,那是不安全的。这就是为什么它不在那里。我接受了艾尔斯的回答,因为这正是我想要的。有一种方法会导致两个操作之间出现异常,这会使中间示例不安全(使用Thread.stop),但由于它是使用不推荐的调用生成的,并且无论您做什么都会让您陷入困境,因此我觉得使用中间示例是安全的。

中间示例是安全的,而最后一个示例则不是


try finally块意味着即使
doSomethingWithStream
抛出异常,流也会关闭。是的,您可以捕获所有异常,然后以这种方式关闭流-但是让异常冒泡到调用方,但通过finally块在途中关闭流要简单得多。

实际上,在最后一个代码示例中,在两个调用之间可能会发生异常,并保持资源打开。如果在流构造之后,另一个线程立即使用thread.stop()或thread.stop(Throwable)强行停止该线程,则该线程将抛出异常(在第一种情况下为ThreadDeath),并且不会释放资源

但这正是这些方法被弃用的原因…

仔细研究。它有一个@Cleanup注释,可在局部变量上设置,用于清理资源

 import lombok.Cleanup;
 import java.io.*;

 public class CleanupExample {
   public static void main(String[] args) throws IOException {
     @Cleanup InputStream in = new FileInputStream(args[0]);
     @Cleanup OutputStream out = new FileOutputStream(args[1]);
     byte[] b = new byte[10000];
     while (true) {
       int r = in.read(b);
       if (r == -1) break;
       out.write(b, 0, r);
     }
   }
 }

最后一个是安全的,但我想它的目的是把
doSomethingWithStream(in)
放在两者之间。那当然就不安全了。为什么最后一个不安全?(我太慢了,doublep回答alread)在上一个示例中,目的不是在两次调用之间放置doSomethingWithStream。我猜这个问题更像是“这两个操作之间是否会出问题”。假设异常停止运行
close
。无法保证在垃圾收集
FileInputStream
之前需要多长时间(如果有),并且在此之前底层文件句柄将被打开。在一个进程中一次打开的文件句柄总数通常很小(几千个是一个常见的限制),因此FDs泄漏,即
FileInputStream
对象泄漏是严重的。@palto:如果你真的对流不做任何事,那么我想它是安全的。。。但这毫无意义。你多久打开一条小溪然后关闭一次?就我个人而言,在这种情况下我仍然会使用finally块,这样以后修改代码就更容易了,而不会引入bug。顺便说一句,如果您使用的是Apache Commons,您可以
IOUtils.closequirey(in)
。此实用程序函数检查
null
并抑制
IOException
,因为您可能对关闭时出现的异常不感兴趣。@doublep:谢谢您的提示。似乎还有很多其他有用的东西。为了澄清,在上一个示例中,doSomethingWithStream被故意忽略了。您认为这是一个严重的问题,我不应该使用我发布流的方式吗?是的,但是添加
try
-
finally
将不会有帮助。为什么它没有帮助?我的意思是,如果最后一个示例像第一个示例一样受到保护,那么即使没有线程死亡错误,它也不会安全吗?@palto:想象一下,如果在获取资源之后但在分配给变量之前引发异常…@Jon Skeet:那将是资源获取代码中的一个错误,而不是我的错误。这不是我的问题:)看起来很有趣,但似乎它与Eclipse结合得很好,我使用Netbeans。老实说,我对它错误处理Eclipse的方式也不满意。它使用字节码重写,并更改内存中API可以随时更改的方法。