《java编程思想》读书笔记-异常

12.1.概念
看看百度百科的说法

12.2.基本异常
抛出异常以后会发生什么?首先使用new 在堆上创建异常对象,然后当前的执行被终止,并且弹出对异常对象的“引用”。此时异常处理机制接管程序,他的任务是使程序从错误张太重恢复,使程序要么换一种方式运行,要么继续运行下去。(好像和没说一样啊)

12.2.1异常参数
java的异常对象,也是一个对象,他有两个构造器。一个是默认无参构造器、另一个是传入一个字符串的构造器,这个字符串就是异常的报错信息。

12.3.捕获异常
12.3.1try块
try块的作用是捕获并处理异常,当有一段代码(或者其内部调用的方法)会抛出异常时,你可以选择继续向上抛出异常,要么就通过try包括可能出现异常的代码块。
12.3.2异常处理程序
异常是通过catch捕获的,catch内是抛出异常的类型或者其父类型。catch有点像switch
里的case,而且是每个case结束判断后有break形式,一旦捕获到一个异常就不能继续捕获后续的异常。
12.3.3终止与恢复
异常处理理论有两种模型,java支持终止模型。这种模型中,异常出现后程序不能到发生异常的地方继续执行。
另一种是恢复模型,希望出现异常后能修正错误。但是想要恢复代码使其争取执行,无疑需要出错的相关信息,导致代码的耦合性大大增加。因此不实用。

12.4.创建自定义异常
有时候,java本身提供的异常类可能不能描述你的异常,那么你可以自定义异常类。

class SimpleException extends Exception {}
public class InheritingExceptions {
	public void f() throws SimpleException {
		System.out.println("Throw  impleException from f()");
		throw new SimpleException();
	}
	public static void main(String [] args) {
		InheritingExceptions sed=new InheritingExceptions();
		try {
			sed.f();
		}
		catch(SimpleException e) {
			System.out.println("caught it!");
		}
	}
}
/*
Throw  impleException from f()
caught it!
*/

可以为异常类定义一个接受字符串参数的构造器

package exception;

class MyException extends Exception {
	public MyException() {
	}

	public MyException(String msg) {
		super(msg);
	}
}

public class FullConstructors {
	public static void f() throws MyException {
		System.out.println("Throw MyException from f()");
		throw new MyException();
	}

	public static void g() throws MyException {
		System.out.println("Throw MyException from g()");
		throw new MyException();
	}

	public static void main(String[] args) {
		try {
			f();
		} catch (MyException e) {
			e.printStackTrace(System.out);
		}
		try {
			g();
		} catch (MyException e) {
			e.printStackTrace(System.out);
		}

	}

}
/*
Throw MyException from f()
exception.MyException
	at exception.FullConstructors.f(FullConstructors.java:15)
	at exception.FullConstructors.main(FullConstructors.java:25)
Throw MyException from g()
exception.MyException
	at exception.FullConstructors.g(FullConstructors.java:20)
	at exception.FullConstructors.main(FullConstructors.java:30)

*/

在异常处理程序中,调用了在throwable类生命的printStachTrace()方法。就像从输出中看到的,他将打印“从方法调用出到异常抛处的方法调用序列”。这里信息被发送到了System.out,并自动打印出来,但是如果不适用参数的话,信息则被发送到标准错误流。

12.4.1异常与记录日志 ((1)了解即可,(2)的getMessage可以看一下)
使用java.util.logging 工具包记录日志

package exception;
 
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Logger;

class LoggingException extends Exception {
	private static Logger logger = Logger.getLogger("LoggingException");

	public LoggingException() {
		StringWriter trace = new StringWriter();
		printStackTrace(new PrintWriter(trace));
		logger.severe(trace.toString());
	}
}

public class LoggingExceptions {
	public static void main(String []args) {
		try {
			throw new LoggingException();
		}catch(LoggingException e) {
			System.err.println("caught1 "+e);
		}
		try {
			throw new LoggingException();
		}catch(LoggingException e) {
			System.err.println("caught2 "+e);
		}
	}

}

/*
四月 26, 2019 2:10:06 下午 exception.LoggingException 
严重: exception.LoggingException
	at exception.LoggingExceptions.main(LoggingExceptions.java:20)

caught1 exception.LoggingException
四月 26, 2019 2:10:06 下午 exception.LoggingException 
严重: exception.LoggingException
	at exception.LoggingExceptions.main(LoggingExceptions.java:25)

caught2 exception.LoggingException

*/

我们将StringWriter对象传递给printWriter的构造器,通过toString()方法,我们就可以抽取一个String。(我也不明白啥意思,大概就是StringWriter trace = new StringWriter();
printStackTrace(new PrintWriter(trace));
logger.severe(trace.toString());这段代码能将错误信息转换成String罢了)
getMessage()看一下:

package exception;

class MyException2 extends Exception {
	private int x;

	public MyException2() {
	}

	public MyException2(String msg) {
		super(msg);
	}

	public MyException2(String msg, int x) {
		super(msg);
		this.x = x;
	}

	public int val() {
		return x;
	}

	public String getMessage() {
		return "Detail Message " + x + " " + super.getMessage();
	}
}

public class ExtreaFeatures {
	public static void f() throws MyException2 {
		System.out.println("Throwing MyException2 from f()");
		throw new MyException2("Driginated in f()");
	}

	public static void g() throws MyException2 {
		System.out.println("Throwing MyException2 from g()");
		throw new MyException2("Driginated in g()");
	}

	public static void h() throws MyException2 {
		System.out.println("Throwing MyException2 from h()");
		throw new MyException2("Driginated in h()", 6);
	}

	public static void main(String[] args) {
		try {
			f();
		} catch (MyException2 e) {
			e.printStackTrace(System.out);
		}
		try {
			g();
		} catch (MyException2 e) {
			e.printStackTrace(System.out);
		}
		try {
			h();
		} catch (MyException2 e) {
			e.printStackTrace(System.out);
			System.out.println("e.val()= " + e.val());
		}
	}

}

/*
Throwing MyException2 from f()
exception.MyException2: Detail Message 0 Driginated in f()
	at exception.ExtreaFeatures.f(ExtreaFeatures.java:25)
	at exception.ExtreaFeatures.main(ExtreaFeatures.java:37)
Throwing MyException2 from g()
exception.MyException2: Detail Message 0 Driginated in g()
	at exception.ExtreaFeatures.g(ExtreaFeatures.java:29)
	at exception.ExtreaFeatures.main(ExtreaFeatures.java:43)
Throwing MyException2 from h()
exception.MyException2: Detail Message 6 Driginated in h()
	at exception.ExtreaFeatures.h(ExtreaFeatures.java:33)
	at exception.ExtreaFeatures.main(ExtreaFeatures.java:49)
e.val()= 6
*/

这个异常增加了字段x,以及设定x的构造器。此外还覆盖了Throwable的getMessage()方法。getMessage方法一点类似toString()方法,从结果可以看出来我们可以打印出来。

12.5异常说明throws
java通过在接口或者方法上,对异常进行声明,来表示方法有哪些受检异常。
异常声明的形式应该是这样的
void f()throws TooBig,TooSmall,DivZero{…}

如果你在方法里面抛出(throw)异常的话,编译器会提示你应该throws这个异常,就像刚才的例子。此外,有些异常是不用抛出的,比如继承了RuntimeExecption的异常就不需要Throws声明异常。这种需要在方法上Throws的异常,我们称为受检异常。

12.6捕获所有异常
由于Exception是所有异常的子类,所以catch Exception就可以捕获到所有的异常

try{
...
}catch(Exception e){
...
}

实际上,这样使我们对出现的异常,得到的信息少之又少。但是如果只能捕获Exception的情况下,我们可以尽量获得更多的信息。Exception其父类Throwable有一些方法可以重用,String getMessage()、StringLocalizedMessage() void printStackTrace()等等,具体使用的例子我就不写了。
12.6.1栈轨迹
printStackTrace()方法所提供的信息可以通过getStackTrace()方法来访问,这个方法返回的是一个所调用方法名称构成的 数组。元素0是调用序列的最后调用的方法。

package exception;

public class WhoCalled {
	static void f() {
		try {
			throw new Exception();
		} catch (Exception e) {
			for (StackTraceElement ste : e.getStackTrace())
				System.out.println(ste.getMethodName());
		}

	}

	static void g() {
		f();
	}

	static void h() {
		g();
	}

	public static void main(String[] args) {
		f();
		System.out.println("-------------------------");
		g();
		System.out.println("-------------------------");
		h();

	}

    }
    
    /*

f
main
-------------------------
f
g
main
-------------------------
f
g
h
main
*/

在这里我们只打印了方法名字,需要其他信息可以 System.out.println(ste); 可以打印出错的位置你可以自己试一下。

12.6.2重新抛出异常
有时候希望把刚不获得异常重新抛出(适用于什么情况?),尤其在使用Exception,捕获异常的时候
既然已经得到了当前异常对象的引用可以直接把他抛出。

catch(Exception e){
throw e;
}

注意throw 抛出异常会使你抛出异常到上一级环境,此外同一个try块的后续catch子语句都被忽略。另外printStacjTrace()方法现实的是原异常抛出点的信息,而不是重新抛出点的信息,要想更新这个信息,可以调用fillInStackTrace()方法。
(1)例子:

package exception;

public class Rethrowing {
	public static void f() throws Exception {
		System.out.println("orignating the exceptioin in f()");
		throw new Exception("throw from f()");
	}

	public static void g() throws Exception {
		try {
			f();
		} catch (Exception e) {
			System.out.println("Inside g() ,e.printStackTrace()");
			e.printStackTrace(System.out);
			throw e;
		}
	}

	public static void h() throws Exception {
		try {
			f();
		} catch (Exception e) {
			System.out.println("Inside h() ,e.printStackTrace()");
			e.printStackTrace(System.out);
			throw (Exception) e.fillInStackTrace();
		}
	}

	public static void main(String[] args) {
		try {
			g();
		} catch (Exception e) {
			System.out.println("main1:printStackTrace()");
			e.printStackTrace(System.out);
		}
		try {
			h();
		} catch (Exception e) {
			System.out.println("main2:printStackTrace()");
			e.printStackTrace(System.out);
		}
	}

}
//注意"main1:printStackTrace()"、"main2:printStackTrace()"之后的结果
由于使用了方法e.fillInStackTrace(),抛出异常的位置在上层了。
/*
orignating the exceptioin in f()
Inside g() ,e.printStackTrace()
java.lang.Exception: throw from f()
	at exception.Rethrowing.f(Rethrowing.java:6)
	at exception.Rethrowing.g(Rethrowing.java:11)
	at exception.Rethrowing.main(Rethrowing.java:29)
main1:printStackTrace()
java.lang.Exception: throw from f()
	at exception.Rethrowing.f(Rethrowing.java:6)
	at exception.Rethrowing.g(Rethrowing.java:11)
	at exception.Rethrowing.main(Rethrowing.java:29)
orignating the exceptioin in f()
Inside h() ,e.printStackTrace()
java.lang.Exception: throw from f()
	at exception.Rethrowing.f(Rethrowing.java:6)
	at exception.Rethrowing.h(Rethrowing.java:20)
	at exception.Rethrowing.main(Rethrowing.java:35)
main2:printStackTrace()
java.lang.Exception: throw from f()
	at exception.Rethrowing.h(Rethrowing.java:24)
	at exception.Rethrowing.main(Rethrowing.java:35)

*/

(2)当你捕获到异常后再次抛出异常,对于第二个异常来说会丢失前一个异常的信息,他只是知道异常发生在第二次抛出异常的地方。
例子略。

12.6.3异常链
针对上面的情况,我们想要在捕获异常后抛出另一个异常,并且保存前一个异常的信息,这个思路就叫异常链。Throwable的子类的构造其中可以传一个参数进去。

============2019.4.30

你可能感兴趣的:(《java编程思想》笔记)