前言
異常層次結構圖:
一、概述
- 異常機制:程式在執行過程中發生了不正常的情況。
代碼示範:
public class ExceptionText {
public static void main(String[] args) {
int a=100;
int b=0;
System.out.println(a/b);
}
}
運作結果:
沒有正确輸出,抛出了被 0 除異常
通過以上示例,我們看到 java 給我們提供了這樣一個體系結構,當出現問題的時候,它會告
訴我們,并且把錯誤的詳細資訊也告訴我們了,這就是異常的體系結構,這樣我們的程式更健
壯,我們可以把這個資訊,再進行處理以下告訴使用者。從上面大家還可以看到,java 異常都是
類,在異常類中會攜帶一些資訊給我們,我們可以通過這個類把資訊取出來
- java提供異常處理機制,将不正常情況輸出在控制台,供程式員參考,修改代碼,提高代碼的健壯性!!!
- 例如常見的:
、ArrayIndexOutOfBoundsException異常
、ClassCastException異常
NullPointerException異常
- 異常在java中以類和對象的形式存在每個類可以建立對象。
-
Throwable下有兩個分支:Error(不可處理,直接退出JVM)和Exception(可處理的)
Exception下有兩個分支:Exception的直接子類:編譯時異常(要求程式員在編寫程式階段必須預先對這些異常進行處理,如果不處理編譯器報錯)。RuntimeException:運作時異常。(在編寫程式階段程式員可以預先處理,也可以不處理)
- 編譯時異常(受控異常)和運作時異常(非受控異常),都是發生在運作階段。
- 編譯時異常和運作時異常的差別?
編譯時異常一般發生的機率比較高。
舉個例子:
你看到外面下雨了,傾盆大雨的。
你出門之前會預料到:如果不打傘,我可能會生病(生病是一種異常)。
而且這個異常發生的機率很高,是以我們出門之前要拿一把傘。
“拿一把傘”就是對“生病異常”發生之前的一種處理方式。
對于一些發生機率較高的異常,需要在運作之前對其進行預處理。
運作時異常一般發生的機率比較低。
舉個例子:
小明走在大街上,可能會被天上的飛機輪子砸到。
被飛機輪子砸到也算一種異常。
但是這種異常發生機率較低。
在出門之前你沒必要提前對這種發生機率較低的異常進行預處理。
如果你預處理這種異常,你将活的很累。
二、異常處理
Java中異常處理有兩種方式:
- 在方法聲明的位置上,使用throws關鍵字,抛給上一級。誰調用我,我就抛給誰。抛給上一級。
public class ExceptionText {
public static void main(String[] args) throws Exception{
int a=100;
int b=0;
divide(a,b);
}
public static void divide(int a, int b) throws Exception{
int c = a / b;
System.out.println(c);
}
}
- 使用try…catch語句進行異常的捕捉。
public class ExceptionText {
public static void main(String[] args){
int a=100;
int b=0;
try {
divide(a,b);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void divide(int a, int b) throws Exception{
int c = a / b;
System.out.println(c);
}
注意:
1.Java中異常發生之後如果一直上抛,最終抛給了main方法,main方法繼續向上抛,抛給了調用者JVM,JVM知道這個異常發生,隻有一個結果。終止java程式的執行。
2.try語句中某一行出現異常該行後續代碼不執行try…catch捕獲後,後續代碼可執行。
try…catch和finally概述
- 文法格式:
try {
}catch(OneException e) {
}catch(TwoException e) {
}finally {
}
- try 中包含了可能産生異常的代碼
- try 後面是 catch,catch 可以有一個或多個,catch 中是需要捕獲的異常
-
finally 表示:不管是出現異常,還是沒有出現異常,finally 裡的代碼都執行,finally 和 catch
可以分開使用,但 finally 必須和 try 一塊使用
try {
}finally {
}
-
jdk8新特性!!catch(異常1 | 異常2 |異常3 |......)
示例代碼(1):
public class ExceptionText {
public static void main(String[] args){
int a=100;
int b=0;
try {
divide(a,b);
//上一行代碼有異常,直接進入catch裡面!!
System.out.println("我能執行嗎?");
} catch (Exception e) {
System.out.println("被0除了!!");
}
}
public static void divide(int a, int b) throws Exception{
int c = a / b;
System.out.println(c);
}
}
運作結果:
被0除了!!
示例代碼(2):
public class ExceptionText {
public static void main(String[] args){
int a=100;
int b=0;
try {
divide(a,b);
//上一行代碼有異常,直接進入catch裡面!!
System.out.println("我能執行嗎?");
} catch (Exception e) {
System.out.println("被0除了!!");
}finally {
System.out.println("finally執行了!!");
}
}
public static void divide(int a, int b) throws Exception{
int c = a / b;
System.out.println(c);
}
}
運作結果:
被0除了!!
finally執行了!!
throws與try…catch如何選擇?
需要上報異常使用throws,需要捕獲異常時使用try…catch進行捕獲!!
finally重要面試題:
示例代碼(3):
public class FinallyText {
public static void main(String[] args) {
System.out.println(n());
}
public static int n(){
int i=100;
try {
return i;
}finally {
i++;
}
}
}
運作結果:你們猜猜?有興趣的鐵子評論區讨論讨論一番哦!!!
final、finalize 和 finally差別詳述。
- final:是一個關鍵字,表示最終的,不變的,可修飾屬性、方法等!
- finalize:是Object類的一個方法,無需程式員調用,JVM垃圾回收器GC調用。
- finally:與try一起使用,異常處理機制中,finally語句塊一定執行!!
三、異常中兩個迷人的方法
取得異常描述資訊:getMessage()
示例代碼(4):
public class ExceptionText01 {
public static void main(String[] args) {
int a=100;
int b=0;
try {
int c=a/b;
System.out.println(c);
}catch (ArithmeticException e){
//e 是一個引用,它指向了堆中的 ArithmeticException
//通過 getMessage 可以得到異常的描述資訊
System.out.println(e.getMessage());
}
}
}
運作結果:
/ by zero
找不同:找一找下面的結果和上面的結果有什麼不同?
取得異常的堆棧資訊(比較适合于程式調試階段):printStackTrace();
示例代碼(5):
public class ExceptionText01 {
public static void main(String[] args) {
int a=100;
int b=0;
try {
int c=a/b;
System.out.println(c);
}catch (ArithmeticException e){
//e 是一個引用,它指向了堆中的 ArithmeticException
//通過 printStackTrace 可以列印棧結構
e.printStackTrace();
}
}
}
運作結果:
比較比較兩個方法在運作結束後,各有什麼不同呢!!!
四、手動抛異常
話不多說,直接上代碼!!!
示例代碼(6):
public static void main(String[] args) {
int ret = method1(1000, 10);
if (ret == -1) {
System.out.println("除數為 0");
}
if (ret == -2) {
System.out.println("被除數必須為 1~100 之間的資料");
}
if (ret == 1) {
System.out.println("正确");
}
}
private static int method1(int value1, int value2){
if (value2 == 0) {
return -1;
}
if (!(value1 >0 && value1<=100)) {
return -2;
}
int value3 = value1/value2;
System.out.println("value3=" + value3);
return 1;
}
運作結果:
被除數必須為 1~100 之間的資料
将以上代碼與以下代碼作比較,找不同!!
示例代碼(7):
public static void main(String[] args) {
try {
int ret = method1(1000, 10);
System.out.println(ret);
}catch(Exception iae) { //可以采用 Exception 攔截所有的異常
System.out.println(iae.getMessage());
}
}
private static int method1(int value1, int value2){
if (value2 == 0) {
//手動抛出異常
throw new IllegalArgumentException("除數為 0");
}
if (!(value1 >0 && value1<=100)) {
//手動抛出異常
throw new IllegalArgumentException("被除數必須為 1~100 之間的資料");
}
int value3 = value1/value2;
return value3;
}
運作結果:
被除數必須為 1~100 之間的資料
我們不難看出,使用throw抛出異常的形式來編寫代碼,代碼會變得更加美觀,更加高大上,更加無懈可擊,換句話說,代碼不會太Low!!!(小編建議大家以後可以多多使用)
throws 和 throw 的差別?
thorws 是聲明異常,throw是抛出異常
五、神奇的自定義異常
第一步:編寫一個類,繼承Exception或RunTimeException.
第二步:提供兩個構造方法。
示例代碼(8):
public class MyException extends Exception{
public MyException() {
}
public MyException(String s) {
super(s);
}
}
小試牛刀:
編寫程式模拟使用者注冊:
1、程式開始執行時,提示使用者輸入“使用者名”和“密碼”資訊。
2、輸入資訊之後,背景java程式模拟使用者注冊。
3、注冊時使用者名要求長度在[6-14]之間,小于或者大于都表示異常。
代碼示範:
使用者注冊類:
/**
*使用者登入
* @username 使用者名
* @password 密碼
* 當使用者名為null,使用者名要求長度在[6-14]之間,小于或者大于都表示異常。
*/
class UserService {
public void register(String username, String password) throws MyException {
if (null==username || username.length() <= 6 || username.length() >= 14) {
throw new MyException("輸入有誤,請輸入6~14之間的使用者名");
}
System.out.println("恭喜你注冊成功!!");
}
}
自定義異常類:
public class MyException extends Exception{
public MyException() {
}
public MyException(String s) {
super(s);
}
}
測試類:
public class ExceptionText {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("請輸入使用者名:");
String str = input.nextLine();
System.out.println("請輸入密碼:");
String passWord = input.next();
UserService userService = new UserService();
try {
userService.register(str, passWord);
} catch (MyException e) {
// e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
請輸入使用者名:
小馬
請輸入密碼:
123456
輸入有誤,請輸入6~14之間的使用者名
請輸入使用者名:
鵝廠小馬前來報到
請輸入密碼:
123456789
恭喜你注冊成功!!