工作实践之 资源关闭
- try-with-resource 注“JDK7及其之后的资源关闭方式
注意:下面都是文件创建来举例子
**
* 资源关闭优化前与优化后代码量对比
*/
public class ResourceCloseVs {
@Test
public void newFileHandle(String url,
FileConsumer fileConsumer) {
try (
// 声明、创建文件的读取流
FileInputStream fileInputStream =
new FileInputStream(url);
InputStreamReader inputStreamReader =
new InputStreamReader(fileInputStream);
BufferedReader bufferedReader =
new BufferedReader(inputStreamReader);
) {
// 定义行变量和内容sb
String line;
StringBuilder stringBuilder = new StringBuilder();
// 循环读取文件内容
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line + "\n");
}
// 调用函数式接口方法,将文件内容传递给lambda表达式,实现业务逻辑
fileConsumer.fileHandler(stringBuilder.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void oldFileHandle(String url,
FileConsumer fileConsumer) {
// 声明
FileInputStream fileInputStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
// 创建文件读取流
try {
fileInputStream = new FileInputStream(url);
inputStreamReader =
new InputStreamReader(fileInputStream);
bufferedReader =
new BufferedReader(inputStreamReader);
// 定义行变量和内容sb
String line;
StringBuilder stringBuilder = new StringBuilder();
// 循环读取文件内容
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line + "\n");
}
// 调用函数式接口方法,将文件内容传递给lambda表达式,实现业务逻辑
fileConsumer.fileHandler(stringBuilder.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流资源
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStreamReader != null) {
try {
inputStreamReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
常见需要手动释放的物理资源
- 文件/流资源
- 套接字资源
- 数据库连接资源
4.NIO的直接内存资源
物理资源没有手动释放的坏处
- 资源被长时间无效占用
- 超过最大限制后,将无资源可用
- 导致系统无法正常运行
具体案例:文件拷贝(初始版本)
* 1. 创建输入/输出流
* 2. 执行文件拷贝,读取文件内容,写入到另一个文件中
* 3. **关闭文件流资源**
/**
* JDK7之前的文件拷贝功能
*/
public class FileCopyTest {
@Test
public void copyFile() {
/**
* 1. 创建输入/输出流
* 2. 执行文件拷贝,读取文件内容,写入到另一个文件中
* 3. **关闭文件流资源**
*/
// 定义输入路径和输出路径
String originalUrl = "lib/FileCopyTest.java";
String targetUrl = "targetTest/target.txt";
// 声明文件输入流,文件输出流
FileInputStream originalFileInputStream = null;
FileOutputStream targetFileOutputStream = null;
try {
// 实例化文件流对象
originalFileInputStream =
new FileInputStream(originalUrl);
targetFileOutputStream =
new FileOutputStream(targetUrl);
// 读取的字节信息
int content;
// 迭代,读取/写入字节
while ((content = originalFileInputStream.read()) != -1) {
targetFileOutputStream.write(content);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流资源
if (targetFileOutputStream != null) {
try {
targetFileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (originalFileInputStream != null) {
try {
originalFileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 基于JDK7之后,实现正确关闭流资源方法
* try - with - resource
*/
public class NewFileCopyTest {
@Test
public void copyFile() {
// 先定义输入/输出路径
String originalUrl = "lib/NewFileCopyTest.java";
String targetUrl = "targetTest/new.txt";
// 初始化输入/输出流对象
try (
FileInputStream originalFileInputStream =
new FileInputStream(originalUrl);
FileOutputStream targetFileOutputStream =
new FileOutputStream(targetUrl);
) {
int content;
// 迭代,拷贝数据
while ((content = originalFileInputStream.read()) != -1) {
targetFileOutputStream.write(content);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
工作实践之 资源关闭
try-with-resource 注“JDK7及其之后的资源关闭方式
- java 7引入的新特性
- 优雅关闭资源
- 一种java语法糖(可以反编译看源码)
案例实战: 源码解析 -> 下面是 NewFileCopyTest.class 反编译的源代码
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.junit.Test;
public class NewFileCopyTest {
public NewFileCopyTest() {
}
@Test
public void copyFile() {
String originalUrl = "lib/NewFileCopyTest.java";
String targetUrl = "targetTest/new.txt";
try {
FileInputStream originalFileInputStream = new FileInputStream(originalUrl);
Throwable var4 = null;
try {
FileOutputStream targetFileOutputStream = new FileOutputStream(targetUrl);
Throwable var6 = null;
try {
int content;
try {
while((content = originalFileInputStream.read()) != -1) {
targetFileOutputStream.write(content);
}
} catch (Throwable var33) {
var6 = var33;
throw var33;
}
} finally {
if (targetFileOutputStream != null) {
if (var6 != null) {
try {
targetFileOutputStream.close();
} catch (Throwable var32) {
var6.addSuppressed(var32);
}
} else {
targetFileOutputStream.close();
}
}
}
} catch (Throwable var35) {
var4 = var35;
throw var35;
} finally {
if (originalFileInputStream != null) {
if (var4 != null) {
try {
originalFileInputStream.close();
} catch (Throwable var31) {
var4.addSuppressed(var31);
}
} else {
originalFileInputStream.close();
}
}
}
} catch (FileNotFoundException var37) {
var37.printStackTrace();
} catch (IOException var38) {
var38.printStackTrace();
}
}
}
try-with-resource使用注意下面几点:
package java.lang;
/**
* An object that may hold resources (such as file or socket handles)
* until it is closed. The {@link #close()} method of an {@code AutoCloseable}
* object is called automatically when exiting a {@code
* try}-with-resources block for which the object has been declared in
* the resource specification header. This construction ensures prompt
* release, avoiding resource exhaustion exceptions and errors that
* may otherwise occur.
*
* @apiNote
* <p>It is possible, and in fact common, for a base class to
* implement AutoCloseable even though not all of its subclasses or
* instances will hold releasable resources. For code that must operate
* in complete generality, or when it is known that the {@code AutoCloseable}
* instance requires resource release, it is recommended to use {@code
* try}-with-resources constructions. However, when using facilities such as
* {@link java.util.stream.Stream} that support both I/O-based and
* non-I/O-based forms, {@code try}-with-resources blocks are in
* general unnecessary when using non-I/O-based forms.
*
* @author Josh Bloch
* @since 1.7
*/
public interface AutoCloseable {
/**
* Closes this resource, relinquishing any underlying resources.
* This method is invoked automatically on objects managed by the
* {@code try}-with-resources statement.
*
* <p>While this interface method is declared to throw {@code
* Exception}, implementers are <em>strongly</em> encouraged to
* declare concrete implementations of the {@code close} method to
* throw more specific exceptions, or to throw no exception at all
* if the close operation cannot fail.
*
* <p> Cases where the close operation may fail require careful
* attention by implementers. It is strongly advised to relinquish
* the underlying resources and to internally <em>mark</em> the
* resource as closed, prior to throwing the exception. The {@code
* close} method is unlikely to be invoked more than once and so
* this ensures that the resources are released in a timely manner.
* Furthermore it reduces problems that could arise when the resource
* wraps, or is wrapped, by another resource.
*
* <p><em>Implementers of this interface are also strongly advised
* to not have the {@code close} method throw {@link
* InterruptedException}.</em>
*
* This exception interacts with a thread's interrupted status,
* and runtime misbehavior is likely to occur if an {@code
* InterruptedException} is {@linkplain Throwable#addSuppressed
* suppressed}.
*
* More generally, if it would cause problems for an
* exception to be suppressed, the {@code AutoCloseable.close}
* method should not throw it.
*
* <p>Note that unlike the {@link java.io.Closeable#close close}
* method of {@link java.io.Closeable}, this {@code close} method
* is <em>not</em> required to be idempotent. In other words,
* calling this {@code close} method more than once may have some
* visible side effect, unlike {@code Closeable.close} which is
* required to have no effect if called more than once.
*
* However, implementers of this interface are strongly encouraged
* to make their {@code close} methods idempotent.
*
* @throws Exception if this resource cannot be closed
*/
void close() throws Exception;
}
try-with-resource使用注意下面几点:
- 多资源自动关闭
- 实现AutoCloseable接口
- 避免了异常被屏蔽的问题 :addSuppressed
资源关闭顺序问题:
- 先开后关原则
- 从外到内原则
- 底层资源单独声明原则
资源关闭的特殊情况
- 资源对象被return的情况下,由调用方关闭
- ByteArrayInputStream等不需要检查关闭的资源对象
- 使用Socket获取的InputStream和OutputStream对象不需要关闭