自学内容网 自学内容网

Java 中的 try-with-resources 详解

在 Java 7 之前,处理资源关闭通常使用 try-catch-finally 块。虽然这种方式可以确保资源被正确关闭,但代码显得冗长且容易出错。Java 7 引入了 try-with-resources 语法,使得资源管理变得更加简洁和安全。本文将详细介绍 try-with-resources 的使用方法和优势。

1 try-catch-finally 的回顾

在介绍 try-with-resources 之前,我们先回顾一下传统的 try-catch-finally 块的使用方法。

示例:

public class TrycatchfinallyDecoder {
    public static void main(String[] args) {
        BufferedReader br = null;
        try {
            String path = TrycatchfinallyDecoder.class.getResource("/牛逼.txt").getFile();
            String decodePath = URLDecoder.decode(path, "utf-8");
            br = new BufferedReader(new FileReader(decodePath));

            String str = null;
            while ((str = br.readLine()) != null) {
                System.out.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

在这个例子中,我们使用 try-catch-finally 块来读取文件内容并确保 BufferedReader 资源被正确关闭。虽然这种方式可以确保资源被关闭,但代码显得冗长且容易出错,尤其是在 finally 块中还需要处理 close() 方法可能抛出的异常。

2 try-with-resources 的引入

try-with-resources 语法简化了资源管理,使得代码更加简洁和安全。要使用 try-with-resources,资源必须实现 AutoCloseable 接口。

示例:

try (BufferedReader br = new BufferedReader(new FileReader(decodePath))) {
    String str = null;
    while ((str = br.readLine()) != null) {
        System.out.println(str);
    }
} catch (IOException e) {
    e.printStackTrace();
}

在这个例子中,BufferedReader 资源在 try 块结束后会自动关闭,无需显式调用 close() 方法。

3 多个资源的管理

try-with-resources 语法支持同时管理多个资源,只需在 try 后的括号中声明多个资源即可。

示例:

try (BufferedReader br = new BufferedReader(new FileReader(decodePath));
     PrintWriter writer = new PrintWriter(new File(writePath))) {
    String str = null;
    while ((str = br.readLine()) != null) {
        writer.print(str);
    }
} catch (IOException e) {
    e.printStackTrace();
}

在这个例子中,BufferedReaderPrintWriter 资源都会在 try 块结束后自动关闭。

4 自定义资源的管理

如果需要管理自定义资源,只需让资源类实现 AutoCloseable 接口,并提供 close() 方法。

示例:

public class TrywithresourcesCustom {
    public static void main(String[] args) {
        try (MyResource resource = new MyResource()) {
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class MyResource implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("关闭自定义资源");
    }
}

在这个例子中,MyResource 类实现了 AutoCloseable 接口,并在 close() 方法中执行资源关闭操作。在 try-with-resources 块中使用 MyResource 对象时,close() 方法会自动调用。

反编译后的字节码:

class MyResource implements AutoCloseable {
    MyResource() {
    }

    public void close() throws Exception {
        System.out.println("关闭自定义资源");
    }
}

public class TrywithresourcesCustom {
    public TrywithresourcesCustom() {
    }

    public static void main(String[] args) {
        try {
            MyResource resource = new MyResource();
            resource.close();
        } catch (Exception var2) {
            var2.printStackTrace();
        }

    }
}

编译器主动为try-with-resources进行了变身,在 try 中调用了 close() 方法。

5 异常处理

try-with-resources 语法在处理异常时更加优雅。如果 try 块中的代码和资源关闭时都抛出异常,try-with-resources 会自动处理这些异常,并将被抑制的异常附加到主异常中。

示例:

class MyResourceOutThrow implements AutoCloseable {
    @Override
    public void close() throws Exception {
        throw new Exception("close()");
    }

    public void out() throws Exception {
        throw new Exception("out()");
    }
}

public class TrywithresourcesCustomOutThrow {
    public static void main(String[] args) {
        try (MyResourceOutThrow resource = new MyResourceOutThrow()) {
            resource.out();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行结果:

java.lang.Exception: out()
    at com.cmower.dzone.trycatchfinally.MyResourceOutThrow.out(TrywithresourcesCustomOutThrow.java:20)
    at com.cmower.dzone.trycatchfinally.TrywithresourcesCustomOutThrow.main(TrywithresourcesCustomOutThrow.java:6)
    Suppressed: java.lang.Exception: close()
        at com.cmower.dzone.trycatchfinally.MyResourceOutThrow.close(TrywithresourcesCustomOutThrow.java:16)
        at com.cmower.dzone.trycatchfinally.TrywithresourcesCustomOutThrow.main(TrywithresourcesCustomOutThrow.java:5)

在这个例子中,out() 方法和 close() 方法都抛出了异常。try-with-resources 语法将 close() 方法的异常附加到 out() 方法的异常中,并使用 Suppressed 关键字标记,使得调试更加方便。

反编译后的字节码:

public class TrywithresourcesCustomOut {
    public TrywithresourcesCustomOut() {
    }

    public static void main(String[] args) {
        try {
            MyResourceOut resource = new MyResourceOut();

            try {
                resource.out();
            } catch (Throwable var5) {
                try {
                    resource.close();
                } catch (Throwable var4) {
                    var5.addSuppressed(var4);
                }

                throw var5;
            }

            resource.close();
        } catch (Exception var6) {
            var6.printStackTrace();
        }

    }
}

catch 块主动调用了 resource.close(),并且有一段很关键的代码 var5.addSuppressed(var4)
当一个异常被抛出的时候,可能有其他异常因为该异常而被抑制住,从而无法正常抛出。这时可以通过 addSuppressed() 方法把这些被抑制的方法记录下来,然后被抑制的异常就会出现在抛出的异常的堆栈信息中,可以通过 getSuppressed() 方法来获取这些异常。这样做的好处是不会丢失任何异常,方便我们进行调试。

6 思维导图

在这里插入图片描述

7 参考链接

深入理解 Java 中的 try with resources


原文地址:https://blog.csdn.net/gaosw0521/article/details/143503940

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!