抛出异常的作用
- 通过规定某种必须保证的形式来防止随心所欲的编程导致的问题,降低处理代码错误的复杂度。
- 异常是对一种“知道这么做不对,但是代码无法立马解决的”情况的描述
- 异常将每件事都当做一个事务,作为每个事务的底线维护它们的逻辑稳定性。
- 一旦异常发生,就不允许程序按照正常模式执行下去。
基本异常
- 使用
throw
抛出异常对象的引用,异常对象的名字一般以Exception
结尾 - 抛出异常之后,会发生什么?
- 使用
new
在堆上创建异常对象
- 停止当前执行路径,抛出
异常对象
的引用 - 异常机制接管程序,在异常处理程序中继续管理的运行,然后使程序要么换个方式继续运行,要么继续运行
- 例子
if(t == null) throw new NullPointerException();
异常参数
- 异常对象的根类:
Throwable
,一般情况下,异常的错误信息可以保存在异常对象的内部,明显的错误也可以通过对象的特定名字来表示 - 虽然
throw
方法和return
方法在语义上有些相似,都是退出某个作用域,并返回一个对象,但是return
返回的是函数压栈的起始位置,而throw
则是不确定的,可能会跨越方法的栈
异常捕获
try
+catch(CatchType catchid)
,一个try
可以抛出多种异常,但是一个catch
只能接受一种,因此一个try
可以带一系列的catch
try{
}catch(Type1 id1){
}catch(Type2 id2){
}catch(Type3 id3){
}
终止模型与恢复模型
- 终止模型:异常错误很关键,程序无法再返回到异常发生的地方继续
- 恢复模型:
- 不抛出异常,在发现异常的时候,调用方法修复
- 把
try...catch
放到while
循环中,直到没有异常。这会导致代码耦合程度高,让开发人员承担维护人员的职责。
创建自定义异常
- 异常类只能通过继承实现
- 在抛出异常的方法名字后面要加上
throws xxxException
的关键字,这代表着在抛出异常之后,该程序还能继续往下执行(一定要继续往下,因为还没有到catch
的位置)
class SimpleException extends Exception{}
public class InheritingException{
public void f() throws SimpleException{System.out.println("Throw SimpleException from f()");}
throw new SimpleException();
}
public static void main(String[] args){
InheritingExceptions sed = new InheritingExceptions();
try{
sed.f();
}catch(SimpleExceptions e){
System.err.println("Caught it!");
}
}
- 对于大多数异常对象来说,最重要的是类的名字,因此很多自定义的异常其实相当于一个重命名
- 异常调用的
printStackTrace(object o)
方法可以将从方法调用处到异常抛出处的方法调用序列
异常与记录日志
package com.exception;
import java.util.logging.*;
import java.io.*;
class LoggingException extends Exception{
private static Logger logger = Logger.getLogger("LoggingException");
public LoggingException(){
System.out.println(123);
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("Caught "+ e);
}
}
}
Logger
对象会将接收到的信息发送给System.err
,想要获取printStackTrace()
的内容,我们可以通过io
类中的PrintWriter
对象来接受printStackTrace
中的信息,然后通过logger.xxx
的方法来写入到日志中。- 当然,异常类也可以当做普通类来进行扩展,如下所示
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 int String getMessage(){
return "Detail Message: "+x+" "+super.getMessage();
}
}
public class ExtraFeatures{
public static void f() throws MyException2{
print("Throwing MyException2 from f()");
throw new MyException2();
}
public static void g() throws MyException2{
print("Throwing MyException2 from g()");
throw new MyException2("Originated in g");
}
public static void h() throws MyException2{
print("Throwing MyException2 from h()");
throw new MyException2("h");
}
}
参考