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

文章目錄
- 一、異常
- 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 異常類層次結構圖概覽 :
1、Exception 和 Error 有什麼差別?
在 Java 中,所有的異常都有一個共同的祖先
java.lang
包中的
Throwable
類。
Throwable
類有兩個重要的子類:
-
:程式本身可以處理的異常,可以通過Exception
來進行捕獲。catch
又可以分為 Checked Exception (受檢查異常,必須處理) 和 Unchecked Exception (不受檢查異常,可以不處理)。Exception
-
:Error
屬于程式無法處理的錯誤 ,我們沒辦法通過 Error
來進行捕獲不建議通過catch
捕獲 。例如 Java 虛拟機運作錯誤(catch
)、虛拟機記憶體不夠錯誤(Virtual MachineError
)、類定義錯誤(OutOfMemoryError
)等 。這些異常發生時,Java 虛拟機(JVM)一般會選擇線程終止。NoClassDefFoundError
2、Checked Exception 和 Unchecked Exception 有什麼差別?
Checked Exception 即 受檢查異常 ,Java 代碼在編譯過程中,如果受檢查異常沒有被
catch
/
throw
處理的話,就沒辦法通過編譯 。
比如下面這段 IO 操作的代碼:
除了
RuntimeException
及其子類以外,其他的
Exception
類及其子類都屬于受檢查異常 。常見的受檢查異常有: IO 相關的異常、
ClassNotFoundException
、
SQLException
…。
Unchecked Exception 即 不受檢查異常 ,Java 代碼在編譯過程中 ,我們即使不處理不受檢查異常也可以正常通過編譯。
RuntimeException
及其子類都統稱為非受檢查異常,常見的有(建議記下來,日常開發中會經常用到):
-
(空指針錯誤)NullPointerException
-
(參數錯誤比如方法入參類型錯誤)IllegalArgumentException
-
(字元串轉換為數字格式錯誤,NumberFormatException
的子類)IllegalArgumentException
-
(數組越界錯誤)ArrayIndexOutOfBoundsException
-
(類型轉換錯誤)ClassCastException
-
(算術錯誤)ArithmeticException
-
(安全錯誤比如權限不夠)SecurityException
-
(不支援的操作錯誤比如重複建立同一使用者)UnsupportedOperationException
- …
3、Throwable 類常用方法有哪些?
-
: 傳回異常發生時的簡要描述String getMessage()
-
: 傳回異常發生時的詳細資訊String toString()
-
: 傳回異常對象的本地化資訊。使用String getLocalizedMessage()
的子類覆寫這個方法,可以生成本地化資訊。如果子類沒有覆寫該方法,則該方法傳回的資訊與Throwable
傳回的結果相同getMessage()
-
: 在控制台上列印void printStackTrace()
對象封裝的異常資訊Throwable
4、try-catch-finally 如何使用?
-
塊 : 用于捕獲異常。其後可接零個或多個try
塊,如果沒有catch
塊,則必須跟一個catch
塊。finally
-
塊 : 用于處理 try 捕獲到的異常。catch
-
塊 : 無論是否捕獲或處理異常,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 clause executes a return, the compiled code does the following:
try
- Saves the return value (if any) in a local variable.
- Executes ajsrto the code for the
clause.
finally
- Upon return from the
clause, returns the value saved in the local variable.
finally
代碼示例:
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
塊的代碼也不會被執行:
- 程式所在的線程死亡。
- 關閉 CPU。
相關 issue: https://github.com/Snailclimb/JavaGuide/issues/190。
🧗🏻 進階一下:從位元組碼角度分析
try catch finally
這個文法糖背後的實作原理。
6、如何使用 try-with-resources
代替 try-catch-finally
?
try-with-resources
try-catch-finally
- 适用範圍(資源的定義):任何實作
或者java.lang.AutoCloseable
的對象java.io.Closeable
- 關閉資源和 finally 塊的執行順序:在
語句中,任何 catch 或 finally 塊在聲明的資源關閉後運作try-with-resources
《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
- 使用日志列印異常之後就不要再抛出異常了(兩者不要同時存在一段代碼邏輯中)。
- …
二、泛型
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異常、泛型面試題總結*就到這裡的,希望本篇文章能夠幫助到大家,同時也希望大家看後能學有所獲!!!