2012-03-31 252 views
3

因此,我最近編寫了一個java類,它擴展了異常,並使用該類的一個實例來檢查個案並在發生錯誤時自行拋出。我發現當main的調用者捕獲到這個異常時,它表示拋出異常的那一行是創建異常的那一行,而不是它從那裏拋出的那一行。我只是想知道爲什麼會這樣,以及它是否打算用於jvm的行爲,因爲這不是拋出異常的常見方式。如果它是有意的行爲,那麼這是合理的,因爲它看起來像從拋出異常的行號會更有用(並且可能更容易通過堆棧進行跟蹤)。樣本案例遵循展示預期行爲和意外情況。jvm異常捕獲


正常的異常投擲:

1 public class Test 
2 { 
3 public static void main(String ... args) throws Throwable 
4 { 
5  switch(5) 
6  { 
7   case 1: throw new Exception("Exception"); 
8   case 2: throw new Exception("Exception"); 
9   case 3: throw new Exception("Exception"); 
10   case 4: throw new Exception("Exception"); 
11   case 5: throw new Exception("Exception"); 
12  } 
13 } 
14 } 

輸出:

Exception in thread "main" java.lang.Exception: Exception 
    at Test.main(Test.java:11) 

我的方法(簡化):

1 public class Test 
2 { 
3 public static void main(String ... args) throws Throwable 
4 { 
5  Exception e = new Exception("Exception"); 
6  switch(5) 
7  { 
8   case 1: throw e; 
9   case 2: throw e; 
10   case 3: throw e; 
11   case 4: throw e; 
12   case 5: throw e; 
13  } 
14 } 
15 } 

輸出:

Exception in thread "main" java.lang.Exception: Exception 
    at Test.main(Test.java:5) 

回答

7

它說的異常被拋出從是從哪兒 異常被創造,而不是從那裏被扔行線。我只是想知道 這是爲什麼,以及它是否是預期的行爲爲JVM 或不

是。它不僅是有意的,而且是有記錄的。請參閱Javadoc的java.lang.Throwable:'throwable包含其創建時其線程執行堆棧的快照。'如果你不想這樣做,你可以選擇在投擲之前調用fillInStackTrace()

+0

+1正要回覆簡訊正是這個。 – hmjd 2012-03-31 08:58:07

1

JavaDoc for Throwable

通常,這是在此拋出對象創建並 拋出的點。

這有點含糊不清,但99%的時間在拋出點時創建異常。我猜創建從創建點的堆棧跟蹤更有意義,當你考慮重新拋出異常,例如:

void bar() throws Exception 
{ 
    throw Exception(); 
} 

void foo() throws Exception 
{ 
    try 
    { 
     bar(); 
    } 
    catch (Exception e) 
    { 
     throw e; 
    } 
} 

public static void main(String[] args) 
{ 
    foo(); 
} 

更爲有用知道異常是在bar()創建的,比知道它被重新拋出在foo()。如果這個信息很重要,你可以用原始參數引發一個新的異常。

UPDATE

爲了說明這一點,如果你真的想知道,這個例外是在foo()拋出那麼,你會做這foo()

void foo() throws Exception 
{ 
    try 
    { 
     bar(); 
    } 
    catch (Exception e) 
    { 
     throw new Exception("Some more useful information from foo", e); 
    } 
} 
+0

但在您的示例中,您在創建它時同時拋出異常。在這種情況下,如果異常是在別處創建的,那麼您仍然想知道它是從欄中拋出的,而不是它創建的位置。我想EJP說你可以通過調用填充堆棧跟蹤來選擇這種行爲,以便更多地解釋爲什麼他們會這樣設計throws子句。 – 2012-03-31 09:09:19

+0

我已經更新了答案。我不確定'fillInStrackTrace()'會有你正在談論的行爲。有了異常處理,你*真的希望它儘可能的明顯。特別是對於查看你的代碼的其他人。即更喜歡在同一點創建和拋出異常,這是99%的人看到堆棧跟蹤所期望的。 – SimonC 2012-03-31 09:15:23

+0

我剛測試過它,並且fillInStackTrace()按我的意圖工作。值得注意的是,在你的例子中,堆棧跟蹤顯示,異常在bar中開始,並且通過foo傳遞給main,即使沒有額外的代碼也是如此。問題不在於標準慣例是什麼,我知道我的方法似乎有點奇怪,但在上下文中相信我,這很有道理。 – 2012-03-31 09:20:52