面试官:“来,你会try-with-resource写法吗”?
Posted 懂你的大海
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试官:“来,你会try-with-resource写法吗”?相关的知识,希望对你有一定的参考价值。
前言
try-with-resouce写法是在JDK1.7引入的一个语法糖,用来进行io数据流关闭的简易写法。
常见的Java关闭IO数据流的写法
在JDK 1.7之前,我们先看一下常见的写法
String readTextFromFile(String path) {
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line).append("\\n");
}
br.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
看readTextFromFile这个方法,从一个文件中用BufferedReader读取数据内容并返回一个字符串,这是一个非常传统与标准的io读取与关闭的写法,利用finally机制,因为finally一定会被执行,所以可以保证资源一定被释放,同时因为close方法会抛出一个异常,所以要在finally里添加try-catch用来处理这个异常,整体来看十分臃肿和繁琐。
try-with-resources写法
在 JDK 1.7开始,为我们提供了以中便捷的关闭io流的方法
String readTextFromFile(String path){
StringBuilder sb=new StringBuilder();
try(BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(path)))){
String line=null;
while((line=br.readLine())!=null){
sb.append(line).append("\\n");
}
return sb.toString();
}
catch(IOException e){
e.printStackTrace();
}
return sb.toString();
}
可以看到,没有了finally,没有了close调用,感觉代码缩短了一半,而这些只是需要你在实例化BufferedReader的时候放在try中
try(BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(path)))){
}
原理
我们看一下使用try-with-resources的写法编译后的字节码再反编译之后的样子
String readTextFromFile(String path) {
StringBuilder sb = new StringBuilder();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
String var5;
try {
String line = null;
while(true) {
if ((line = br.readLine()) == null) {
var5 = sb.toString();
break;
}
sb.append(line).append("\\n");
}
} catch (Throwable var7) {
try {
br.close();
} catch (Throwable var6) {
var7.addSuppressed(var6);
}
throw var7;
}
br.close();
return var5;
} catch (IOException var8) {
var8.printStackTrace();
return sb.toString();
}
}
可以看到这个跟我们标准的Java io流关闭的写法还是差不多的,只不过没有使用finally机制,而是在各种catch中进行close方法的调用,可以看到try-with-resouce其实就是一个语法糖,由编译器在编译为字节码的时候为你自动添加了close方法调用,使你更关注于逻辑,也使代码显得更加整洁。那么既然是语法糖,我们自己能不能利用这个语法特性呢?先看一下Reader的源码,
可以看到Reader实现了Closeable接口,这个接口有一个close方法,也即是我们调用的BufferedReader的close方法,再看Closeable接口
可以看到Closeable接口继承自AutoCloseble接口,自动可关闭对象?是不是有那个味道了?进入这个接口,可以看到这个类的注释
/**
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
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
*/
可以看到,注释里明确说明,如果实现了这个接口,那么就可以使用try-with-resource这种语法用来自动关闭。这里其实有个小问题,就是Closeable接口继承自AutoCloseabl,同时在Cloaseable中也声明了close方法,但是会抛出一个IOException,不同于AutoCloseable中close方法抛出的Exception,刚开始不太明白这种写法的含义,目前来看通过这种方式缩减了所有IO操作关注的异常范围,只关注IOException,避免异常范围过大导致的异常指向不明确。
通过实现AutoCloseable接口,我们就可以享受try-with-resources带来的语法便利。我们定义一个AutoCloseClass类来验证一下
public class Test {
public static void main(String[] args) {
try(AutoCloseClass d=new AutoCloseClass()){
System.out.println("hello world");
}
catch(Exception e){
e.printStackTrace();
}
}
public static class AutoCloseClass implements AutoCloseable{
@Override
public void close() throws IOException {
System.out.println("close honey");
}
}
}
可以看到先打印 hello world,然后打印close honey
kotlin写法
现如今Kotlin已经作为android开发的第一语言,那么在Kotlin中有没有类似的语法呢?实际上也是有的,有一个内联的扩展方法,use,它就是来做相同的事情的。
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
var exception: Throwable? = null
try {
return block(this)
} catch (e: Throwable) {
exception = e
throw e
} finally {
when {
apiVersionIsAtLeast(1, 1, 0) -> this.closeFinally(exception)
this == null -> {}
exception == null -> close()
else ->
try {
close()
} catch (closeException: Throwable) {
// cause.addSuppressed(closeException) // ignored here
}
}
}
}
可以看到use是一个内联的泛型扩展函数,接收者为一个实现Closeable的接口类型T,传入一个函数类型,接收泛型参数T,然后在finally中调用close方法进行关闭。
总结
try-with-resources是一个很有用的语法糖,而且在《Effective Java》中也被推荐使用来进行io流的关闭
更多相关的Android面试题可以点击蓝色字体获得
以上是关于面试官:“来,你会try-with-resource写法吗”?的主要内容,如果未能解决你的问题,请参考以下文章