《Java从小白到大牛》纸质版已经上架了!!!html
有时在try-catch语句中会占用一些非Java资源,如:打开文件、网络链接、打开数据库链接和使用数据结果集等,这些资源并不是Java资源,不能经过JVM的垃圾收集器回收,须要程序员释放。为了确保这些资源可以被释放可使用finally代码块或Java 7以后提供自动资源管理(Automatic Resource Management)技术。java
try-catch语句后面还能够跟有一个finally代码块,try-catch-finally语句语法以下:程序员
try{ //可能会生成异常语句 } catch(Throwable e1){ //处理异常e1 } catch(Throwable e2){ //处理异常e1 } catch(Throwable eN){ //处理异常eN } finally{ //释放资源 }
不管try正常结束仍是catch异常结束都会执行finally代码块,如同14-2所示。数据库
使用finally代码块示例代码以下:网络
//HelloWorld.java文件 package com.a51work6; … … public class HelloWorld { public static void main(String[] args) { Date date = readDate(); System.out.println("读取的日期 = " + date); } public static Date readDate() { FileInputStream readfile = null; InputStreamReader ir = null; BufferedReader in = null; try { readfile = new FileInputStream("readme.txt"); ir = new InputStreamReader(readfile); in = new BufferedReader(ir); // 读取文件中的一行数据 String str = in.readLine(); if (str == null) { return null; } DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); Date date = df.parse(str); return date; } catch (FileNotFoundException e) { System.out.println("处理FileNotFoundException..."); e.printStackTrace(); } catch (IOException e) { System.out.println("处理IOException..."); e.printStackTrace(); } catch (ParseException e) { System.out.println("处理ParseException..."); e.printStackTrace(); } finally { ① try { if (readfile != null) { readfile.close(); ② } } catch (IOException e) { e.printStackTrace(); } try { if (ir != null) { ir.close(); ③ } } catch (IOException e) { e.printStackTrace(); } try { if (in != null) { in.close(); ④ } } catch (IOException e) { e.printStackTrace(); } } ⑤ return null; } }
上述代码第①行~第⑤行是finally语句,在这里经过关闭流释放资源,FileInputStream、InputStreamReader和BufferedReader是三个输入流,它们都须要关闭,见代码第②行~第④行经过流的close()关闭流,可是流的close()方法还有能够能发生IOException异常,因此这里又针对每个close()语句还须要进行捕获处理。框架
注意 为了代码简洁等目的,可能有的人会将finally代码中的多个嵌套的try-catch语句合并,例如将上述代码改为以下形式,将三个有能够发生异常的close()方法放到一个try-catch。读者本身考虑一下这处理是否稳妥呢?每个close()方法对应关闭一个资源,若是第一个close()方法关闭时发生了异常,那么后面的两个也不会关闭,所以以下的程序代码是有缺陷的。ide
try {
... ...优化
} catch (FileNotFoundException e) {设计
... ...code
} catch (IOException e) {
... ...
} catch (ParseException e) {
... ...
} finally {
try {
if (readfile != null) {
readfile.close();
}
if (ir != null) {
ir.close();
}
if (in != null) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
### 自动资源管理 {#-0} 14.4.1节使用finally代码块释放资源会致使程序代码大量增长,一个finally代码块每每比正常执行的程序还要多。在Java 7以后提供自动资源管理(Automatic Resource Management)技术,能够替代finally代码块,优化代码结构,提升程序可读性。 自动资源管理是在try语句上的扩展,语法以下: ```java try (声明或初始化资源语句) { //可能会生成异常语句 } catch(Throwable e1){ //处理异常e1 } catch(Throwable e2){ //处理异常e1 } catch(Throwable eN){ //处理异常eN }
在try语句后面添加一对小括号“()”,其中是声明或初始化资源语句,能够有多条语句语句之间用分号“;”分隔。
示例代码以下:
//HelloWorld.java文件 package com.a51work6; … … public class HelloWorld { public static void main(String[] args) { Date date = readDate(); System.out.println("读取的日期 = " + date); } public static Date readDate() { // 自动资源管理 try (FileInputStream readfile = new FileInputStream("readme.txt"); ① InputStreamReader ir = new InputStreamReader(readfile); ② BufferedReader in = new BufferedReader(ir)) { ③ // 读取文件中的一行数据 String str = in.readLine(); if (str == null) { return null; } DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); Date date = df.parse(str); return date; } catch (FileNotFoundException e) { System.out.println("处理FileNotFoundException..."); e.printStackTrace(); } catch (IOException e) { System.out.println("处理IOException..."); e.printStackTrace(); } catch (ParseException e) { System.out.println("处理ParseException..."); e.printStackTrace(); } return null; } }
上述代码第①行~第③行是声明或初始化三个输入流,三条语句放到在try语句后面小括号中,语句之间用分号“;”分隔,这就是自动资源管理技术了,采用了自动资源管理后再也不须要finally代码块,不须要本身close这些资源,释放过程交给了JVM。
注意 全部能够自动管理的资源须要实现AutoCloseable接口,上述代码中三个输入流FileInputStream、InputStreamReader和BufferedReader从Java 7以后实现AutoCloseable接口,具体哪些资源实现AutoCloseable接口须要查询API文档。
throws与声明方法抛出异常 {#throws}
在一个方法中若是可以处理异常,则须要捕获并处理。可是本方法没有能力处理该异常,捕获它没有任何意义,则须要在方法后面声明抛出该异常,通知上层调用者该方法有能够发生异常。
方法后面声明抛出使用throws关键字,回顾一下10.3.3节成员方法语法格式以下:
class className { [public | protected | private ] [static] [final | abstract] [native] [synchronized] type methodName([paramList]) [throws exceptionList] { //方法体 } }
其中参数列表以后的[throws exceptionList]语句是声明抛出异常。方法中可能抛出的异常(除了Error和RuntimeException及其子类外)都必须经过throws语句列出,多个异常之间采用逗号(,)分隔。
注意 若是声明抛出的多个异常类之间有父子关系,能够只声明抛出父类。但若是没有父子关系状况下,最好明确声明抛出每个异常,由于上层调用者会根据这些异常信息进行相应的处理。假如一个方法中有可能抛出IOException和ParseException两个异常,那么声明抛出IOException和ParseException呢?仍是只声明抛出Exception呢?由于Exception是IOException和ParseException的父类,只声明抛出Exception从语法是容许的,可是声明抛出IOException和ParseException更好一些。
若是将14.3节示例进行修改,在readDate()方法后声明抛出异常,代码以下:
//HelloWorld.java文件 package com.a51work6; … … public class HelloWorld { public static void main(String[] args) { ① try { Date date = readDate(); ② System.out.println("读取的日期 = " + date); } catch (IOException e) { ③ System.out.println("处理IOException..."); e.printStackTrace(); } catch (ParseException e) { ④ System.out.println("处理ParseException..."); e.printStackTrace(); } } public static Date readDate() throws IOException, ParseException { ⑤ // 自动资源管理 FileInputStream readfile = new FileInputStream("readme.txt"); ⑥ InputStreamReader ir = new InputStreamReader(readfile); BufferedReader in = new BufferedReader(ir); // 读取文件中的一行数据 String str = in.readLine(); ⑦ if (str == null) { return null; } DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); Date date = df.parse(str); ⑧ return date; } }
因为readDate()方法中代码第⑥、⑦、⑧行都有可能引起异常。在readDate()方法内又没有捕获处理,全部须要在代码第⑤行方法后声明抛出异常,事实上有三个异常FileNotFoundException、IOException和ParseException,因为FileNotFoundException属于IOException异常,因此只声明IOException和ParseException就能够了。
一旦readDate()方法声明抛出了异常,那么它的调用者main()方法,也会面临一样的问题:要么捕获本身处理,要么抛出给上层调用者。若是一旦发生异常main()方法也选择抛出那么程序运行就会终止。本例中main()方法是捕获异常进行处理,捕获异常过程前面已经介绍过了,这里再也不赘述。
有些公司为了提升代码的可重用性,本身开发了一些Java类库或框架,其中少不了本身编写了一些异常类。实现自定义异常类须要继承Exception类或其子类,若是自定义运行时异常类需继承RuntimeException类或其子类。
实现自定义异常类示例代码以下:
package com.a51work6; public class MyException extends Exception { ① public MyException() { ② } public MyException(String message) { ③ super(message); } }
上述代码实现了自定义异常,自定义异常类通常须要提供两个构造方法,一个是代码第②行的无参数的默认构造方法,异常描述信息是空的;另外一个是代码第③行的字符串参数的构造方法,message是异常描述信息,getMessage()方法能够得到这些信息。
自定义异常就这样简单,主要是提供两个构造方法就能够了,
Java异常相关的关键字中有两个很是类似,它们是throws和throw,其中throws关键字前面14.5节已经介绍了,throws用于方法后声明抛出异常,而throw关键字用来人工引起异常。本节以前读者接触到的异常都是因为系统生成的,当异常发生时,系统一个异常对象,并将其抛出。但也能够经过throw语句显式抛出异常,语法格式以下:
throw Throwable或其子类的实例
全部Throwable或其子类的实例均可以经过throw语句抛出。
显式抛出异常目的有不少,例如不想某些异常传给上层调用者,能够捕获以后从新显式抛出另一种异常给调用者。
修改14.4节示例代码以下:
//HelloWorld.java文件 package com.a51work6; … … public class HelloWorld { public static void main(String[] args) { try { Date date = readDate(); System.out.println("读取的日期 = " + date); } catch (MyException e) { System.out.println("处理MyException..."); e.printStackTrace(); } } public static Date readDate() throws MyException { // 自动资源管理 try (FileInputStream readfile = new FileInputStream("readme.txt"); InputStreamReader ir = new InputStreamReader(readfile); BufferedReader in = new BufferedReader(ir)) { // 读取文件中的一行数据 String str = in.readLine(); if (str == null) { return null; } DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); Date date = df.parse(str); return date; } catch (FileNotFoundException e) { ① throw new MyException(e.getMessage()); ② } catch (IOException e) { ③ throw new MyException(e.getMessage()); ④ } catch (ParseException e) { System.out.println("处理ParseException..."); e.printStackTrace(); } return null; } }
若是软件设计者不但愿readDate()方法中捕获的FileNotFoundException和IOException异常出如今main()方法(上层调用者)中,那么能够在捕获到FileNotFoundException和IOException异常时,经过throw语句显式抛出一个异常,见代码第②行和第④行throw new MyException(e.getMessage())语句,MyException是自定义的异常。
注意 throw显式抛出的异常与系统生成并抛出的异常,在处理方式上没有区别,就是两种方法:要么捕获本身处理,要么抛出给上层调用者。在本例中是声明抛出,因此在readDate()方法后面要声明抛出MyException异常。
本章小结
本章介绍了Java异常处理机制,其中包括Java异常类继承层次、捕获异常、释放资源、throws、throw和自定义异常类。读者须要重点掌握捕获异常处理,熟悉throws和throw的区分和用法。
http://edu.51cto.com/topic/1246.html
http://www.zhijieketang.com/group/5