Java自动化资源关闭利器 - try-with-resource使用实践

在JDK 7中,引入了try-with-resource用于替代在try-catch-finally中手动的资源关闭

通常需要我们手动释放的资源包括:

  • 文件/流资源
  • socket资源
  • 数据库连接资源

这些资源不能自动的被回收,长时间无效占用,当超过最大限制后,将会无资源可用,最终导致系统无法正常运行

以文件拷贝为例演示JDK 7之前和引入try-with-resource后的差异

  • 使用try-catch-finally实现文件拷贝的资源管理
    输入输出流需要在try块外先定义,并在finally中按初始化顺序的倒序逐一进行释放
	@Test
    public void copyFile() {
        //路径
        String originalUrl = "lib/FileCopy.java";
        String outUrl = "outTest/out.txt";
        //资源对象
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;

        try {
            //初始化资源对象
            fileInputStream = new FileInputStream(originalUrl);
            fileOutputStream = new FileOutputStream(outUrl);

            int content;
            //读取并写入
            while ((content = fileInputStream.read()) != -1) {
                fileOutputStream.write(content);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {//资源关闭
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileInputStream!= null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

使用try-with-resource实现文件拷贝的资源管理
try-with-resource的结构是:

		try (
                //资源定义

        ) {
                //逻辑代码
        } catch(Exception e) {
                //异常处理
        }

try-catch-finally相比,在try后多了一对小括号用于资源定义,且不需要再手动的关闭资源了

具体代码如下:

	/**
     * 基于JDK7及以后的
     * try - with - resource
     */
    @Test
    public void newCopyFile() {
        //路径
        String originalUrl = "lib/FileCopy.java";
        String outUrl = "outTest/out.txt";

        /**
         * 小括号内定义资源,不需要显示的关闭资源,会自动的关闭
         * try - with - resource
         */
        try (
                //定义资源
                FileInputStream fileInputStream = new FileInputStream(originalUrl);
                FileOutputStream fileOutputStream = new FileOutputStream(outUrl);
        ) {
            int content;
            while ((content = fileInputStream.read()) != -1) {
                fileOutputStream.write(content);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

从上面两段代码可以看出,在try-with-resource中的小括号内定义资源就不用再手动的进行释放了

为了更清楚的弄明白是怎样实现了,查看下反编译的代码

这里反编译的代码来自IDEA编译后的target文件下自动反编译的文件。
在这里插入图片描述
使用try-with-resource 的反编译代码如下

	@Test
    public void newCopyFile() {
        String originalUrl = "lib/FileCopy.java";
        String outUrl = "outTest/out.txt";

        try {
            FileInputStream fileInputStream = new FileInputStream(originalUrl);
            Throwable var4 = null;

            try {
                FileOutputStream fileOutputStream = new FileOutputStream(outUrl);
                Throwable var6 = null;

                try {
                    int content;
                    try {
                        while((content = fileInputStream.read()) != -1) {
                            fileOutputStream.write(content);
                        }
                    } catch (Throwable var33) {
                        var6 = var33;
                        throw var33;
                    }
                } finally {
                    if (fileOutputStream != null) {
                        if (var6 != null) {
                            try {
                                fileOutputStream.close();
                            } catch (Throwable var32) {
                                var6.addSuppressed(var32);
                            }
                        } else {
                            fileOutputStream.close();
                        }
                    }

                }
            } catch (Throwable var35) {
                var4 = var35;
                throw var35;
            } finally {
                if (fileInputStream != null) {
                    if (var4 != null) {
                        try {
                            fileInputStream.close();
                        } catch (Throwable var31) {
                            var4.addSuppressed(var31);
                        }
                    } else {
                        fileInputStream.close();
                    }
                }

            }
        } catch (FileNotFoundException var37) {
            var37.printStackTrace();
        } catch (IOException var38) {
            var38.printStackTrace();
        }

    }

可以很容易的发现,编译器将try-with-resource格式的代码编译成了嵌套的try-catch-finally的形式,所以可以证明try-with-resource能实现自动添加资源释放

使用注意点:

  • 资源需要实现AutoCloseable接口
    在这里插入图片描述在这里插入图片描述
  • 资源对象被return的情况下,由调用方关闭
  • ByteArrayInputStream等不需要检查关闭资源对象
  • 使用socket获取的InputStream和OutputStream对象不需要关闭
    (如果直接关闭会关闭socket整个连接,需要调用socket的方法进行关闭-shutdowInput 和 shutdownOutput)

猜你喜欢

转载自blog.csdn.net/qq_41170102/article/details/105658805