激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

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

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給我們提供的異常機制,它好似一個長者,時不時給我們指引道路,也讓我們在編碼的時候沒有那么無聊:)

延伸 · 閱讀

精彩推薦
265
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25
主站蜘蛛池模板: 97超级碰碰人国产在线观看 | 亚洲国产精品一 | 午夜视频在线观看免费视频 | 欧美顶级毛片在线播放小说 | 一级在线免费观看视频 | 免费a级黄色片 | 国产品久久 | 亚洲一区二区三区四区精品 | 国产精品字幕 | 欧产日产国产精品v | 欧美一级片免费在线观看 | 中国一级免费视频 | 欧美性生交大片 | 国产成人77亚洲精品www | 免费看黄色一级大片 | 免费黄色欧美视频 | 91国内精品久久久久免费影院 | 7777网站 | 玩偶姐姐在线观看免费 | 黄免费在线 | 91青青 | 久久国产精品免费视频 | 一级黄色国产视频 | 蜜桃网站免费 | 日本一区免费看 | 亚洲网站在线观看视频 | 黑人一级片视频 | a视频在线看 | 伊人欧美 | 精品一区二区久久久久 | 日韩美香港a一级毛片 | 久久精品免费国产 | 黄色毛片视频在线观看 | 国产大片中文字幕在线观看 | 久久99精品久久久久久园产越南 | 欧美一区二区三区中文字幕 | 国产做爰全免费的视频黑人 | 99这里有精品 | 中文字幕在线播放一区 | 中文字幕在线观看免费 | 亚洲无马在线观看 |