try-with-resources是Java SE7的一个新特性。
用try-with-resources语句确保资源关闭
try-with-resources语句是一种声明了一种或多种资源的try语句。资源是指在程序用完了之后必须要关闭的对象。任何实现了AutoCloseable接口和Closeable接口的对象,都可以当作资源使用。
在Java SE7之前,需要用finally代码块来手动关闭资源,无论try语句正常结束还是异常结束,都会执行finally代码块的内容。example1从键盘读取一行输入,并在finally中释放BufferedReader资源。
// example1
static String myReadLineWithFinally() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
return br.readLine();
} finally {
if (br != null) {
br.close();
}
}
}
复制代码
Java SE7以后,可以用try-with-resources代替try-catch-finally。在example2中,try-with-resources语句声明的是BufferedReader资源。声明语句紧跟着try关键字后的圆括号里。无论try语句是正常结束还是异常结束(比如readLine方法抛出一个IOException异常),它都会被自动关闭。
// example2
static String myReadLine() throws IOException {
try (BufferedReader br =
new BufferedReader(new InputStreamReader(System.in));) {
return br.readLine();
}
}
复制代码
example3用try-with-resources自动关闭java.sql.Connection
对象和java.sql.Statement
,关闭的顺序是先Statement
,后Connection
。
// example3
try (Connection con = DriverManager.getConnection("jdbc:calcite:", config)) {
try (Statement stmt = con.createStatement()) {
try (ResultSet resultSet = stmt.executeQuery(sql)) {
output(resultSet);
}
}
}
复制代码
也可以自己创建资源(只需要实现java,lang.AutoCloseable
接口或java.io.Closeable
接口),然后在try-with-resources结构里声明、使用自己的资源。
// example4
public class Test{
public static void main(String[] args) throws Exception {
try (MyResources mr = new MyResources();) {
mr.work();
}
// 控制台输出
// MyResources is working
// MyResources is closed
}
}
class MyResources implements AutoCloseable {
public void work() {
System.out.println("MyResources is working");
}
@Override
public void close() throws Exception {
// TODO Auto-generated method stub
System.out.println("MyResources is closed ");
}
}
复制代码
被压抑的异常
在try-finally语句中,如果try和finally中都发生异常,那么finally只会抛出发生在finally中的异常,try里的异常将会被抑制。如example3所示,会抛出java.io.IOException: Stream closed
异常,而java.lang.ArithmeticException: / by zero
异常被抑制。
// example5
static String myReadLineWithFinally() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
int x = 1 / 0; // java.lang.ArithmeticException: / by zero
return br.readLine();
} finally {
if (br != null) {
br.close();
}
br.read(); // java.io.IOException: Stream closed
}
}
复制代码
在try-with-resources中,如果在圆括号里和代码块里都发生了异常,圆括号里的异常会向外传播,这与旧风格相反。在example4中,抛出的是 java.io.FileNotFoundException
而不是java.lang.ArithmeticException: / by zero
// example6
static void printFile() throws FileNotFoundException, IOException {
try (FileInputStream input = new FileInputStream("not_exist.txt")) {// java.io.FileNotFoundException:
int x = 1 / 0;
}
}
复制代码
当然,try-with-resouces语句也可以有catch和finally代码块。在try-with-resources语句中,任何的catch和finally代码块都在所有被声明的资源被关闭后执行。
使用多个资源
可以在try-with-resources中声明多个资源,这些资源都能被自动地关闭。关闭的顺序是创建顺序的逆序。如example5,先关闭BufferedReader
,再关闭FileInputStream
。
// example7
static void multiSources() throws IOException {
try (FileInputStream input = new FileInputStream("D://file.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));) {
int data = input.read();
String line = br.readLine();
System.out.println(data + " " + line);
}
}
复制代码