Java 什么';try with resources语句的目的是什么?

Java 什么';try with resources语句的目的是什么?,java,java-7,try-with-resources,Java,Java 7,Try With Resources,Java7有一个新特性,叫做。这是怎么一回事?我们为什么要使用它,应该在哪里使用它,我们可以在哪里利用这个特性 try语句没有使我困惑的catch块。如下: try with resources语句是一个try语句,它声明了一个 或者更多的资源。资源是一个对象,必须在 程序结束了。try with resources语句 确保在语句末尾关闭每个资源。任何 实现java.lang.AutoCloseable,其中包括所有 实现java.io.Closeable的对象可以用作 资源 下面的示例从文件

Java7有一个新特性,叫做。这是怎么一回事?我们为什么要使用它,应该在哪里使用它,我们可以在哪里利用这个特性

try
语句没有使我困惑的
catch
块。

如下:

try with resources语句是一个try语句,它声明了一个 或者更多的资源。资源是一个对象,必须在 程序结束了。try with resources语句 确保在语句末尾关闭每个资源。任何 实现
java.lang.AutoCloseable
,其中包括所有 实现
java.io.Closeable
的对象可以用作 资源

下面的示例从文件中读取第一行。它使用一个 从文件中读取数据的BufferedReader实例。缓冲区读取 是必须在程序结束后关闭的资源 它:

在本例中,在try with resources中声明的资源 语句是一个BufferedReader。此时将显示声明语句 在try关键字后面的括号内。班级 BufferedReader在JavaSE7及更高版本中实现了该接口 java.lang.AutoCloseable。因为BufferedReader实例是 在try with resource语句中声明,它将被关闭 不管try语句是正常完成还是突然完成


您可以从中阅读更多内容。

之所以引入它,是因为Java中使用的一些资源(如SQL连接或流)难以正确处理;例如,在java 6中,要正确处理InputStream,必须执行以下操作:

InputStream stream = new MyInputStream(...);
try {
    // ... use stream
} catch(IOException e) {
   // handle exception
} finally {
    try {
        if(stream != null) {
            stream.close();
        }
    } catch(IOException e) {
        // handle yet another possible exception
    }
}
你注意到那个丑陋的双重尝试了吗?现在,使用“试用资源”,您可以执行以下操作:

try (InputStream stream = new MyInputStream(...)){
    // ... use stream
} catch(IOException e) {
   // handle exception
}

并自动调用close(),如果它抛出IOException,它将被抑制(如中所指定)。java中的java.sql.Connection

也会发生同样的情况,如果您使用输入流或输出流之类的资源,那么在使用后总是必须关闭它。它还可以抛出异常,因此它必须位于
try
catch
块中。关闭必须在
finally
块中。在Java7之前,这是一种最起码的方法。这有几个缺点:

  • 在关闭ressource之前,您必须检查它是否为
    null
  • 关闭本身可能引发异常,因此您的
    最终
    必须包含另一个
    try
    -
    catch
  • 程序员往往忘记关闭他们的资源

前两个主要是语法问题,后一个更为关键。因此,如果您使用try-with语句,您的代码将变得更干净,而且最重要的是:您的ressource将始终关闭:-)

优点是您不需要显式关闭try-with-resources语句中定义的资源。JVM会处理它。它将自动为您关闭这些资源


开发人员通常面临的问题是构造try-catch-finally块,因为即使在finally块中关闭资源,我们也必须使用try-catch。try-catch-finally语句有多种结构可以帮助解决此问题,但try-with-resources语句基本上可以帮助您简化编码结构逻辑。

您可以尝试此方法-如果资源在try{}内初始化,它将自动关闭:

try {
            Scanner scanner = new Scanner(new File(csvFile));
            while (scanner.hasNext()) {
                 // do something
            }
            scanner.close();
        }catch(FileNotFoundException fnfe)
        {
            System.err.println(fnfe.getLocalizedMessage());
        }

使用“与资源一起尝试”的好处:

  • 更可读的代码和易于编写

  • 自动资源管理

  • 代码行数减少

  • 不需要为了关闭资源而最终阻塞

  • 我们可以在try-with-resources语句中打开多个资源,语句之间用分号分隔。例如,我们可以编写以下代码

    public void sampleTryWithResource() {
        try(Connection dbCon = DriverManager.getConnection("url", "user", "password");
                BufferedReader br = new BufferedReader(new FileReader("C://readfile/input.txt"));) {
            //...Your Business logic
        } catch (Exception e) {
            //...Exception Handling
        }
    }
    
  • 在try-with-resources中打开多个资源时,会以相反的顺序关闭它们,以避免任何依赖性问题。你可以扩展我的资源计划来证明这一点

  • 自2017年Java 9发布后更新 现在使用
    java9
    我们有了更多的语法糖,我们可以在
    try-catch
    块之外声明一个资源,但仍然可以正确处理

    让我们以Java 6处理资源的
    方式为例:

    InputStream stream = new MyInputStream(...);
    try {
        // ... use stream
    } catch(IOException e) {
       // handle exception
    } finally {
        try {
            if(stream != null) {
                stream.close();
            }
        } catch(IOException e) {
            // handle yet another possible exception
        }
    }
    
    在这里,我们可以注意到,正如其他答案所指出的,这个代码非常丑陋

    因此
    Java7
    中的解决方案是引入这个
    try catch with resource

    try (InputStream stream = new MyInputStream(...)){
        // ... use stream
    } catch(IOException e) {
       // handle exception
    }
    
    这个符号肯定比前一个好得多,但是我们有一个问题。如果资源(在本例中为流)先前已声明,但我们希望确保在该块中正确处理,则需要以下技巧:

    InputStream stream = new MyInputStream(...)
    try (InputStream stream2 = stream) {
       // do something with stream being sure that is going to be closed at the end
    } catch(IOException e) {
       // handle exception
    }
    
    我们可以注意到,这种情况只能通过另一段丑陋的代码来解决。这就是为什么Java 9改进了“资源试用”引入了一种新语法:

    InputStream stream = new MyInputStream(...)
    try (stream) {
       // do something with stream being sure that is going to be closed at the end
    } catch(IOException e) {
       // handle exception
    }
    
    注意,对于Java版本8或更小版本,此语法将导致编译时错误

    这是一种更“自然”的编写方式,即使在大多数用例中,我们不需要try块范围之外的资源。
    唯一的限制是reader变量应该是有效的final或刚好final。

    看看trailIf如果BufferedReader构造函数抛出异常(不太可能),FileReader将不会关闭。Personnaly我发现try with resources语句也非常难看。当您有多个资源时,情况更糟。@morgano
    如果它抛出IOException,它将在同一catch子句中处理,这是误导。如果
    close()
    抛出异常,它将被抑制。将
    stream
    声明为
    final
    ,并且不需要检查
    是否(stream!=null)
    (它将始终为真)
    InputStream stream = new MyInputStream(...)
    try (stream) {
       // do something with stream being sure that is going to be closed at the end
    } catch(IOException e) {
       // handle exception
    }