1. 程式人生 > 實用技巧 >異常機制和File類

異常機制和File類

16.1 異常機制(重點)

16.1.1 基本概念

異常就是"不正常"的含義,在Java語言中主要指程式執行中發生的不正常情況。

java.lang.Throwable類是Java語言中錯誤(Error)和異常(Exception)的超類。

其中Error類主要用於描述Java虛擬機器無法解決的嚴重錯誤,通常無法編碼解決,如:JVM掛掉了等。

其中Exception類主要用於描述因程式設計錯誤或偶然外在因素導致的輕微錯誤,通常可以編碼解決,如:0作為除數等。

16.1.2 異常的分類

java.lang.Exception類是所有異常的超類,主要分為以下兩種:

RuntimeException - 執行時異常,也叫作非檢測性異常

IOException和其它異常 - 其它異常,也叫作檢測性異常,所謂檢測性異常就是指在編譯階段都能被編譯器檢測出來的異常。

其中RuntimeException類的主要子類:

ArithmeticException類 - 算術異常

ArrayIndexOutOfBoundsException類 - 陣列下標越界異常

NullPointerException - 空指標異常 ClassCastException - 型別轉換異常

NumberFormatException - 數字格式異常

注意:當程式執行過程中發生異常但又沒有手動處理時,則由Java虛擬機器採用預設方式處理異常,而預設處理方式就是:列印異常的名稱、異常發生的原因、異常發生的位置以及終止程式。

16.1.3 異常的避免

在以後的開發中儘量使用if條件判斷來避免異常的發生。

但是過多的if條件判斷會導致程式的程式碼加長、臃腫,可讀性差。

16.1.4 異常的捕獲

語法格式 try {

編寫可能發生異常的程式碼;

}

catch(異常型別 引用變數名) {

編寫針對該類異常的處理程式碼;

}

...

finally {

編寫無論是否發生異常都要執行的程式碼;

}

注意事項

a.當需要編寫多個catch分支時,切記小型別應該放在大型別的前面; b.懶人的寫法:

catch(Exception e) {}

c.finally通常用於進行善後處理,如:關閉已經開啟的檔案等。

執行流程 try { a;

b; - 可能發生異常的語句 c;

}catch(Exception ex) { d;

}finally { e;

}

當沒有發生異常時的執行流程:a b c e; 當發生異常時的執行流程:a b d e;

16.1.5 異常的丟擲

基本概念在某些特殊情況下有些異常不能處理或者不便於處理時,就可以將該異常轉移給該方法的呼叫者,這種方法就叫異常的丟擲。當方法執行時出現異常,則底層生成一個異常類物件丟擲,此時異常程式碼後續的程式碼就不再執行。

語法格式

訪問許可權 返回值型別 方法名稱(形參列表) throws 異常型別1,異常型別2,...{ 方法體; } 如:

public void show() throws IOException{}

方法重寫的原則

a.要求方法名相同、引數列表相同以及返回值型別相同,從jdk1.5開始支援返回子類型別;

b.要求方法的訪問許可權不能變小,可以相同或者變大; c.要求方法不能丟擲更大的異常;

注意:子類重寫的方法不能丟擲更大的異常、不能丟擲平級不一樣的異常,但可以丟擲一樣的異常、更小的異常以及不丟擲異常。

經驗分享

若父類中被重寫的方法沒有丟擲異常時,則子類中重寫的方法只能進行異常的捕獲處理。

若一個方法內部又以遞進方式分別呼叫了好幾個其它方法,則建議這些方法內可以使用丟擲的方法處理到最後一層進行捕獲方式處理。

16.1.6 自定義異常

基本概念當需要在程式中表達年齡不合理的情況時,而Java官方又沒有提供這種針對性的異常,此時就需要程式設計師自定義異常加以描述。

實現流程

a.自定義xxxException異常類繼承Exception類或者其子類。

b.提供兩個版本的構造方法,一個是無參構造方法,另外一個是字串作為引數的構造方法。

異常的產生

throw new 異常型別(實參);

如:

throw new AgeException("年齡不合理!!!");

Java採用的異常處理機制是將異常處理的程式程式碼集中在一起,與正常的程式程式碼分開,使得程式簡潔、優雅,並易於維護。

// 自定義個異常類
public class AgeException extends Exception {
    public AgeException() {
    }

    public AgeException(String message) {
        super(message);
    }
}
//建立一個人類
public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        setName(name);
        setAge(age);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age > 0 && age < 150){
            this.age = age;
        } else {
            try {
                throw new AgeException("年齡不合理");
            } catch (AgeException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class PersonTest {
    public static void main(String[] args) {
        Person p1 = new Person("張飛",-30);
        System.out.println(p1);
    }
}

16.2 File類(重點)

16.2.1 基本概念

java.io.File類主要用於描述檔案或目錄路徑的抽象表示資訊,可以獲取檔案或目錄的特徵資訊,如:大小等。

16.2.2 常用的方法

方法宣告

功能概述

File(String pathname)

根據引數指定的路徑名來構造物件

File(String parent, String child)

根據引數指定的父路徑和子路徑資訊構造物件

File(File parent, String child)

根據引數指定的父抽象路徑和子路徑資訊構造物件

boolean exists()

測試此抽象路徑名錶示的檔案或目錄是否存在

String getName()

用於獲取檔案的名稱

long length()

返回由此抽象路徑名錶示的檔案的長度

long lastModified()

用於獲取檔案的最後一次修改時間

String getAbsolutePath()

用於獲取絕對路徑資訊

boolean delete()

用於刪除檔案,當刪除目錄時要求是空目錄

boolean createNewFile()

用於建立新的空檔案

boolean mkdir()

用於建立目錄

boolean mkdirs()

用於建立多級目錄

File[] listFiles()

獲取該目錄下的所有內容

boolean isFile()

判斷是否為檔案

boolean isDirectory()

判斷是否為目錄

File[] listFiles(FileFilter filter)

獲取目錄下滿足篩選器的所有內容

案例題目

遍歷指定目錄以及子目錄中的所有內容並打印出來。

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;

public class FileTest {

    // 自定義成員方法實現指定目錄以及子目錄中所有內容的列印
    public static void show(File file) {
        // 獲取目錄f3下的所有內容並記錄到一維陣列中
        File[] filesArray = file.listFiles();
        // 遍歷陣列
        for (File tf: filesArray) {
            String name = tf.getName();
            // 判斷是否為檔案,若是則直接列印檔名稱
            if (tf.isFile()) {
                System.out.println(name);
            }
            // 若是目錄,則使用[]將目錄名稱括起來
            if (tf.isDirectory()) {
                System.out.println("[" + name + "]");
                show(tf);
            }
        }
    }

    public static void main(String[] args) throws IOException {

        // 1.構造File型別的物件與d:/a.txt檔案關聯
        File f1 = new File("d:/a.txt");
        // 2.若檔案存在則獲取檔案的相關特徵資訊並列印後刪除檔案
        if (f1.exists()) {
            System.out.println("檔案的名稱是:" + f1.getName());
            System.out.println("檔案的大小是:" + f1.length());
            Date d1 = new Date(f1.lastModified());
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            System.out.println("檔案的最後一次修改時間:" + sdf.format(d1));
            // 絕對路徑: 主要指以根目錄開始的路徑資訊,如:c:/  d:/   /..
            // 相對路徑: 主要指以當前目錄所在位置開始的路徑資訊,如:./  ../   相對路徑
            System.out.println("檔案的絕對路徑資訊是:" + f1.getAbsolutePath());
            System.out.println(f1.delete()? "檔案刪除成功": "檔案刪除失敗");
        } else {
            // 3.若檔案不存在則建立新的空檔案
            System.out.println(f1.createNewFile()? "檔案建立成功": "檔案建立失敗!");
        }

        System.out.println("---------------------------------------------------------");
        // 4.實現目錄的刪除和建立
        File f2 = new File("d:/搗亂/猜猜我是誰/你猜我猜不猜/死鬼");
        if (f2.exists()) {
            System.out.println("目錄名稱是:" + f2.getName());
            System.out.println(f2.delete()? "目錄刪除成功": "目錄刪除失敗");
        } else {
            //System.out.println(f2.mkdir()? "目錄建立成功": "目錄建立失敗");   // 建立單層目錄
            System.out.println(f2.mkdirs()? "目錄建立成功": "目錄建立失敗");   // 建立多層目錄
        }

        System.out.println("---------------------------------------------------------");
        // 5.實現將指定目錄中的所有內容打印出來
        File f3 = new File("d:/搗亂");
        // 獲取目錄f3下的所有內容並記錄到一維陣列中
        File[] filesArray = f3.listFiles();
        // 遍歷陣列
        for (File tf: filesArray) {
            String name = tf.getName();
            // 判斷是否為檔案,若是則直接列印檔名稱
            if (tf.isFile()) {
                System.out.println(name);
            }
            // 若是目錄,則使用[]將目錄名稱括起來
            if (tf.isDirectory()) {
                System.out.println("[" + name + "]");
            }
        }

        System.out.println("---------------------------------------------------------");
        // 6.實現目錄中所有內容獲取的同時進行過濾
        // 匿名內部類的語法格式:介面/父類型別 引用變數名 = new 介面/父類型別() { 方法的重寫 };
        /*FileFilter fileFilter = new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                // 若檔名是以.avi為結尾,則返回true表示保留   否則返回false就是表示丟棄
                return pathname.getName().endsWith(".avi");
            }
        };*/
        // Lambda表示式的格式:(引數列表) -> {方法體}
        FileFilter fileFilter = (File pathname) -> {return pathname.getName().endsWith(".avi");};
        File[] filesArray2 = f3.listFiles(fileFilter);
        for (File tf : filesArray2) {
            System.out.println(tf);
        }

        System.out.println("---------------------------------------------------------");
        // 7.使用遞迴的思想獲取目錄以及子目錄中的內容
        show(new File("d:/搗亂"));
    }
}