前言
Try-with-resources是java7中一个新的异常处理机制,它能够很容易地关闭在try-catch语句块中使用的资源。
jdk7之前
下面是按行读取txt的小demo,数据处理之后需要在finally中关闭流
public void handleResourceBeforeJdk7() {
String encoding = "utf-8";
File file = new File("e:/1/test.txt");
InputStreamReader read = null;
BufferedReader br = null;
try {
read = new InputStreamReader(
new FileInputStream(file), encoding);
br = new BufferedReader(read);
if (file.exists() && file.isFile()) {
String lineText;
while ((lineText = br.readLine()) != null) {
LOGGER.info("lineText=" + lineText);
}
}
} catch (IOException e) {
LOGGER.error("error", e);
} finally {
try {
if (br != null) {
br.close();
}
if (read != null) {
read.close();
}
} catch (Exception e) {
LOGGER.error("error", e);
}
}
}
jdk7之后
jdk7之后,我们采用try-with-resource来处理资源的关闭,可以看到代码立马简洁了不少
public void handleResourceAfterJdk7() {
String encoding = "utf-8";
File file = new File("e:/1/test.txt");
try (InputStreamReader read = new InputStreamReader(
new FileInputStream(file), encoding);
BufferedReader br = new BufferedReader(read)) {
if (file.exists() && file.isFile()) {
String lineText;
while ((lineText = br.readLine()) != null) {
LOGGER.info("lineText=" + lineText);
}
}
} catch (IOException e) {
LOGGER.error("error", e);
}
}
自定义实现AutoCloseable接口的资源类
其实在try-with-resiurce中定义的资源都是实现了AutoCloseable接口,在资源处理完成之后会自动进行关闭,我们可以自己定义一个资源类实现AutoCloseable接口来模拟资源的自动关闭
/**
* @author: 爱琴孩
*/
@Service
public class AutoclosedTest implements AutoCloseable {
private static final Logger LOGGER = LoggerFactory.getLogger(AutoclosedTest.class);
public void handleResource() throws Exception {
LOGGER.info("开始处理资源");
}
@Override
public void close() throws Exception {
LOGGER.info("资源处理完成之后的后处理操作!");
}
}
使用try-with-resouce格式来处理我们自定义的资源类AutoclosedTest
try (AutoclosedTest autoclosedTest = new AutoclosedTest()) {
autoclosedTest.handleResource();
} catch (Exception e) {
LOGGER.error("error", e);
}
执行结果如下
try-with-resource不会遮蔽原始异常
try-with-resource相比之前的try-catch-finally,前者不会因为finally可能抛出的异常而屏蔽了try块的原始异常,这在实际现网问题排查影响很大,可以在上面两个方法中都抛出一个异常来测试下
public void handleResourceWithException() throws Exception {
LOGGER.info("开始处理资源");
throw new Exception("exception from resource");
}
@Override
public void close() throws Exception {
LOGGER.info("资源处理完成之后的后处理操作!");
throw new Exception("exception from close resource");
}
执行之后如下
我们可以看看上面的使用try-with-resource形式处理AutoclosedTest资源类反编译之后的代码,看看为啥没有屏蔽资源处理的原始异常
try {
AutoclosedTest autoclosedTest = new AutoclosedTest();
Throwable var3 = null;
try {
autoclosedTest.handleResource();
} catch (Throwable var13) {
var3 = var13;
throw var13;
} finally {
if (autoclosedTest != null) {
if (var3 != null) {
try {
autoclosedTest.close();
} catch (Throwable var12) {
var3.addSuppressed(var12);
}
} else {
autoclosedTest.close();
}
}
}
} catch (Exception var15) {
LOGGER.error("error", var15);
}
上面的代码可以看到,其实try-with-resource在代码编译之后还是在finally中去处理资源的后续操作,而var3.addSuppressed(var12)就能解释try-with-resource不会屏蔽原始异常了。