Java7 异常处理:try-with-resources 关闭资源异常

某些资源在尝试关闭时也会抛出异常。如果某个资源在尝试关闭时抛出异常,在同一 try-with-resources 块中打开的其他资源仍会被关闭。关闭所有资源后,尝试关闭资源失败时产生的异常将在调用堆栈中向上传播。例如:

package com.hxstrive.jdk7.try_with_resources;

/**
 * JDK7 新特性 try-with-resources
 * @author hxstrive.com
 */
public class TryWithResourcesDemo5 {

    static class MyResource1 implements AutoCloseable {
        @Override
        public void close() throws Exception {
            // 关闭抛出异常
            throw new Exception("MyResource1.close");
        }
    }

    static class MyResource2 implements AutoCloseable {
        @Override
        public void close() throws Exception {
            // 即使 MyResource1 关闭抛出了异常,也会执行
            System.out.println("MyResource2.close");
        }
    }

    public static void main(String[] args) throws Exception {
        try(
                MyResource1 resource1 = new MyResource1();
                MyResource2 resource2 = new MyResource2()
        ) {
            //...
        }
        //结果:
        //MyResource2.close
        //Exception in thread "main" java.lang.Exception: MyResource1.close
    }

}

如果多个资源关闭尝试抛出了多个异常,则第一个遇到的异常将向上传播到调用堆栈。其余异常将被抑制。例如:

package com.hxstrive.jdk7.try_with_resources;

import java.util.Arrays;

/**
 * JDK7 新特性 try-with-resources
 * @author hxstrive.com
 */
public class TryWithResourcesDemo6 {

    static class MyResource1 implements AutoCloseable {
        @Override
        public void close() throws Exception {
            // 关闭抛出异常
            System.out.println("MyResource1.close()");
            throw new Exception("MyResource1.close");
        }
    }

    static class MyResource2 implements AutoCloseable {
        @Override
        public void close() throws Exception {
            System.out.println("MyResource2.close()");
            throw new Exception("MyResource2.close");
        }
    }

    public static void main(String[] args) throws Exception {
        try {
            try (
                    MyResource1 resource1 = new MyResource1();
                    MyResource2 resource2 = new MyResource2()
            ) {
                //...
            }
        } catch (Exception e) {
            // 输出抑制的异常列表
            System.out.println(Arrays.toString(e.getSuppressed()));
            e.printStackTrace();
        }
        //结果:
        //MyResource2.close()
        //MyResource1.close()
        //[java.lang.Exception: MyResource1.close]
        //java.lang.Exception: MyResource2.close
    }

}

如果在 try-with-resources 代码块内和关闭资源(调用 close() 时)时都出现异常,则 try 代码块内出现的异常将在调用堆栈中向上传播。试图关闭资源时抛出的异常将被抑制。这与普通 try-catch-finally 代码块中的情况相反,在普通 try-catch-finally 代码块中,最后遇到的异常才会在调用栈中向上传递。例如:

package com.hxstrive.jdk7.try_with_resources;

import java.util.Arrays;

/**
 * JDK7 新特性 try-with-resources
 * @author hxstrive.com
 */
public class TryWithResourcesDemo4 {

    static class MyResource implements AutoCloseable {
        private String name;
        private boolean closeFlag;

        public MyResource(String name, boolean closeFlag) {
            this.name = name;
            this.closeFlag = closeFlag;
        }

        @Override
        public void close() throws Exception {
            System.out.println("close");
            if(closeFlag) {
                throw new RuntimeException(this.name + " close error");
            }
        }

        public void doSomething(boolean doFlag) {
            System.out.println("doSomething");
            if(doFlag) {
                throw new RuntimeException(this.name + " doSomething error");
            }
        }
    }

    public static void main(String[] args) throws Exception {
        // 如果 try-with-resources 代码块和关闭资源均出现异常,则抛出代码块中的异常,抑制关闭资源时出现的异常。
        try {
            try (MyResource resource = new MyResource("test", true)) {
                resource.doSomething(true);
            }
        } catch (Exception e) {
            // getSuppressed() 方法返回一个数组,其中包含为传递此异常而抑制的所有异常,
            // 通常是通过 try-with-resources 语句抑制的异常。如果没有异常被抑制或抑制被禁用,则返回空数组。
            // 该方法是线程安全的。对返回数组的写入不会影响以后对该方法的调用。
            System.out.println(Arrays.toString(e.getSuppressed()));
            e.printStackTrace();
        }
        //结果:
        //doSomething
        //close
        //[java.lang.RuntimeException: test close error] 这就是被抑制的异常列表
        //java.lang.RuntimeException: test doSomething error
        //...
    }

}

请记住,在 try 代码块中只能抛出一个异常。一旦抛出异常,就会退出 try 代码块,并尝试关闭资源。

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号