java.lang.Throwable

处理机制

当程序发生异常时会产生一个代表异常的对象
这个异常对象可能是当前程序创建的
也可能是JVM创建的
同时当前程序会将这个异常对象交给运行时系统
运行时系统会寻找相应的代码来处理异常对象
捕获:先捕获异常,再做处理
抛出:不处理异常继续抛出

捕获异常

被认为是一种积极的异常处理方式

过程

运行时系统得到一个异常对象后,会沿着方法调用栈逐层回溯,寻找处理这异常的代码
这一过程被称作 捕获异常 找到能够处理这种异常的代码后,运行时系统就将当前的异常对象交给代码进行处理
如果运行时系统找不到可以处理异常的代码,则运行系统将终止,这也将导致程序终止(JVM)退出

实现

try…catch….

System.out.println( “main begin …” );

  1. **int** a = 100 ;<br /> **int** b = 0 ;
  2. **try** {<br /> **int** c = a / b ; // 至此会触发异常,JVM创建表示该异常的对象,将该对象交给运行时系统处理<br /> **System**.out.println( a + " / " + b + " = " + c );
  3. // 运行时系统 会寻找 try 之后的 catch 语句块,<br /> // 如果 遇到 与异常对象的类型 匹配的语句块,则将该异常对象 传递 给该 catch 语句块<br /> } **catch**( **NullPointerException** e ) { // 注意,catch 后的 ( ) 中指定的实际上是个 形参<br /> **System**.out.println( e ); // 输出异常对象的字符串形式<br /> **System**.out.println( e.getClass() ); // 运行时类型<br /> } **catch**( **ArithmeticException** e ) {<br /> **System**.out.println( e ); // 输出异常对象的字符串形式<br /> **System**.out.println( "message : " + e.getMessage() );<br /> **System**.out.println( "cause : " + e.getCause() );<br /> **System**.out.println( e.getClass() ); // 运行时类型<br /> }
  4. **System**.out.println( "main end ." );<br /> }<br />//main begin ...<br />java.lang.ArithmeticException: / by zero<br />message : / by zero<br />cause : null<br />class java.lang.ArithmeticException<br />main end .

try…finally
public static void main(String[] args) {

  1. **System**.out.println( "main begin ..." );
  2. **int** a = 100 ;<br /> **int** b = 0 ;
  3. **try** {<br /> **System**.out.println( "- - - try - - -" );<br /> **int** c = a / b ; // 至此会触发异常,JVM创建表示该异常的对象,将该对象交给运行时系统处理<br /> **System**.out.println( a + " / " + b + " = " + c );<br /> } **finally** {<br /> **System**.out.println( "- - - finally - - -" );<br /> }
  4. **System**.out.println( "main end ." ); // **因为前面没有 catch 异常,所以这里不输出**<br /> }<br />**try...catch...finally**<br />**public** **static** **void** **main**(**String**[] args) {
  5. **System**.out.println( "main begin ..." );
  6. **Integer** a = 100 ;<br /> // Integer b = null ;<br /> **Integer** b = 0 ;
  7. **try** {<br /> **System**.out.println( "- - - try - - -" );<br /> **Integer** c = a / b ; // 至此会触发异常,JVM创建表示该异常的对象,将该对象交给运行时系统处理<br /> **System**.out.println( a + " / " + b + " = " + c );<br /> } **catch**( **NullPointerException** e ) {<br /> **System**.out.println( "空指针异常 : " + e.getMessage() );<br /> e.printStackTrace(); // 打印 栈 轨迹<br /> } **catch**( **ArithmeticException** e ) {<br /> **System**.out.println( "算术异常 : " + e.getMessage() );<br /> e.printStackTrace(); // 打印 栈 轨迹<br /> } **finally** {<br /> **System**.out.println( "- - - finally - - -" );<br /> }
  8. **System**.out.println( "main end ." );<br /> }

抛出异常

被认为是一种消极的异常处理方式
如果该异常没有try..catch处理,则导致当前方法立即终止执行 可以通过throw关键字显示抛出异常实例
也可以由JVM创建异常实例并抛出异常实例
异常类型之间使用逗号隔开 声明方法时,在方法参数列表之后通过throws关键字声明该方法可能抛出的异常类型。

  1. **Integer** a = 100 ;<br /> **Integer** b = 0 ;
  2. **Integer** r = divide( a , b );<br /> **System**.out.println( r );<br /> }
  3. /**<br /> * 实现 除法运算<br /> * @param dividend 被除数<br /> * @param divisor 除数<br /> * @return 返回 第一个参数 除以 第二个参数 的 商<br /> * @throws NullPointerException 声明方法可能抛出 空指针异常 ( NullPointerException )<br /> * @throws ArithmeticException 声明方法可能抛出 算术异常 ( ArithmeticException )<br /> */<br /> **public** **static** **Integer** divide( **Integer** dividend , **Integer** divisor ) **throws** **NullPointerException** , **ArithmeticException** {<br /> **Integer** result = dividend / divisor ; // 商 = 被除数 / 除数 ;<br /> **return** result ;

运行时异常和受检查异常

运行时异常:

也被称作 非受检查异常
凡是直接或间接继承国java.lang.RuntimeException类的异常类都是运行时异常
对于运行时异常来说,可以不显示使用try….catch…语句来处理该异常,那么要为相应的方法添加throws声明
某个方法内可能抛出运行时异常(但是没有捕获),该方法可以不适用throws关键字声明抛出异常

受检查异常

从来没有继承国java.lang.RuntimeExcetion
在编译中 收编译器检查,如果程序中存在没有处理的受检查异常,则编译器拒绝编译
对于 受检查异常 来说,源代码中要么通过try..catch…语句来捕获异常,要么为相应的方法添加throws声明
通过受检查异常 可以让程序员必须处理那些重要的程序缺陷
受检查异常也被称作 非运行时异常、设计时异常

在方法的声明中使用 throws 关键字声明抛出【受检查异常】

public static void main(String[] args) {

  1. **Integer** a = 100 ;<br /> **Integer** b = 0 ;
  2. **try** {<br /> // 作为 divide 方法的调用者,<br /> // 要么 main 方法继续声明抛出 ( throws )<br /> // 要么在 main 方法内部把 divide 方法所抛出的异常捕获( try...catch ),<br /> **Integer** r = divide( a , b );<br /> **System**.out.println( r );<br /> } **catch** (**Exception** e) {<br /> **System**.out.println( "出错了:" );<br /> e.printStackTrace();<br /> }
  3. **System**.out.println( "main end ." );<br /> }
  4. /**<br /> * 实现 除法运算<br /> * @param dividend 被除数<br /> * @param divisor 除数<br /> * @return 返回 第一个参数 除以 第二个参数 的 商<br /> * @throws Exception 抛出一个 受检查异常 ( 受 编译器 检查 )<br /> */<br /> **public** **static** **Integer** divide( **Integer** dividend , **Integer** divisor ) **throws** **Exception** {<br /> **Integer** result = dividend / divisor ; // 商 = 被除数 / 除数 ;<br /> **return** result ;<br /> }

在方法内部通过 throw 关键字显式抛出单个异常实例

import java.util.Arrays;
public class ExceptionHandlingTestB {

  1. **static** **Object**[] elements = **new** **Object**[ 10 ];<br /> **public** **static** **void** **main**(**String**[] args) {
  2. add( 2 , "二五零" );<br /> show();<br /> add( 250 , 250 );<br /> show();<br /> }
  3. **public** **static** **void** **add**( **int** index , **Object** element ) {<br /> **if**( index < 0 || index >= elements.length ) {<br /> // 指定异常实例中封装的 详细信息 ( 关于异常的描述信息 )<br /> **String** message = "索引必须是 [ 0 , " + elements.length + " ) 之间" ;<br /> // 创建异常实例<br /> **ArrayIndexOutOfBoundsException** e = **new** **ArrayIndexOutOfBoundsException**( message );<br /> // 注意,与 throws 关键字不同,throw 关键字之后跟的是 单个异常实例<br /> **throw** e ; // 抛出异常实例<br /> }<br /> elements[ index ] = element ;<br /> }
  4. **public** **static** **void** **show**() {<br /> **System**.out.println( **Arrays**.toString( elements ) );<br /> }<br />}

自定义异常类型/异常转译

通过直接或间接继承RuntimeException类来定义 运行时异常类型
通过直接或间接继承Exception类来定义受检查异常类型(不能继承RuntimeException)
建议参照父类的构造方法生成自定义异常的构造方法
eg:public class SuanShuException extends RuntimeException {

  1. **public** **SuanShuException**() {<br /> **super**();<br /> }<br /> **public** **SuanShuException**(**String** message, **Throwable** cause, **boolean** enableSuppression, **boolean** writableStackTrace) {<br /> **super**(message, cause, enableSuppression, writableStackTrace);<br /> }<br /> **public** **SuanShuException**(**String** message, **Throwable** cause) {<br /> **super**(message, cause);<br /> }<br /> **public** **SuanShuException**(**String** message) {<br /> **super**(message);<br /> }<br /> **public** **SuanShuException**(**Throwable** cause) {<br /> **super**(cause);<br /> }

}

public class ExceptionHandlingTestC {

  1. **public** **static** **void** **main**(**String**[] args) {<br /> **System**.out.println( "main begin ..." );<br /> **Integer** a = 100 ;<br /> **Integer** b = 0 ;<br /> divide( a , b );<br /> **System**.out.println( "main end ." );<br /> }
  2. /**<br /> * 实现 除法运算<br /> * @param dividend 被除数<br /> * @param divisor 除数<br /> * @return 返回 第一个参数 除以 第二个参数 的 商<br /> * @throws Exception 抛出一个 受检查异常 ( 受 编译器 检查 )<br /> */<br /> **public** **static** **Integer** divide( **Integer** dividend , **Integer** divisor ){<br /> **Integer** result = **null** ;<br /> **try** {<br /> result = dividend / divisor ; // 商 = 被除数 / 除数 ;<br /> } **catch**( **NullPointerException** | **ArithmeticException** cause ) {<br /> **String** message = "执行除法运算时发生错误" ;<br /> //【异常转译】以已经捕获到的异常为原因创建另外一个异常实例<br /> **SuanShuException** sse = **new** **SuanShuException**( message , cause ); // 创建新的异常实例<br /> **throw** sse ; // 抛出异常实例<br /> }<br /> **return** result ;<br /> }<br />}

小陷阱

当 return 遇到 finally 时,仍然是 finally 先执行后再执行 return

public class ExceptionHandlingTestD {

  1. **public** **static** **void** **main**(**String**[] args) {<br /> **System**.out.println( "main begin ..." );<br /> **int** x = test2();<br /> **System**.out.println( x );//101<br /> **System**.out.println( "main end ." );<br /> }
  2. @SuppressWarnings("finally")<br /> **public** **static** **int** **test2**(){<br /> **int** a = 100 ;<br /> **try** {<br /> **System**.out.println( "- - - try - - -" );<br /> **return** a + 10 ;//final中的return会替换这里的return<br /> } **catch**( **Exception** cause ) {<br /> **System**.out.println( "- - - catch - - -" );<br /> **return** a - 10 ;<br /> } **finally** {<br /> **System**.out.println( "- - - finally - - -" );<br /> **return** ++a ;<br /> }<br /> }<br />}