一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - 簡單談談java的異常處理(Try Catch Finally)

簡單談談java的異常處理(Try Catch Finally)

2020-04-13 11:29hebedich JAVA教程

在程序設計中,進行異常處理是非常關鍵和重要的一部分。一個程序的異常處理框架的好壞直接影響到整個項目的代碼質量以及后期維護成本和難度。

異常的英文單詞是exception,字面翻譯就是“意外、例外”的意思,也就是非正常情況。事實上,異常本質上是程序上的錯誤,包括程序邏輯錯誤和系統錯誤。

一 前言

java異常處理大家都不陌生,總的來說有下面兩點:

1.拋出異常:throw exception

?
1
2
3
4
5
class SimpleException{
  public void a() throws Exception{
    throw new Exception();
  };
}

2.捕獲異常:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyException {
  public static void main(String[] args){
    MyException e = new MyException();
    SimpleException se = new SimpleException();
    try {
      se.a();
    } catch (Exception e1) {
      e1.printStackTrace();
    }
  }
}
 
class SimpleException{
  public void a() throws Exception{
    throw new Exception();
  };

本文將在此基礎上,更加深入的談一些細節問題。

二 自定義異常類

java語言為我們提供了很多異常類,但是有時候我們為了寫代碼的方便還是要自定義的去創造異常類:

class SimpleException extends Exception {};
創建好之后我們可以使用try catch捕獲它:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MyException {
  public static void main(String[] args){
    MyException e = new MyException();
    try {
      e.a();
    } catch (SimpleException e1) {
      e1.printStackTrace();
    }
  }
  
  public void a() throws SimpleException{
    throw new SimpleException();
  }
}
 
class SimpleException extends Exception {};

我們在MyException中定義了一個方法a(),讓它拋出SimpleException異常,然后我們在main()中調用這個方法,并使用try catch捕獲了這個異常:

?
1
2
3
4
5
6
7
8
9
10
SimpleException
  at MyException.a(MyException.java:15)
  at MyException.main(MyException.java:8)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:606)
  at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
 
Process finished with exit code 0

編譯執行后的結果,主要看前三行就行了。這里著重說明幾點:
1.拋出異常類型的指定:(exception specification)
當我們需要在一個方法中拋出一個異常時,我們使用throw后加某異常類的實例,程序會在此向客戶端程序(調用這段代碼的程序)拋出對應異常并在此退出(相當于return)。另外需要注意的是,我們必須在定義該方法的時候指明異常類型,比如下面這段代碼會拋出SimpleException異常

public void a() throws SimpleException

2.拋出多個異常:

?
1
2
3
4
public void a() throws SimpleException,AException,BException{
  throw new SimpleException();
  
}

不同的異常類之間用逗號隔開即可,在這種情況下我們不必須throw每個異常類的實例(),但是客戶端代碼必須要catch到每個異常類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyException {
  public static void main(String[] args){
    MyException e = new MyException();
    try {
      e.a();
    } catch (SimpleException e1) {
      e1.printStackTrace();
    } catch (BException e1) {
      e1.printStackTrace();
    } catch (AException e1) {
      e1.printStackTrace();
    }
  }
 
  public void a() throws SimpleException,AException,BException{
    throw new SimpleException();
    
  }
}
 
class SimpleException extends Exception {};
class AException extends Exception{}
class BException extends Exception{}

三 stack trace

無論是拋出異常,或者是捕獲處理異常,我們的目的是為了寫出更健壯的程序,這很大程度上依賴于java異常機制給我們提供的異常信息,而它的載體就是stack trace。
前面的代碼中我們直接使用printStackTrace()打印出異常信息,其實我們還可以使用getStackTrace()方法來獲取StackTraceElement型的集合,如果你手頭有IDEA的話,你可以先搜索出StackTraceElement類,可以發現它實現了接口Serializable ,再看看它的類描述:

?
1
2
3
4
5
6
7
8
9
10
11
12
/**
 * An element in a stack trace, as returned by {@link
 * Throwable#getStackTrace()}. Each element represents a single stack frame.
 * All stack frames except for the one at the top of the stack represent
 * a method invocation. The frame at the top of the stack represents the
 * execution point at which the stack trace was generated. Typically,
 * this is the point at which the throwable corresponding to the stack trace
 * was created.
 *
 * @since 1.4
 * @author Josh Bloch
 */

講的很清楚,這個類的每個實例都是stack trace的一個元素,代表著一個stack frame,stack trace是由getStackTrace()方法返回的。后邊的我試著翻譯了幾遍,都覺得不好,還是直接上代碼才能說清楚:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MyException {
  public static void main(String[] args){
    MyException e = new MyException();
    e.a();
 
  public void a(){
    try {
      throw new Exception();
    } catch (Exception e) {
      StackTraceElement[] ste = e.getStackTrace();
      System.out.println(ste.length);
 
    }
  }
}

我們定義了方法a,讓它拋出Exception異常的同時捕獲它,然后我們通過getStackTrace()方法得到一個StackTraceElement型的數組,并打印出數組的長度:

7

Process finished with exit code 0
我們把代碼稍微改一下,不在a中捕獲異常了,我們重新定義一個方法b,讓它在調用a的同時將異常捕獲:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MyException {
  public static void main(String[] args){
    MyException e = new MyException();
    e.b();
  }
 
  public void b(){
    try {
      a();
    } catch (Exception e) {
      StackTraceElement[] ste = e.getStackTrace();
      System.out.println(ste.length);
    }
  }
 
  public void a() throws Exception{
    throw new Exception();
  }
}

結果如下:

8

Process finished with exit code 0
別急,我們再來看點有趣的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class MyException {
  public static void main(String[] args){
    MyException exception = new MyException();
    try {
      exception.c();
    } catch (Exception e) {
      StackTraceElement[] ste = e.getStackTrace();
      System.out.println(ste.length);
      System.out.println("---------------------------------------------------------------");
      for (StackTraceElement s : e.getStackTrace()){
        System.out.println(s.getClassName()+":method "+s.getMethodName()+" at line"+s.getLineNumber());
      }
      System.out.println("---------------------------------------------------------------");
 
    }
 
  }
 
 public void c() throws Exception{
    try {
      a();
    }catch (Exception e){
      throw e;
    }
  }
 
  public void a() throws Exception{
    throw new Exception();
  }
}

下面是結果:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
8
---------------------------------------------------------------
MyException:method a at line43
MyException:method c at line39
MyException:method main at line9
sun.reflect.NativeMethodAccessorImpl:method invoke0 at line-2
sun.reflect.NativeMethodAccessorImpl:method invoke at line57
sun.reflect.DelegatingMethodAccessorImpl:method invoke at line43
java.lang.reflect.Method:method invoke at line606
com.intellij.rt.execution.application.AppMain:method main at line144
---------------------------------------------------------------
 
Process finished with exit code 0

也就是說,getStackTrace()返回一個棧,它包含從調用者(main())到初始拋出異常者(a())的一些基本信息 ,在上面的代碼中,我們在c方法中調用a方法時捕獲異常并通過throws將其再次拋出(rethrow),調用c方法的方法可以捕獲并處理異常,也可以選擇繼續拋出讓更高層次的調用者(靠近棧底)處理。rethrow雖然很方便,但存在著一些問題,我們看下面這段代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class MyException {
  public static void main(String[] args){
    MyException exception = new MyException();
    try {
      exception.c();
    } catch (Exception e) {
      e.printStackTrace(System.out);
    }
 
  }
 
  public void c() throws Exception{
    try {
      a();
    }catch (Exception e){
      throw e;
    }
  }
 
  public void a() throws Exception{
 
    throw new Exception("Exception from a()");
  }
}
java.lang.Exception: Exception from a()
  at MyException.a(MyException.java:40)
  at MyException.c(MyException.java:30)
  at MyException.main(MyException.java:21)

我們在c中重新拋出e,在main中使用 e.printStackTrace()打印出來,可以看到打印出來stack trace還是屬于a的,如果我們想把stack trace變成c的可以這么寫:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class MyException {
  public static void main(String[] args){
    MyException exception = new MyException();
 
    try {
      exception.c();
    } catch (Exception e) {
      e.printStackTrace(System.out);
    }
 
  }
 
  public void c() throws Exception{
    try {
      a();
    }catch (Exception e){
//      throw e;
      throw (Exception)e.fillInStackTrace();
    }
  }
 
  public void a() throws Exception{
 
    throw new Exception("Exception from a()");
  }
}
java.lang.Exception: Exception from a()
  at MyException.c(MyException.java:22)
  at MyException.main(MyException.java:10)

四 異常鏈 Exception chaining

先來看一個場景:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class TestException {
  public static void main(String[] args){
    TestException testException = new TestException();
    try {
      testException.c();
    } catch (CException e) {
      e.printStackTrace();
    }
  }
 
  public void a() throws AException{
    AException aException = new AException("this is a exception");
    throw aException;
  }
 
  public void b() throws BException{
    try {
      a();
    } catch (AException e) {
      throw new BException("this is b exception");
    }
  }
 
  public void c() throws CException{
    try {
      b();
    } catch (BException e) {
      throw new CException("this is c exception");
    }
  }
}
 
class AException extends Exception{
  public AException(String msg){
    super(msg);
  }
}
 
class BException extends Exception{
  public BException(String msg){
    super(msg);
  }
}
 
class CException extends Exception{
  public CException(String msg){
    super(msg);
  }
}

創建了三個異常類AException、BException、CException,然后在a()中拋出AException,在b()中捕獲AException并拋出BException,最后在c()中捕獲BException并拋出CException,結果打印如下:

?
1
2
3
CException: this is c exception
  at TestException.c(TestException.java:31)
  at TestException.main(TestException.java:8)

好,我們只看到了CException的信息,AException,BException的異常信息已丟失,這時候異常鏈的作用就出來了,看代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class TestException {
  public static void main(String[] args){
    TestException testException = new TestException();
    try {
      testException.c();
    } catch (CException e) {
      e.printStackTrace();
    }
  }
 
  public void a() throws AException{
    AException aException = new AException("this is a exception");
    throw aException;
  }
 
  public void b() throws BException{
    try {
      a();
    } catch (AException e) {
//      throw new BException("this is b exception");
      BException bException = new BException("this is b exception");
      bException.initCause(e);
      throw bException;
    }
  }
 
  public void c() throws CException{
    try {
      b();
    } catch (BException e) {
//      throw new CException("this is c exception");
      CException cException = new CException("this is c exception");
      cException.initCause(e);
      throw cException;
    }
  }
}
 
class AException extends Exception{
  public AException(String msg){
    super(msg);
  }
}
 
class BException extends Exception{
  public BException(String msg){
    super(msg);
  }
}
 
class CException extends Exception{
  public CException(String msg){
    super(msg);
  }
}

我們用initCause()方法將異常信息給串聯了起來,結果如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CException: this is c exception
  at TestException.c(TestException.java:35)
  at TestException.main(TestException.java:8)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:606)
  at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: BException: this is b exception
  at TestException.b(TestException.java:24)
  at TestException.c(TestException.java:32)
  ... 6 more
Caused by: AException: this is a exception
  at TestException.a(TestException.java:15)
  at TestException.b(TestException.java:21)
  ... 7 more
 
Process finished with exit code 0

五 后記

其實關于java異常處理還有很多需要探討的地方,但是由于我經驗有限,還不能體會的太深刻,最常用的也就是

?
1
2
3
4
5
6
7
try {
      ...
    }catch (Exception e){
      ...
    }finally {
     //不管異常會不會被捕捉或者處理都會執行的代碼,如關閉IO操作
    }

但是無論如何我們還是要感謝java給我們提供的異常機制,它好似一個長者,時不時給我們指引道路,也讓我們在編碼的時候沒有那么無聊:)

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产一级特黄在线播放 | 欧美精品久久久久久久免费观看 | 清清草在线视频 | 果冻传媒在线播放1 | 岛国在线播放v片免费 | 国偷盗摄自产福利一区在线 | 91婷婷射| 国产激情一区二区三区四区 | 亚洲国产福利精品一区二区 | 超碰成人在线播放 | 日本乱子| 2019中文字幕 | 四虎影视在线影院在线观看 | 女人和男人搞基 | 成人免费影院 | 青青精品视频 | 美女扒开尿口让男生添 漫画 | 冰山美人调教耻辱h | 精品欧美日韩一区二区三区 | xvideoscom极品肌肉警察 | 成人福利 | 国产精品毛片高清在线完整版 | 欧美日韩亚洲一区二区三区在线观看 | 国产图片一区 | 免费一级片在线 | 国产一区二区三区高清 | 国产精品天天看天天爽 | 亚洲国产高清一区二区三区 | 丰满大乳欲妇三级k8 | 3d动漫被吸乳羞羞 | 国产一区二区免费不卡在线播放 | 亚洲免费小视频 | 日韩经典在线 | 无毒成人社区 | 亚洲剧情在线观看 | 91香蕉视频在线观看 | 午夜一级免费视频 | 美女露鸡鸡 | 国产欧美va欧美va香蕉在线观看 | 波多野结衣在线中文字幕 | 青草香蕉精品视频在线观看 |