天天看點

《我要進大廠》- Java基礎奪命連環10問,你能堅持到第幾問?(異常 | 泛型)

⭐️ ⭐️上篇文章-​​《我要進大廠》- Java基礎奪命連環14問,你能堅持到第幾問?​​

《我要進大廠》- Java基礎奪命連環10問,你能堅持到第幾問?(異常 | 泛型)

文章目錄

  • ​​一、異常​​
  • ​​1、Exception 和 Error 有什麼差別?​​
  • ​​2、Checked Exception 和 Unchecked Exception 有什麼差別?​​
  • ​​3、Throwable 類常用方法有哪些?​​
  • ​​4、try-catch-finally 如何使用?​​
  • ​​5、finally 中的代碼一定會執行嗎?​​
  • ​​6、如何使用 `try-with-resources` 代替`try-catch-finally`?​​
  • ​​7、異常使用有哪些需要注意的地方?​​
  • ​​二、泛型​​
  • ​​1、什麼是泛型?有什麼作用?​​
  • ​​2、泛型的使用方式有哪幾種?​​
  • ​​3、項目中哪裡用到了泛型?​​
  • ​​總結​​

一、異常

Java 異常類層次結構圖概覽 :

《我要進大廠》- Java基礎奪命連環10問,你能堅持到第幾問?(異常 | 泛型)

1、Exception 和 Error 有什麼差別?

在 Java 中,所有的異常都有一個共同的祖先 ​

​java.lang​

​​ 包中的 ​

​Throwable​

​​ 類。​

​Throwable​

​ 類有兩個重要的子類:

  • ​Exception​

    ​​ :程式本身可以處理的異常,可以通過​

    ​catch​

    ​​ 來進行捕獲。​

    ​Exception​

    ​ 又可以分為 Checked Exception (受檢查異常,必須處理) 和 Unchecked Exception (不受檢查異常,可以不處理)。
  • ​Error​

    ​​ :​

    ​Error​

    ​ 屬于程式無法處理的錯誤 ,我們沒辦法通過 ​

    ​catch​

    ​ 來進行捕獲不建議通過​

    ​catch​

    ​​捕獲 。例如 Java 虛拟機運作錯誤(​

    ​Virtual MachineError​

    ​​)、虛拟機記憶體不夠錯誤(​

    ​OutOfMemoryError​

    ​​)、類定義錯誤(​

    ​NoClassDefFoundError​

    ​)等 。這些異常發生時,Java 虛拟機(JVM)一般會選擇線程終止。

2、Checked Exception 和 Unchecked Exception 有什麼差別?

Checked Exception 即 受檢查異常 ,Java 代碼在編譯過程中,如果受檢查異常沒有被 ​

​catch​

​​/​

​throw​

​ 處理的話,就沒辦法通過編譯 。

比如下面這段 IO 操作的代碼:

《我要進大廠》- Java基礎奪命連環10問,你能堅持到第幾問?(異常 | 泛型)

除了​

​RuntimeException​

​及其子類以外,其他的​

​Exception​

​類及其子類都屬于受檢查異常 。常見的受檢查異常有: IO 相關的異常、​

​ClassNotFoundException​

​​ 、​

​SQLException​

​…。

Unchecked Exception 即 不受檢查異常 ,Java 代碼在編譯過程中 ,我們即使不處理不受檢查異常也可以正常通過編譯。

​RuntimeException​

​ 及其子類都統稱為非受檢查異常,常見的有(建議記下來,日常開發中會經常用到):

  • ​NullPointerException​

    ​(空指針錯誤)
  • ​IllegalArgumentException​

    ​(參數錯誤比如方法入參類型錯誤)
  • ​NumberFormatException​

    ​​(字元串轉換為數字格式錯誤,​

    ​IllegalArgumentException​

    ​的子類)
  • ​ArrayIndexOutOfBoundsException​

    ​(數組越界錯誤)
  • ​ClassCastException​

    ​(類型轉換錯誤)
  • ​ArithmeticException​

    ​(算術錯誤)
  • ​SecurityException​

    ​ (安全錯誤比如權限不夠)
  • ​UnsupportedOperationException​

    ​(不支援的操作錯誤比如重複建立同一使用者)
《我要進大廠》- Java基礎奪命連環10問,你能堅持到第幾問?(異常 | 泛型)

3、Throwable 類常用方法有哪些?

  • ​String getMessage()​

    ​: 傳回異常發生時的簡要描述
  • ​String toString()​

    ​: 傳回異常發生時的詳細資訊
  • ​String getLocalizedMessage()​

    ​​: 傳回異常對象的本地化資訊。使用​

    ​Throwable​

    ​​ 的子類覆寫這個方法,可以生成本地化資訊。如果子類沒有覆寫該方法,則該方法傳回的資訊與​

    ​getMessage()​

    ​傳回的結果相同
  • ​void printStackTrace()​

    ​​: 在控制台上列印​

    ​Throwable​

    ​ 對象封裝的異常資訊

4、try-catch-finally 如何使用?

  • ​try​

    ​​塊 : 用于捕獲異常。其後可接零個或多個​

    ​catch​

    ​​ 塊,如果沒有​

    ​catch​

    ​​ 塊,則必須跟一個​

    ​finally​

    ​ 塊。
  • ​catch​

    ​ 塊 : 用于處理 try 捕獲到的異常。
  • ​finally​

    ​​ 塊 : 無論是否捕獲或處理異常,​

    ​finally​

    ​ 塊裡的語句都會被執行。當在 ​

    ​try​

    ​ 塊或 ​

    ​catch​

    ​ 塊中遇到 ​

    ​return​

    ​ 語句時,​

    ​finally​

    ​ 語句塊将在方法傳回之前被執行。

代碼示例:

try {
    System.out.println("Try to do something");
    throw new RuntimeException("RuntimeException");
} catch (Exception e) {
    System.out.println("Catch Exception -> " + e.getMessage());
} finally {
    System.out.println("Finally");
}      

輸出:

Try to do something
Catch Exception -> RuntimeException
Finally      

注意:不要在 finally 語句塊中使用 return!當 try 語句和 finally 語句中都有 return 語句時,try 語句塊中的 return 語句會被忽略。這是因為 try 語句中的 return 傳回值會先被暫存在一個本地變量中,當執行到 finally 語句中的 return 之後,這個本地變量的值就變為了 finally 語句中的 return 傳回值。

​​jvm 官方文檔​​中有明确提到:

If the ​

​try​

​ clause executes a return, the compiled code does the following:
  1. Saves the return value (if any) in a local variable.
  2. Executes ajsrto the code for the​

    ​finally​

    ​ clause.
  3. Upon return from the​

    ​finally​

    ​ clause, returns the value saved in the local variable.

代碼示例:

public static void main(String[] args) {
    System.out.println(f(2));
}

public static int f(int value) {
    try {
        return value * value;
    } finally {
        if (value == 2) {
            return 0;
        }
    }
}      

輸出:

5、finally 中的代碼一定會執行嗎?

不一定的!在某些情況下,finally 中的代碼不會被執行。

就比如說 finally 之前虛拟機被終止運作的話,finally 中的代碼就不會被執行。

try {
    System.out.println("Try to do something");
    throw new RuntimeException("RuntimeException");
} catch (Exception e) {
    System.out.println("Catch Exception -> " + e.getMessage());
    // 終止目前正在運作的Java虛拟機
    System.exit(1);
} finally {
    System.out.println("Finally");
}      

輸出:

Try to do something
Catch Exception -> RuntimeException      

另外,在以下 2 種特殊情況下,​

​finally​

​ 塊的代碼也不會被執行:

  1. 程式所在的線程死亡。
  2. 關閉 CPU。

相關 issue: ​​https://github.com/Snailclimb/JavaGuide/issues/190​​。

🧗🏻 進階一下:從位元組碼角度分析​

​try catch finally​

​這個文法糖背後的實作原理。

6、如何使用 ​

​try-with-resources​

​​ 代替​

​try-catch-finally​

​?

  1. 适用範圍(資源的定義):任何實作​

    ​java.lang.AutoCloseable​

    ​​或者​

    ​java.io.Closeable​

    ​ 的對象
  2. 關閉資源和 finally 塊的執行順序:在​

    ​try-with-resources​

    ​ 語句中,任何 catch 或 finally 塊在聲明的資源關閉後運作

《Effective Java》中明确指出:

面對必須要關閉的資源,我們總是應該優先使用 ​

​try-with-resources​

​​ 而不是​

​try-finally​

​​。随之産生的代碼更簡短,更清晰,産生的異常對我們也更有用。​

​try-with-resources​

​​語句讓我們更容易編寫必須要關閉的資源的代碼,若采用​

​try-finally​

​則幾乎做不到這點。

Java 中類似于​

​InputStream​

​​、​

​OutputStream​

​​ 、​

​Scanner​

​​ 、​

​PrintWriter​

​​等的資源都需要我們調用​

​close()​

​​方法來手動關閉,一般情況下我們都是通過​

​try-catch-finally​

​語句來實作這個需求,如下:

//讀取文本檔案的内容
Scanner scanner = null;
try {
    scanner = new Scanner(new File("D://read.txt"));
    while (scanner.hasNext()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} finally {
    if (scanner != null) {
        scanner.close();
    }
}      

使用 Java 7 之後的 ​

​try-with-resources​

​ 語句改造上面的代碼:

try (Scanner scanner = new Scanner(new File("test.txt"))) {
    while (scanner.hasNext()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException fnfe) {
    fnfe.printStackTrace();
}      

當然多個資源需要關閉的時候,使用 ​

​try-with-resources​

​​ 實作起來也非常簡單,如果你還是用​

​try-catch-finally​

​可能會帶來很多問題。

通過使用分号分隔,可以在​

​try-with-resources​

​塊中聲明多個資源。

try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));
     BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")))) {
    int b;
    while ((b = bin.read()) != -1) {
        bout.write(b);
    }
}
catch (IOException e) {
    e.printStackTrace();
}      

7、異常使用有哪些需要注意的地方?

  • 不要把異常定義為靜态變量,因為這樣會導緻異常棧資訊錯亂。每次手動抛出異常,我們都需要手動 new 一個異常對象抛出。
  • 抛出的異常資訊一定要有意義。
  • 建議抛出更加具體的異常比如字元串轉換為數字格式錯誤的時候應該抛出​

    ​NumberFormatException​

    ​​而不是其父類​

    ​IllegalArgumentException​

    ​。
  • 使用日志列印異常之後就不要再抛出異常了(兩者不要同時存在一段代碼邏輯中)。
《我要進大廠》- Java基礎奪命連環10問,你能堅持到第幾問?(異常 | 泛型)

二、泛型

1、什麼是泛型?有什麼作用?

Java 泛型(Generics) 是 JDK 5 中引入的一個新特性。使用泛型參數,可以增強代碼的可讀性以及穩定性。

編譯器可以對泛型參數進行檢測,并且通過泛型參數可以指定傳入的對象類型。比如 ​

​ArrayList<Persion> persons = new ArrayList<Persion>()​

​​ 這行代碼就指明了該 ​

​ArrayList​

​​ 對象隻能傳入 ​

​Persion​

​ 對象,如果傳入其他類型的對象就會報錯。

ArrayList<E> extends AbstractList<E>      

并且,原生 ​

​List​

​​ 傳回類型是 ​

​Object​

​ ,需要手動轉換類型才能使用,使用泛型後編譯器自動轉換。

2、泛型的使用方式有哪幾種?

泛型一般有三種使用方式:泛型類、泛型接口、泛型方法。

1.泛型類:

//此處T可以随便寫為任意辨別,常見的如T、E、K、V等形式的參數常用于表示泛型
//在執行個體化泛型類時,必須指定T的具體類型
public class Generic<T>{

    private T key;

    public Generic(T key) {
        this.key = key;
    }

    public T getKey(){
        return key;
    }
}      

如何執行個體化泛型類:

Generic<Integer> genericInteger = new Generic<Integer>(123456);      

2.泛型接口 :

public interface Generator<T> {
    public T method();
}      

實作泛型接口,不指定類型:

class GeneratorImpl<T> implements Generator<T>{
    @Override
    public T method() {
        return null;
    }
}      

實作泛型接口,指定類型:

class GeneratorImpl<T> implements Generator<String>{
    @Override
    public String method() {
        return "hello";
    }
}      

3.泛型方法 :

public static < E > void printArray( E[] inputArray )
   {
         for ( E element : inputArray ){
            System.out.printf( "%s ", element );
         }
         System.out.println();
    }      

使用:

// 建立不同類型數組: Integer, Double 和 Character
Integer[] intArray = { 1, 2, 3 };
String[] stringArray = { "Hello", "World" };
printArray( intArray  );
printArray( stringArray  );      

3、項目中哪裡用到了泛型?

  • 自定義接口通用傳回結果​

    ​CommonResult<T>​

    ​​ 通過參數​

    ​T​

    ​ 可根據具體的傳回類型動态指定結果的資料類型
  • 定義​

    ​Excel​

    ​​ 處理類​

    ​ExcelUtil<T>​

    ​​ 用于動态指定​

    ​Excel​

    ​ 導出的資料類型
  • 建構集合工具類(參考​

    ​Collections​

    ​​ 中的​

    ​sort​

    ​​,​

    ​binarySearch​

    ​ 方法)。

總結

OK,今天關于**Java異常、泛型面試題總結*就到這裡的,希望本篇文章能夠幫助到大家,同時也希望大家看後能學有所獲!!!