本章重点
例外和例外的处理例外处理classtry-catch-finallythrows和throwover writeJAVA的source file即使编译成功,在执行时也可能出错,此时的报错称为例外。
例外由负责执行程式的JVM发出给使用者知道。如果没有指定应对方法的话,程式就会直接中断。
对应例外的class阶层如下
Throwable(全部例外处理的父类)
来看看各例外class下面常见的子class
Error class
RuntimeException class
非RuntimeException class
除了JAVA内建的例外class,开发者也可以自定义class如下例:
public class MyException extends Exception{}
继承Exception类可以获得以下方法
void printStackTrace() //显示例外发生的地方String getMessage() //取得例外发生的原因等相关资讯例外的处理方式有以下两种:
try-catch-finallythrows先来看看try-catch-finally的文法和範例
文法如下:
void method(){ try{ 可能发生例外的地方 }catch(例外处理的class 变数){ 例外发生时如何处理 }finally{ 不管有没有例外都要进行的处理 }}
使用时未必三种关键字都要写,catch和finally择一即可。
範例:
class Sample8_1 { public static void main(String[] args) { int[] num = {10,20,30}; for (int i = 0; i < 4; i++){ try{ System.out.print("num :" + num[i]); System.out.println(" : 第" + (i + 1) + "次的迴圈"); }catch(ArrayIndexOutOfBoundsException e){ System.out.println("例外发生!"); } } System.out.println("--end--"); }}
执行结果
num :10 : 第1次的迴圈num :20 : 第2次的迴圈num :30 : 第3次的迴圈例外发生!--end--
如果把阵列缩短一点,执行结果如下
num :10 : 第1次的迴圈num :20 : 第2次的迴圈例外发生!例外发生!--end--
添加了finally的範例如下:
class Sample8_2 { public static void main(String[] args) { int[] num = {10,20,30}; for (int i = 0; i < 4; i++){ try{ System.out.print("num :" + num[i]); System.out.println(" : 第" + (i + 1) + "次的迴圈"); }catch(ArrayIndexOutOfBoundsException e){ System.out.println("例外发生!"); } } System.out.println("--end--"); }}
执行结果
num :10 : 第1次的迴圈--finally--num :20 : 第2次的迴圈--finally--num :30 : 第3次的迴圈--finally--例外发生!--finally----end--
catch处理可以指定多个例外处理class,但若class之间有继承关係,则须从子类到父类(範围从小到大)撰写,否则会编译错误(因为不合逻辑)。
会报错的範例:
}catch(Exception e){ ...}catch(NullPointerException e){ ...}
正确的範例
}catch(NullPointerException e){ ...}catch(Exception e){ ...}
若是没有继承关係的class,则可以"|"符号组合起来。
}catch(FileNotFoundException | ArithmeticException e){
用throws传递例外
有时候遇到例外时我们不想当场处理,可以使用throws来传递给上一层或更上层,最后再用try-catch来处理它。
请看以下範例:
class DBAccess{ void select(...){ try{ ... }catch{ ... } } void insert(...){ try{ ... }catch{ ... } }}
上面是一个访问DB的class,里面有複数的方法存在。如果每一个都要写try-catch的话,程式码会变得很冗长。
可以利用throws改写为以下样子
class DBAccess{ void select(...) throws SQLException{ } void insert(...) throws SQLException{ }}
然后在呼叫出此物件的上层,利用try-catch进行处理
class Test{ DBAccess d = new DBAccess(); try{ d.select(...); d.insert(...); }catch(SQLException e){ // get log }}
如上例,如果物件里有throws方法的话,使用这些方法时就必须使用try-catch包覆起来。
JAVA里面的工具类也有这样的案例,例如:
java.io包提供的FileReader类的建构式,发生例外时会throws FileNotFoundException。
这个例外不属于RuntimeException的子类,所以"必须"指定例外处理方法。
java.lang包提供的Integer类的parseInt()方法出错时会throws NumberFormatException
这个例外属于RuntimeException的子类,所以不一定要指定例外处理方法。
关于是不是一定要指定例外处理方法,请看以下範例:
import java.io.*;class Sample8_2 { public static void main(String[] args) { //不一定要处理的例外 int i = Integer.parseInt("10"); //一定要处理的例外 FileReader r = new FileReader("Test.txt");}
编译结果
Sample8_2.java:9: error: unreported exception FileNotFoundException; must be caught or declared to be thrown FileReader r = new FileReader("Test.txt"); ^1 error
必须处理的例外,如果没有用try-catch包覆,编译时就会报错。
用throw手动抛出例外
throw和前面说的throws是不一样的指令,请看清楚了。
有些时候我们想要自己定义什么样的值是正常的,什么样的值是异常值需要进行例外处理。
这时候就可以使用throw指令丢出例外并终止后续的处理。
class MyException extends Exception { private int age; public void setAge(int age){this.age = age;} public int getAge(){return this.age;}}class Sample8_3 { public static void main(String[] args) { try{ int age = -10; checkAge(age); }catch(MyException e){ System.out.println("年龄异常。age:" + e.getAge()); } } public static void checkAge(int age) throws MyException{ if (age >= 0){ System.out.println("OK"); }else{ MyException e = new MyException(); e.setAge(age); throw e; } }}
执行结果
年龄异常。age:-10
覆写具有throws的方法时,须注意的规则:
当我们要写一个子类来继承父类,并覆写具有throws的方法时,须注意以下规则:
子类方法可以跟父类丢出一样的例外处理,或是不写throws,或是改写为符合以下规则的处理
来看看範例:
import java.io.*;class Super{ void method() throws IOException{} }class SubA extends Super { void method() {} }class SubB extends Super { void method() throws FileNotFoundException {} }class SubC extends Super { void method() throws Exception{} }class SubD extends Super { void method() throws ClassNotFoundException{} }class SubE extends Super { void method() throws RuntimeException{} }
编译结果
class SubC extends Super { void method() throws Exception{} } ^ overridden method does not throw ExceptionSample8_4.java:8: error: method() in SubD cannot override method() in Superclass SubD extends Super { void method() throws ClassNotFoundException{} } ^ overridden method does not throw ClassNotFoundException2 errors
说明
SubA没有写throws,OK
SubB抛出FileNotFoundException,是IOException的子类,OK。
SubC抛出Exception範围大于Super的IOException因此报错
SubD抛出ClassNotFoundException与 Super的IOException没有继承关係,而且也不是RuntimeException,所以报错。
SubE抛出RuntimeException,OK。
以上 是关于JAVA的学习笔记,到此结束。之后会整理JAVA Web的学习笔记(虽然还很菜..希望整理得出来)
参考教材: JAVAプログラマSilver SE8 - 山本 道子