12.7 Java标准异常
Throwable可以表示任何作为异常被抛出的类,其可分为两类对象:Error和Exception。
Error表示编译时和系统错误,一般不需关心;
Exception表示可以被抛出的基本类型,通常关心该类型。
异常的名称都是可以望文知意的。
12.7.1 特例:RuntimeException
运行时异常由Java虚拟机自动抛出,不必在异常说明中列出,在编译时也不检查这类异常,也无需捕获这类异常。
12.8 使用finally进行清理
finally子句,无论try块中是否抛出异常,finally子句中的代码都会被执行。
try {
// The guarded region: Dangerous activities
// that might throw A, B or C
} catch(A a1) {
// Handler for situation A
} catch(B b1) {
// Handler for situation B
} catch(C c1) {
// Handler for situation C
} finally {
// Activities that happen every time
}
12.8.1 finally用来做什么
把除内存之外的资源恢复到初始状态,就需要用到finally子句。如:
1) 已经打开的文件或网络连接;
2) 在屏幕上画的图形;
3) 外部世界的某个开关。
12.8.2 在return中使用finally
因为finally子句总是会被执行,所以在一个方法中,可以从多个点返回,并且可以保证重要的清理工作仍旧会被执行。
package com.mzm.chapter12;
/**
* Created by 蒙卓明 on 2017/10/22.
*/
public class MultipleReturns {
public static void f(int i){
System.out.println("Initialization that requires cleanup");
try{
System.out.println("Point 1");
if(i == 1){
return;
}
System.out.println("Point 2");
if(i == 2){
return;
}
System.out.println("Point 3");
if(i == 3){
return;
}
System.out.println("End");
return;
} finally {
System.out.println("Performing cleanup");
}
}
public static void main(String[] args){
for(int i = 1; i <= 4; i++){
f(i);
}
}
}
12.8.3 缺憾:异常丢失
在某些情况下使用finally子句,可使异常被忽略。
package com.mzm.chapter12;
/**
*
*/
public class LostMessage {
void f() throws VeryImportantException {
throw new VeryImportantException();
}
void dispose() throws HoHumException {
throw new HoHumException();
}
public static void main(String[] args) throws HoHumException {
try{
LostMessage lm = new LostMessage();
try{
lm.f();
} finally {
lm.dispose();
}
}catch (Exception e) {
System.out.println(e);
}
}
}
class VeryImportantException extends Exception{
public String toString(){
return "A very important exception!";
}
}
class HoHumException extends Exception{
public String toString(){
return "A trivial exception";
}
}
VeryImportantException消失,其被finally子句中的HoHumException所取代。
package com.mzm.chapter12;
/**
* 丢失异常
*
*/
public class ExceptionSilencer {
public static void main(String[] args){
try{
throw new RuntimeException();
} finally {
//异常被忽略
return;
}
}
}
12.9 异常的限制
当覆盖方法时,只能抛出在父类方法的异常说明中所列的异常,也可以不抛异常,只是不能抛出父类相应方法异常说明之外的异常。
针对构造器而言,子类的构造器的异常说明必须包含父类的构造器的异常说明,并且不能捕获父类构造器抛出的异常。
不能基于异常说明来重载方法。
12.10 构造器
在构造器中出现异常的情况,不要再finally子句中执行清理工作。
package com.mzm.chapter12;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
* Created by 蒙卓明 on 2017/10/28.
*/
public class InputFile {
private BufferedReader in;
public InputFile(String fname) throws FileNotFoundException {
try {
in = new BufferedReader(new FileReader(fname));
} catch (FileNotFoundException e) {
System.out.println("Could not open " + fname);
throw e;
} catch (Exception e) {
try{
in.close();
} catch (IOException e1) {
System.out.println("in.close() unsuccessful");
}
throw e;
} finally {
//不建议在此处执行清理工作,因为文件未成功打开
}
}
/**
* 获取文件的下一行
* @return 文件的下一行内容的字符串
*/
public String getLine() {
String s;
try{
s = in.readLine();
} catch (IOException e) {
throw new RuntimeException("readLine() failed");
}
return s;
}
public void dispose() {
try{
in.close();
System.out.println("dispose() successful");
} catch (IOException e) {
throw new RuntimeException("in.close() failed");
}
}
}
12.11 异常匹配
抛出异常时,异常系统会按照就近原则找出最近的处理程序。原则上再编写代码时,子异常类在前,父异常类在后。
12.12 其他可选方式
开发异常程序的初衷是为了方便程序员处理错误。
异常处理的重要原则:只有在知道如何处理的情况下才捕获异常。
异常处理的目标:将异常发生地点与异常处理代码分离。
12.12.3 把异常传递给控制台
即在main()方法上加上异常说明,但是此种方式不推荐。
12.12.4 把”被检查的异常”转换为”不检查的异常”
实际上就是异常转型,将编译时异常转型成为运行时异常。
try {
// ... to do somrthing useful
} catch (IDontKonwWhatToDoWithThisCheckedException e) {
throw new RuntimeException(e);
}
12.13 异常使用指南
1) 在知道如何处理的情况下才捕获异常;
2) 解决问题并且重新调用产生异常的方法;
3) 进行少许修补,然后绕过异常发生的地方继续执行;
4) 用别的数据进行计算,以代替方法预计会返回的值;
5) 把当前运行环境下能做的事情尽量做完,然后把相同的异常抛到更高层;
6) 把当前运行环境下能做的事情尽量做完,然后把不同的异常抛到更高层;
7) 终止程序;
8) 进行简化;
9) 让类库和程序更安全。