Java的異常處理——try-catch-finally-throw-throws

大一大二寫了兩年C++,好幾萬行的代碼,從來沒有寫過異常處理方面的代碼。C++的老師上課放過異常處理的PPT,但是沒有佈置過相關作業,平時寫的代碼也不會想去用異常處理。現在到了大三上學期,才第一次在數據庫課程設計的程序中寫了try-catch。本學期學Java,我要徹底弄清楚異常處理是怎麼弄的。


try-catch

下面的例子:多catch處理語句。一個catch捕獲一個異常。出現異常的時候:停止try,按照代碼裏 catch 的順序從上往下依次匹配異常類型,首次匹配成功後執行該 catch,後面的 catch 跳過,不用繼續匹配。如果 catch 的順序是:先捕獲異常 e1, 其後面再捕獲異常 e2,那麼 e1 不能是 e2 父類。即父類異常要在子類異常的後面捕獲

其實在 catch { } 裏面,理論上也可能拋出異常。寫 catch 的時候要小心,保證不要出問題。如果在 catch 裏面拋出了異常,那就hehe了。

package exception;

import java.util.Scanner;

public class MultiCatchDemo
{

    public static void main(String[] args)
    {
        Scanner scanner = new Scanner(System.in);
        int array[] = new int[3];
        try
        {
            System.out.println("input a number");
            String str = scanner.next();
            int n1 = Integer.parseInt(str); // str 轉換成 int, 可能拋出 NumberFormatException

            System.out.println("input another number");
            int n2 = scanner.nextInt();
            array[1] = n1 / n2; // n2 等於 0 時,拋出ArithmeticException

            array[3] = n1 * n2; // 數組越界,拋出ArrayIndexOutOfBoundsException
            System.out.println("the sum of two numbers is" + (n1 + n2));
        }
        catch (NumberFormatException ex)
        {
            System.out.println("數字格式化異常");
        }
        catch (ArithmeticException ex)
        {
            System.out.println("算術異常");
        }
        catch (ArrayIndexOutOfBoundsException ex)
        {
            System.out.println("數組下標越界異常");
        }
        catch (Exception e)
        {
            System.out.println("其他未知異常");
        }

        scanner.close(); // 物理資源回收
        System.out.println("程序結束");
    }

}

在Java 7中,增加了多異常捕獲,即一個catch可以同時捕獲多個不同類型的異常。這個異常對象是final,其引用不能指向一個另外一個異常對象。

catch (ArrayIndexOutOfBoundsException | NumberFormatException | ArithmeticException ex)
{
    System.out.println("程序發生了數組越界,數字格式異常,算數異常之一");
    // ex = new ArithmeticException("text"); 默認是常數,不能賦值
}

try-catch是可以嵌套的。需要注意的是:內層try拋出的異常,如果內層沒有catch的話,由外層catch負責捕獲。

package exception;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Scanner;


public class NestingTryCatch
{

    public static void main(String[] args)
    {
        // 外層try
        try(Scanner scanner = new Scanner(System.in))  // 自動關閉資源
        {
            System.out.println("input one number");
            String str = scanner.next();
            int n1 = Integer.parseInt(str);

            // 內層try
            try 
            {
                @SuppressWarnings({ "unused", "resource" })
                FileInputStream fis = new FileInputStream("caitao.txt");
            }
            catch (IOException ioe)
            {
                System.out.println(ioe.getMessage());
            }

            System.out.println("input another number");
            int n2 = scanner.nextInt();
            System.out.println("n1/n2 = " + n1 / n2);

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        System.out.println("caitao");
    }

}

try-catch-finally

fianlly的作用一般是回收物理資源,比如:數據庫連接,網絡連接,磁盤文件讀寫等等。如果在try裏面使用了物力資源,不管是否發生異常,都應該回收這些資源。不管是否發生異常,fianlly代碼塊裏面的代碼總會執行。Java的垃圾回收機制可以回收堆內存中對象佔用的內存(也就是 new 操作符的東西),但是不能回收物理資源。

package exception;

import java.io.FileInputStream;
import java.io.IOException;

public class FinallyDemo
{

    public static void main(String[] args)
    {
        FileInputStream fis = null;
        try
        {
            fis = new FileInputStream("caitao.txt");
        }
        catch (IOException ioe)
        {
            System.out.println(ioe.getMessage());
            return;
            //System.exit(0);
        }
        finally
        {
            if (fis != null)
            {
                try
                {
                    fis.close();
                }
                catch (IOException ioe)
                {
                    ioe.printStackTrace();
                }
            }
            System.out.println("執行finally塊裏的資源回收");
        }
    }

}

從 Java 7 開始,try後面可以加一對圓括號,在這個圓括號裏面,可以聲明,初始化一個或多個資源。當 try 語句結束的時候,可以自動關閉資源。這樣就不用finally,不用手動寫 scanner.close() 了,JVM會自動幫我們做。

try(Scanner scanner = new Scanner(System.in))
{

}
catch ()
{

}
// 隱式的finally塊,自動關閉資源

throw & throws

throw 拋出一個異常對象:程序出現異常的時候,系統會自動拋出異常對象,除此之外也可以用代碼手動拋出異常對象(比如拋出自己寫的一個異常類的對象,或者根據業務需要拋出異常對象)

package exception;

import java.util.Scanner;

public class ThrowDemo
{

    public static void main(String[] args)
    {
        try(Scanner scanner = new Scanner(System.in))
        {
            System.out.println("input your age: ");
            int age = scanner.nextInt();
            if (age < 0 || age > 100) // 年齡超出範圍則拋出異常
            {
                throw new Exception("age is unlegal");
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        System.out.println("程序結束");
    }
}

throws 聲明拋出一個異常序列:在定義方法的時候使用。假設定義了方法foo( ),foo( )方法內部可能拋出異常MyException,但是foo( ) 內部沒有catch MyException。於是定義 foo( ) throws MyException { }。這樣 MyException 對象就由調用foo( ) 的上一級調用者進行處理。如果存在多級調用,“下面一級”拋出了一個異常對象,“上一級”捕獲了,那麼“更上一級”就無法捕獲了,畢竟異常對象只有一個。

package exception;

import java.util.Scanner;

public class ThrowsDemo
{

    public static void myThrowsFunction() throws NumberFormatException, ArithmeticException, Exception
    { // 這個方法可能拋出異常,但是沒有自己處理。“甩鍋”給上一級調用者
        Scanner scanner = new Scanner(System.in);

        System.out.println("input a number");
        String string = scanner.next();
        int n1 = Integer.parseInt(string);

        System.out.println("input another number");
        int n2 = scanner.nextInt();
        System.out.println("n1/n2 = " + n1 / n2);

        scanner.close();
    }

    public static void main(String[] args)
    {
        try
        {  
            myThrowsFunction(); 
         // 這個方法可能拋出異常,但是這個方法自己卻沒有處理。於是交給上一級(即 main 方法)處理 
        }
        catch (NumberFormatException e)
        {
            e.printStackTrace();
        }
        catch (ArithmeticException e)
        {
            e.printStackTrace();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

}

自定義一個異常類

從 java.lang.Exception 可以繼承一個檢查型自定義類,也可以從 java.lang.RuntimeException 繼承一個非檢查型異常。

Exception類的構造方法有:super( ),和 super( String message ) 兩種。

package exception;

@SuppressWarnings("serial")
class MyException extends Exception
{
    private int i;

    public int val()
    {
        return i;
    }

    public MyException(){}
    public MyException(String msg)
    {
        super(msg);
    }
    public MyException(String msg, int i)
    {
        super(msg);
        this.i = i;
    }
}

public class MyExceptionDemo
{

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

    public static void b() throws MyException
    {
        System.out.println("Throwing MyException from b()");
        throw new MyException("Originated in b()");
    }

    public static void c() throws MyException
    {
        System.out.println("Throwing MyException from c()");
        throw new MyException("Originated in c()", 43);
    }

    public static void main(String[] args)
    {
        try
        {
            a();
        }
        catch (MyException e)
        {
            e.getMessage();
        }

        try
        {
            b();
        }
        catch (MyException e)
        {
            e.toString();
        }

        try
        {
            c();
        }
        catch (MyException e)
        {
            e.printStackTrace();
            System.out.println("error code: " + e.val());
        }
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章