世界上存在永远不会出现错误的程序吗?也许这只会出现在程序员的梦中。随着软件的诞生,异常就如影随形的围绕着我们,所以,只有正确处理好程序的意外情况,才能有效的避免这些异常。
Java的基本理念是:"结构不佳的代码不能运行",我们有的时候会很反感异常的出现,因为其代表着我们的程序出现了某种"错误",而我们并不希望我们的程序出现错误。
发现错误的理想时机是在编译阶段,但某些情况下编译时期并不能发现所有的异常,有些异常需要运行时去发现。
异常使得我们可以将每件事情都当作一件事务来处理,要么都执行,要么都rollback。
Exception 表示着程序出现了某种意外情况,java.lang.Exception 继承于 java.lang.Throwable,Exception又分为可检查异常(checked)和不可检查异常(unchecked)。
可检查异常(checked)在代码中必须显示的进行处理,这是编译期检查的一部分,需要使用try…catch 进行捕获,或者使用try…finally 进行资源回收
不可检查异常(unchecked)是在程序运行时候的异常,RuntimeException中都是不可检查异常,类似的NullPointerException,ArraysIndexOutOfBoundsException,通常是可以通过编码避免的错误,并不会在编译期强制要求。
Exception类的继承关系:
Error 是指系统出现的崩溃的现象,要比Exception 级别高
java.lang.Error 也是继承于 java.lang.Throwable,它不能够被程序捕获,大部分的错误都是处于非正常环境下
ThreadDeath的错误,即使是正常的环境,也是一个错误,也不能够被捕获
Error类之间的继承关系:
jdk1.7之前我们使用try…catch…的代码是这样的
private static void printFile() throws IOException{
InputStream input = null;
try{
input = new FileInputStream("file.txt");
int data = input.read();
while(data != -1){
System.out.print((char) data);
data = input.read();
}
} finally{
if(input != null){
input.close();
}
}
}
上述代码可能会产生IOException。
类似的抛出异常的情况比较多的情况下,会产生很多try…catch的样板代码,非常不利于维护,也会造成代码冗余,有没有好的改进方式呢?
Try-with-resources是java7中一个新的异常处理机制,它能够很容易地关闭在try-catch语句块中使用的资源。它能够声明1到多个资源的try语句,资源是指执行完成后必须要close掉的对象。
private static void printFileJava7() throws IOException{
try(FileInputStream input = new FileInputStream("file.txt")) {
int data = input.read();
while(data!=-1){
System.out.print((char) data);
data = input.read();
}
}
}
注意代码中的try 语句块的内容:
try(FileInputStream input = new FileInputStream("file.txt")) {
这就是try-with-resource 结构的用法。FileInputStream 类型变量就在try关键字后面的括号中声明。而且一个FileInputStream 类型被实例化并被赋给了这个变量。
当try语句块运行结束时,FileInputStream 会被自动关闭。这是因为FileInputStream 实现了java中的java.lang.AutoCloseable接口。所有实现了这个接口的类都可以在try-with-resources结构中使用。
你可以在块中使用多个资源而且这些资源都能被自动地关闭。下面是例子:
private static void printFileJava7() throws IOException{
try( FileInputStream input =new FileInputStream("file.txt");
BufferedInputStream bufferedInput = new BufferedInputStream(input)
) {
int data = bufferedInput.read();
while(data!=-1){
System.out.print((char) data);
data = bufferedInput.read();
}
}
}
上述例子创建了两个资源: FileInputStream 和 BufferedInputStream,当程序离开try 语句块的时候,资源被关闭。
实现了AutoClosable的类就能够使用try-with-resources进行资源关闭,AutoCloseable 仅有一个方法
实现了此接口的类能够持有资源直到被关闭的时候。其中的close()方法是自动关闭的,当离开try-with-resources中的try 语句块的时候。这种方式确保了能够即使释放资源,避免资源的枯竭和可能出现的错误
public interface AutoCloseable{
void close() throws Exception;
}
代码示例
public class AutoCloseResources implements AutoCloseable{
public void doSomething(){
System.out.println("doSomething...");
}
// 重写close方法,此方法能够被隐性调用
@Override
public void close() throws Exception{
System.out.println("AutoCloseResources.close()");
}
}
public class test{
public static void main(String[] args) throws Exception{
try(AutoCloseResources acr = new AutoCloseResources()){
acr.doSomething();
}
}
}
输出:
doSomething...
AutoCloseResources.close()
由此可见,close()方法并没有显示被调用,当离开try语句块的时候隐式被调用了。
通过上面这些你可以看到,不论try-catch中使用的资源是自己创造的还是java内置的类型,try-with-resources都是一个能够确保资源能被正确地关闭的强大方法。