千家信息网

effective java第三版推荐使用try-with-resources代替try-finally的原因是什么

发表于:2024-11-11 作者:千家信息网编辑
千家信息网最后更新 2024年11月11日,本篇内容主要讲解"effective java第三版推荐使用try-with-resources代替try-finally的原因是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。
千家信息网最后更新 2024年11月11日effective java第三版推荐使用try-with-resources代替try-finally的原因是什么

本篇内容主要讲解"effective java第三版推荐使用try-with-resources代替try-finally的原因是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"effective java第三版推荐使用try-with-resources代替try-finally的原因是什么"吧!

背景

try-finally 这个语句想必做java的同学都不陌生吧,每当我们有关闭资源的需求我们都会使用到try-finally这个语句,比如我们在使用锁的时候,无论是本地的可重入锁还是分布式锁都会有下面类似的结构代码,我们会在finally里面进行unlock,用于强制解锁:

    Lock lock = new ReentrantLock();    lock.lock();    try{        // doSometing    }finally {        lock.unlock();    }

或者我们使用java的文件流读取或者写入文件的时候,我们也会在finally中强制关闭文件流,防止资源泄漏。

    InputStream inputStream = new FileInputStream("file");    try {        System.out.println(inputStream.read(new byte[4]));    }finally {        inputStream.close();    }

其实乍一看 这样的写法应该没什么问题,但是如果我们出现了多个资源需要关闭我们应该怎么写呢?最常见的写法如下:

InputStream inputStream = new FileInputStream("file");    OutputStream outStream = new FileOutputStream("file1");    try {        System.out.println(inputStream.read(new byte[4]));        outStream.write(new byte[4]);    }finally {        inputStream.close();        outStream.close();    }

我们在外面定义了两个资源,然后在finally里面依次对这两个资源进行关闭,这个写法在我最开始写java的时候对文件流和数据库连接池做close的时候一些教学的文章都是这么教学的,那么这个哪里有问题呢?问题其实在于如果在inputStream.close的时候抛出异常,那么outStream.close()就不会执行,这很明显不是我们想要的结果,所以后面就改成了下面这种多重嵌套的方式去写:

    InputStream inputStream = new FileInputStream("file");    try {        System.out.println(inputStream.read(new byte[4]));        try{            OutputStream outStream = new FileOutputStream("file1");            outStream.write(new byte[4]);        }finally {            outStream.close();        }    }finally {        inputStream.close();    }

在这种方式中即便是outStream.close()抛出了异常,但是我们依然会执行到inputStream.close(),因为他们是在不同的finally块,这个的确解决了我们的问题,但是还有两个问题没有解决:

  • 带来的第一个问题就是如果我们有不止两个资源,比如有十个资源,难道需要让我们写十个嵌套的语句吗?写完之后这个代码还能看吗?

  • 第二个问题就是如果我们在try里面出现异常,然后在finally里面又出现异常,就会导致异常覆盖,会导致finally里面的异常将try的异常覆盖了。

public class CloseTest {    public void close(){        throw new RuntimeException("close");    }    public static void main(String[] args) {        CloseTest closeTest = new CloseTest();        try{            throw new RuntimeException("doSomething");        }finally {            closeTest.close();        }    }}输出结果:Exception in thread "main" java.lang.RuntimeException: close

上面这个代码,我们期望的是能抛出doSomething的这个异常,但是实际的数据结果却是close的异常,这和我们的预期不符合。

try-with-resources

上面我们介绍了两个问题,于是在java7中引入了try-with-resources的语句,只要我们的资源实现了AutoCloseable这个接口那么我们就可以使用这个语句了,我们之前的文件流已经实现了这个接口那么我们可以直接使用:

try(InputStream inputStream = new FileInputStream("file");            OutputStream outStream = new FileOutputStream("file1")) {            System.out.println(inputStream.read(new byte[4]));            outStream.write(new byte[4]);        }

我们所有的资源定义全部都在try后面的括号中进行定义,通过这种方式我们就可以解决上面所说的几个问题:

  • 首先第一个问题,我们通过这样的方式,代码非常整洁,无论你有多少个资源,都可以很简洁的去做。

  • 第二个异常覆盖问题的话,我们可以通过实验来看一下,我们将代码改写为如下:

public class CloseTest implements AutoCloseable {    @Override    public void close(){        System.out.println("close");        throw new RuntimeException("close");    }    public static void main(String[] args) {        try(CloseTest closeTest = new CloseTest();            CloseTest closeTest1 = new CloseTest();){            throw new RuntimeException("Something");        }    }}输出结果为:closecloseException in thread "main" java.lang.RuntimeException: Something        at fudao.CloseTest.main(CloseTest.java:33)        Suppressed: java.lang.RuntimeException: close                at fudao.CloseTest.close(CloseTest.java:26)                at fudao.CloseTest.main(CloseTest.java:34)        Suppressed: java.lang.RuntimeException: close                at fudao.CloseTest.close(CloseTest.java:26)                at fudao.CloseTest.main(CloseTest.java:34)

我们在代码中定义了两个CloseTest,用来验证之前close出现异常是否会影响第二个,同时在close和try块里面都抛出不同的异常,可以看见我们的结果,输出了两个close,证明虽然close抛出异常,但是两个close都会执行。然后输出了doSomething的异常,可以发现这里我们输出的就是我们try块里面所抛出的异常,并且我们close的异常以Suppressed的方式记录在异常的堆栈里面,通过这样的方式我们两种异常都能记录下来。

try-with-resources原理

try-with-resources语句其实是一种语法糖,通过编译之后又回到了我们开始说的嵌套的那种模式:

可以发现try-with-resources被编译之后,又采取了嵌套的模式,但是和之前的嵌套有点不同,他close的时候都利用了catch去捕获了异常,然后添加到我们真正的异常中,整体逻辑比我们之前的嵌套要复杂一些。

到此,相信大家对"effective java第三版推荐使用try-with-resources代替try-finally的原因是什么"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0