配套視頻教程
在使用計算機語言進行項目開發的過程中,即使程序員把代碼寫得盡善盡美,在系統的運行過程中仍然會遇到一些問題,因為很多問題不是靠代碼能夠避免的,比如:客戶輸入數據的格式,讀取文件是否存在,網絡是否始終保持通暢等等。
異常:在Java語言中,將程序執行中發生的不正常情況稱為“異常”。(開發過程中的語法錯誤和邏輯錯誤不是異常)
Java程序在執行過程中所發生的異常事件可分為兩類:
- Error: Java虛擬機無法解決的嚴重問題。如:JVM系統內部錯誤、資源耗盡等嚴重情況。一般不編寫針對性的代碼進行處理。
- Exception: 其它因編程錯誤或偶然的外在因素導致的一般性問題,可以使用針對性的代碼進行處理。例如:
1 空指針訪問
2 試圖讀取不存在的文件
3 網絡連接中斷
對于這些錯誤,一般有兩種解決方法:一是遇到錯誤就終止程序的運行。另一種方法是由程序員在編寫程序時,就考慮到錯誤的檢測、錯誤消息的提示,以及錯誤的處理。
捕獲錯誤最理想的是在編譯期間,但有的錯誤只有在運行時才會發生。比如:除數為0,數組下標越界等
分類:編譯時異常和運行時異常
Java異常類層次
1.運行時異常
- 是指編譯器不要求強制處置的異常。一般是指編程時的邏輯錯誤,是程序員應該積極避免其出現的異常。java.lang.RuntimeException類及它的子類都是運行時異常。
- 對于這類異常,可以不作處理,因為這類異常很普遍,若全處理可能會對程序的可讀性和運行效率產生影響。
2.編譯時異常
- 是指編譯器要求必須處置的異常。即程序在運行時由于外界因素造成的一般性異常。編譯器要求java程序必須捕獲或聲明所有編譯時異常。
常見異常
java.lang.RuntimeException
ClassCastException
ArrayIndexOutOfBoundsException
NullPointerException
ArithmeticException
。。。
java.io.IOExeption
FileNotFoundException
EOFException
java.lang.ClassNotFoundException
java.lang.InterruptedException
java.io.FileNotFoundException
java.sql.SQLException
Java異常舉例
public class Test6_1{
public static void main(String[] args) {
String friends[]={"lisa","bily","kessy"};
for(int i=0;i<5;i++) {
System.out.println(friends[i]); //friends[4]?
}
System.out.println("\nthis is the end");
}
}
程序Test6_1編譯正確,運行結果:java Test6_1
lisa
bily
kessy
java.lang.ArrayIndexOutOfBoundsException
at Test6_1.main(Test6_1.java:5)
Exception in thread "main"
public class NullRef{
int i=1;
public static void main(String[] args) {
NullRef t=new NullRef();
t=null;
System.out.println(t.i);
}
}
程序NullRef.java編譯正確,運行結果:java NullRef
java.lang.NullPointerException
at NullRef.main(NullRef.java:6)
Exception in thread "main"
public class DivideZero{
int x;
public static void main(String[] args) {
int y;
DivideZero c=new DivideZero();
y=3/c.x;
System.out.println(“program ends ok!”);
}
}
程序DivideZero.java編譯正確,運行結果:java DivideZero
java.lang.ArithmeticException: / by zero
at DivideZero.main(DivideZero.java:6)
Exception in thread "main"
class Person {
public static void main(String[] args) {
Object obj = new Date();
Person person;
person = (Person)obj;
System.out.println(person);
}
}
程序Person.java編譯正確,運行結果:java Person
java.lang. java.lang.ClassCastException
at Person.main(Person.java:5)
Exception in thread "main"
異常處理機制
在編寫程序時,經常要在可能出現錯誤的地方加上檢測的代碼,如進行x/y運算時,要檢測分母為0,數據為空,輸入的不是數據而是字符等。過多的分支會導致程序的代碼加長,可讀性差。因此采用異常機制。
Java異常處理
Java采用異常處理機制,將異常處理的程序代碼集中在一起,與正常的程序代碼分開,使得程序簡潔,并易于維護。
- Java提供的是異常處理的抓拋模型。
- Java程序的執行過程中如出現異常,會生成一個異常類對象,該異常對象將被提交給Java運行時系統,這個過程稱為拋出(throw)異常。
- 異常對象的生成
由虛擬機自動生成:程序運行過程中,虛擬機檢測到程序發生了問題,如果在當前代碼中沒有找到相應的處理程序,就會在后臺自動創建一個對應異常類的實例對象并拋出——自動拋出
由開發人員手動創建:Exception exception = new ClassCastException();——創建好的異常對象不拋出對程序沒有任何影響,和創建一個普通對象一樣
異常處理是通過try-catch-finally語句實現的。
try{
...... //可能產生異常的代碼
}
catch( ExceptionName1 e ){
...... //當產生ExceptionName1型異常時的處置措施
}
catch( ExceptionName2 e ){
...... //當產生ExceptionName2型異常時的處置措施
}
[ finally{
...... //無論是否發生異常,都無條件執行的語句
} ]
- try
捕獲異常的第一步是用try{…}語句塊選定捕獲異常的范圍,將可能出現異常的代碼放在try語句塊中。 - catch (Exceptiontype e)
在catch語句塊中是對異常對象進行處理的代碼。每個try語句塊可以伴隨一個或多個catch語句,用于處理可能產生的不同類型的異常對象。
如果明確知道產生的是何種異常,可以用該異常類作為catch的參數;也可以用其父類作為catch的參數。
比如:可以用ArithmeticException類作為參數的地方,就可以用RuntimeException類作為參數,或者用所有異常的父類Exception類作為參數。但不能是與ArithmeticException類無關的異常,如NullPointerException(catch中的語句將不會執行)。
捕獲異常的有關信息
與其它對象一樣,可以訪問一個異常對象的成員變量或調用它的方法。
getMessage() 獲取異常信息,返回字符串
printStackTrace() 獲取異常類名和異常信息,以及異常出現在程序中的位置。返回值void。
finally
捕獲異常的最后一步是通過finally語句為異常處理提供一個統一的出口,使得在控制流轉到程序的其它部分以前,能夠對程序的狀態作統一的管理。
不論在try代碼塊中是否發生了異常事件,catch語句是否執行,catch語句是否有異常,catch語句中是否有return,finally塊中的語句都會被執行
異常處理舉例
public class Test6_2{
public static void main(String[] args) {
String friends[]={"lisa","bily","kessy"};
try {
for(int i=0;i<5;i++) {
System.out.println(friends[i]);
}
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println("index err");
}
System.out.println("\nthis is the end");
}
}
程序Test6_2運行結果:java java6_2
lisa
bily
kessy
index err
this is the end
public class DivideZero1{
int x;
public static void main(String[] args) {
int y;
DivideZero1 c=new DivideZero1();
try{
y=3/c.x;
}
catch(ArithmeticException e){
System.out.println("divide by zero error!");
}
System.out.println("program ends ok!");
}
}
程序DivideZero1運行結果:java DivideZero1
divide by zero error!
program ends ok!
練習
編寫一個類TestException,在main方法中使用try、catch、finally,要求:
在try塊中,編寫被零除的代碼。
在catch塊中,捕獲被零除所產生的異常,并且打印異常信息
在finally塊中,打印一條語句。
不捕獲異常時的情況
- 前面使用的異常都是RuntimeException類或是它的子類,這些類的異常的特點是:
即使沒有使用try和catch捕獲,Java自己也能捕獲,并且編譯通過 ( 但運行時會發生異常使得程序運行終止 )。
下面代碼,如果不用try-catch處理,循環到第二次就會退出。
public class Main {
public static void main(String[] args) {
// write your code here
Scanner sc = new Scanner(System.in);
for(int i = 0; i < 5; i++)
{
try
{
int k = sc.nextInt();
if(i == 1)
{
k = k / 0;
}
System.out.println(k);
}
catch (Exception ex)
{
System.out.println(ex.getMessage());
}
}
}
}
- 如果拋出的異常是IOException等類型的非運行時異常,則必須捕獲,否則編譯錯誤。也就是說,我們必須處理編譯時異常,將異常進行捕捉,轉化為運行時異常
IOException異常處理舉例
public class Test6_3{
public static void main(String[] args) {
FileInputStream in=new FileInputStream("myfile.txt");
int b;
b = in.read();
while(b!= -1) {
System.out.print((char)b);
b = in.read();
}
in.close();
}
}
public class Test6_3{
public static void main(String[] args){
try{
FileInputStream in=new FileInputStream("myfile.txt");
int b;
b = in.read();
while(b!= -1) {
System.out.print((char)b);
b = in.read();
}
in.close();
}catch (IOException e) {
System.out.println(e);
}finally {
System.out.println(" It’s ok!");
}
}
}
編譯、運行應用程序Test6_3.java,體會java語言中異常的捕獲和處理機制。
相關知識:FileInputStream類的成員方法read()的功能是每次從相應的(本地為ASCII碼編碼格式)文件中讀取一個字節,并轉換成0~255之間的int型整數返回,到達文件末尾時則返回-1。
聲明拋出異常是Java中處理異常的第二種方式
- 如果一個方法(中的語句執行時)可能生成某種異常,但是并不能確定如何處理這種異常,則此方法應顯示地聲明拋出異常,表明該方法將不對這些異常進行處理,而由該方法的調用者負責處理。
- 在方法聲明中用throws語句可以聲明拋出異常的列表,throws后面的異常類型可以是方法中產生的異常類型,也可以是它的父類。
聲明拋出異常舉例:
public void readFile(String file) throws FileNotFoundException {
……
// 讀文件的操作可能產生FileNotFoundException類型的異常
FileInputStream fis = new FileInputStream(file);
..……
}
public class Test6_4{
public static void main(String[] args){
Test6_4 t = new Test6_4();
try{
t.readFile();
}catch(IOException e){ }
}
public void readFile() throws IOException {
FileInputStream in=new FileInputStream("myfile.txt");
int b;
b = in.read();
while(b!= -1) {
System.out.print((char)b);
b = in.read();
}
in.close();
}
}
人工拋出異常
Java異常類對象除在程序執行過程中出現異常時由系統自動生成并拋出,也可根據需要人工創建并拋出。
- 首先要生成異常類對象,然后通過throw語句實現拋出操作(提交給Java運行環境)。
IOException e = new IOException();
throw e; - 可以拋出的異常必須是Throwable或其子類的實例。下面的語句在編譯時將會產生語法錯誤:
throw new String("want to throw");
創建用戶自定義異常類
- 一般地,用戶自定義異常類都是RuntimeException的子類。
- 自定義異常類通常需要編寫幾個重載的構造器。
- 自定義的異常類對象通過throw拋出。
- 自定義異常最重要的是異常類的名字,當異常出現時,可以根據名字判斷異常類型。
用戶自定義異常類MyException,用于描述數據取值范圍錯誤信息。用戶自己的異常類必須繼承現有的異常類。
class MyException extends Exception {
static final long serialVersionUID = 1L;
private int idnumber;
public MyException(String message, int id) {
super(message);
this.idnumber = id;
}
public int getId() {
return idnumber;
}
}
public class Test6_5{
public void regist(int num) throws MyException {
if (num < 0)
throw new MyException(“人數為負值,不合理”, 3);
else
System.out.println("登記人數" + num );
}
public void manager() {
try {
regist(100);
} catch (MyException e) {
System.out.print("登記失敗,出錯種類"+e.getId());
}
System.out.print("本次登記操作結束");
}
public static void main(String args[]){
Test6_5 t = new Test6_5();
t.manager();
}
}