资源释放的方式
书接上文, 在上一篇文章我们做过一个文件拷贝的练习, 但是在联系中是有释放资源隐患的的, 例如在下面代码中, 在文件释放之前有许多行的逻辑代码; 如果这许多行的逻辑代码有报错, 导致程序不运行, 那么资源就得不到释放
public static void main(String[] args) {
try {
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.pdf");
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/newtest.pdf");
byte[] arr = inp.readAllBytes();
oup.write(arr);
System.out.println("复制成功!");
// 许多行的逻辑代码
oup.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try-catch-finally
为了解决隐患, 我们需要使用try-catch-finally对资源释放进行优化
finally:在异常处理时提供finally块来执行所有清除操作,比如说IO流中的释放资源
特点:被finally控制的语句最终一定会执行(除非JVM退出)
异常处理标准格式:try….catch…finally
try….catch…finally格式:
try {
FileOutputStream fos = new FileOutputStream("a.txt");
fos.write(97);
fos.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
使用try….catch…finally优化文件拷贝代码
由于finally中无法访问到 inp和oup, 所以我们需要在外部定义变量将 inp和oup保存起来
public static void main(String[] args) {
// 在外部保存为了finally中可以访问到
InputStream inp = null;
OutputStream oup = null;
try {
inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.pdf");
oup = new FileOutputStream("/Users/chenyq/Documents/newtest.pdf");
byte[] arr = inp.readAllBytes();
oup.write(arr);
System.out.println("复制成功!");
} catch (IOException e) {
e.printStackTrace();
} finally { // finally中释放资源
try {
if (inp != null) { // 非空校验
inp.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (oup != null) { // 非空校验
oup.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
try-catch-resource
finally虽然可以用于释放资源,但是释放资源的代码过于繁琐, 那么有没有办法可以简化呢?
JDK7和JDK9中都简化了资源释放操作
JDK7改进方案演示:
在括号中放置资源对象, 并且是只能放置资源对象, 用完会自动关闭: 自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭的操作)
public static void main(String[] args) {
try(
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.pdf");
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/newtest.pdf");
) {
byte[] arr = inp.readAllBytes();
oup.write(arr);
System.out.println("复制成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
JDK9改进方案演示:
弊端: 在try外部定义输入输出流还需要再抛出异常
public static void main(String[] args) throws Exception {
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.pdf");
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/newtest.pdf");
try(inp; oup) {
byte[] arr = inp.readAllBytes();
oup.write(arr);
System.out.println("复制成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
注意:
JDK 7 以及 JDK 9的()中只能放置资源对象,否则报错
什么是资源呢?
资源都是实现了Closeable / AutoCloseable接口的类对象
public abstract class InputStream implements Closeable {}
public abstract class OutputStream implements Closeable, Flushable{}