2016-01-07 40 views
2

我讀過關於java異常處理的很多帖子,但我確實得到了滿足的答案。爲什麼我應該把它們放在我的代碼中?爲什麼我應該在Java中使用異常處理?

  1. 我想使用JRE的一些api方法,這些都是通過檢查異常進行的。所以,如果我想使用它們,我需要拋出或捕獲異常(例如,Java I/O)。這是在我的課堂中使用例外的合理規則嗎?
  2. 我聽說過這個

Java異常handlings讓從我 業務邏輯分離的錯誤處理代碼

哪裏是分離的錯誤處理如下片段?

public int division(int divident, int divisor) { 
int result = 0; 
try { 
    result = divident/divisor; 
} catch (ArithmeticException e) { 
    System.out.println("Divisor must not be zero !"); 
} 
return result; 
} 

3. Java的默認異常處理使得在標準輸出中顯示異常信息並終止程序。我是否使用異常處理來避免終止我的程序?

+2

這是三個不同的問題,而不是* a *問題。 –

+0

#1中的問題是什麼?是的,你必須處理它們或宣佈它們。 –

+0

關於Q2,假設'result'被用作業務邏輯中的一個關鍵值,那麼只有當你的代碼是一個有效變量的時候,你纔想把'result'賦給你的代碼,在'try'塊中如果沒有拋出異常,則使用'result'。如果拋出異常,你可以在'catch'塊中給'result'一個默認值。因此,您的業務邏輯代碼從不受由於result變量引發的異常的影響。 – OPK

回答

5

這是三個問題,但這不是第一次發生在這裏。 :-)

  1. 是的,你必須處理它們或聲明它們,因爲它們是檢查異常。你必須這麼做的原因是,調用你的代碼的代碼知道你的代碼可能失敗的方式(因爲你聲明瞭它可以拋出的異常)。

  2. 這段代碼非常簡單,所以分離和收益並不是那麼明顯。但考慮打開兩個流,使用轉換代碼(包括調用從屬方法)從一個到另一個進行復制。最終你會得到一個有10-20個語句的方法體。而不是每個I/O語句必須檢查它是否工作,只需編寫包含在IOException處理程序中的邏輯,知道任何I/O異常都會跳出主邏輯處理程序。

  3. 這取決於您正在編寫什麼類型的程序,但通常情況下,您會在最適合的級別處理異常,這通常是在程序中的多個級別。最外層只處理真正非常不尋常的不可恢復的異常,或者只是讓缺省處理完成它所做的事情,或者使用一個完全相同的處理程序,但可能會(嘗試)記錄失敗在其他地方(如日誌文件),以及:

    public class MyProgram { 
        public static final void main(String[] args) { 
         try { 
          // Run... 
         } 
         catch (Throwable t) { 
          // Handle the fact that something went wrong here, if you can 
          // Usually this would be only for really, really unusual errors, 
          // otherwise you would have handled them earlier 
         } 
        } 
    } 
    

爲了強調在#2點,考慮兩種process方法,一個在Java中有例外,和其他在一個假設的類似Java的語言沒有例外:

Java之一:

private void process() { 
    try (            // <== Main logic 
     Reader fr = new FileReader(this.sourceFileName); // <== Main logic 
     BufferedReader br = new BufferedReader(fr);  // <== Main logic 
     Writer fw = new FileWriter(this.destFileName); // <== Main logic 
     BufferedWriter bw = new BufferedWriter(fw)  // <== Main logic 
     ) {            // <== Main logic 
     String line;          // <== Main logic 
     while ((line = br.readLine()) != null) {   // <== Main logic 
      if (shouldIncludeLine(line)) {    // <== Main logic 
       line = transformLine(line);    // <== Main logic 
       bw.write(line);       // <== Main logic 
       bw.newLine();       // <== Main logic 
      }           // <== Main logic 
     }            // <== Main logic 
    } 
    catch (FileNotFoundException fnfe) {     // <== Error handling 
     // Couldn't find a file       // <== Error handling 
     // (handle it)         // <== Error handling 
    }             // <== Error handling 
    catch (IOException ioe) {       // <== Error handling 
     // I/O error          // <== Error handling 
     // (handle it)         // <== Error handling 
    }             // <== Error handling 
    catch (Exception e) {        // <== Error handling 
     // Something else went wrong      // <== Error handling 
     // (handle it)         // <== Error handling 
    }             // <== Error handling 
} 

假設的類似Java的語言沒有例外之一:

// THIS IS FAKE, PSEUDO-JAVA 
private Errors process() { 
    Reader fr = new FileReader(this.sourceFileName);   // <== Main logic 
    if (fr == null) {           // <== Error handling 
     return Errors.CantOpenSource;       // <== Error handling 
    }               // <== Error handling 
    BufferedReader br = new BufferedReader(fr);     // <== Main logic 

    Writer fw = new FileWriter(this.destFileName);    // <== Main logic 
    if (fw == null) {           // <== Error handling 
     br.close();            // <== Error handling 
     return Errors.CantOpenDest;        // <== Error handling 
    }               // <== Error handling 
    BufferedWriter bw = new BufferedWriter(fw)     // <== Main logic 

    String line;            // <== Main logic 
    while ((line = br.readLine()) != IO.END_OF_FILE) {   // <== Main logic 
     if (line == null) {          // <== Error handling 
      br.close();           // <== Error handling 
      bw.close();           // <== Error handling 
      return Errors.CantRead;        // <== Error handling 
     } 
     if (shouldIncludeLine(line)) {       // <== Main logic 
      line = transformLine(line);       // <== Main logic 
      if (bw.write(line) == -1 || bw.newLine() == -1) { // <== Main logic (plus some error handling) 
       br.close();          // <== Error handling 
       bw.close();          // <== Error handling 
       return Errors.CantWrite;      // <== Error handling 
      } 
     } 
    } 

    bw.close(); 
    br.close(); 
    return Errors.Success; 
} 

注意:

  • 的主要邏輯是如何充斥着錯誤處理,使其難以閱讀和遵守。
  • 特殊的「錯誤」返回值對於任何可能存在某種故障模式的方法都是必需的。我們必須添加一個process,然後我們從new FileReader和這樣的檢查null,和讀取檢查-1和寫OPS等

如果你有興趣,這裏是一個完整的Java程序的版本與完整版的沒有,真正的Java程序:

的Java:

import java.io.*; 

public class Example 
{ 
    private String sourceFileName; 
    private String destFileName; 

    public static void main (String[] args) throws java.lang.Exception 
    { 
     try { 
      new Example(args[0], args[1]).process(); 
     } 
     catch (ArrayIndexOutOfBoundsException npe) { 
      // This is a bit of an exaggeration, I'd check in advance, since the user not 
      // supplying arguments isn't really an "exceptional" condition. 
      System.out.println("Usage: java Example [source file name] [dest file name]"); 
     } 
    } 

    public Example(String src, String dest) { 
     // Similar, these checks would probably be assertions, but I'm making a point... 
     if (src == null || src.length() == 0) { 
      throw new IllegalArgumentException("src must be non-null and non-blank"); 
     } 
     if (dest == null || dest.length() == 0) { 
      throw new IllegalArgumentException("dest must be non-null and non-blank"); 
     } 
     this.sourceFileName = src; 
     this.destFileName = dest; 
    } 

    private void process() { 
     try (            // <== Main logic 
      Reader fr = new FileReader(this.sourceFileName); // <== Main logic 
      BufferedReader br = new BufferedReader(fr);  // <== Main logic 
      Writer fw = new FileWriter(this.destFileName); // <== Main logic 
      BufferedWriter bw = new BufferedWriter(fw)  // <== Main logic 
      ) {            // <== Main logic 
      String line;          // <== Main logic 
      while ((line = br.readLine()) != null) {   // <== Main logic 
       if (shouldIncludeLine(line)) {    // <== Main logic 
        line = transformLine(line);    // <== Main logic 
        bw.write(line);       // <== Main logic 
        bw.newLine();       // <== Main logic 
       }           // <== Main logic 
      }            // <== Main logic 
     } 
     catch (FileNotFoundException fnfe) {     // <== Error handling 
      // Couldn't find a file       // <== Error handling 
      // (handle it)         // <== Error handling 
     }             // <== Error handling 
     catch (IOException ioe) {       // <== Error handling 
      // I/O error          // <== Error handling 
      // (handle it)         // <== Error handling 
     }             // <== Error handling 
     catch (Exception e) {        // <== Error handling 
      // Something else went wrong      // <== Error handling 
      // (handle it)         // <== Error handling 
     }             // <== Error handling 
    } 

    private boolean shouldIncludeLine(String line) { 
     return line.length() != 0; 
    } 

    private String transformLine(String line) { 
     return line.toUpperCase(); 
    } 
} 

毫無例外一個假設的類似Java的語言:

// THIS IS FAKE, PSEUDO-JAVA WITHOUT EXCEPTIONS, IT ISN'T REAL 
import java.io.*; 

public class Example 
{ 
    private String sourceFileName; 
    private String destFileName; 

    private enum Errors { 
     Success, 
     CantOpenSource, 
     CantOpenDest, 
     CantRead, 
     CantWrite 
    } 

    public static void main (String[] args) throws java.lang.Exception 
    { 
     if (args.length < 2) { 
      System.out.println("Usage: java Example [source file name] [dest file name]"); 
     } 
     if (args[0] == null || args[0].length() == 0) { 
      throw new IllegalArgumentException("src must be non-null and non-blank"); 
     } 
     if (args[1] == null || args[1].length() == 0) { 
      throw new IllegalArgumentException("dest must be non-null and non-blank"); 
     } 
     switch (new Example(args[0], args[1]).process()) { 
      case Errors.CantOpenSource: 
       // Handle it 
       break; 
      case Errors.CantOpenDest: 
       // Handle it 
       break; 
      case Errors.CantRead: 
       // Handle it 
       break; 
      case Errors.CantWrite: 
       // Handle it 
       break; 
     } 
    } 

    public Example(String src, String dest) { 
     // Not how now this constructor is trusting that it is called with valid arguments 
     this.sourceFileName = src; 
     this.destFileName = dest; 
    } 

    private Errors process() { 
     Reader fr = new FileReader(this.sourceFileName);   // <== Main logic 
     if (fr == null) {           // <== Error handling 
      return Errors.CantOpenSource;       // <== Error handling 
     }               // <== Error handling 
     BufferedReader br = new BufferedReader(fr);     // <== Main logic 

     Writer fw = new FileWriter(this.destFileName);    // <== Main logic 
     if (fw == null) {           // <== Error handling 
      br.close();            // <== Error handling 
      return Errors.CantOpenDest;        // <== Error handling 
     }               // <== Error handling 
     BufferedWriter bw = new BufferedWriter(fw)     // <== Main logic 

     String line;            // <== Main logic 
     while ((line = br.readLine()) != IO.END_OF_FILE) {   // <== Main logic 
      if (line == null) {          // <== Error handling 
       br.close();           // <== Error handling 
       bw.close();           // <== Error handling 
       return Errors.CantRead;        // <== Error handling 
      } 
      if (shouldIncludeLine(line)) {       // <== Main logic 
       line = transformLine(line);       // <== Main logic 
       if (bw.write(line) == -1 || bw.newLine() == -1) { // <== Main logic (plus some error handling) 
        br.close();          // <== Error handling 
        bw.close();          // <== Error handling 
        return Errors.CantWrite;      // <== Error handling 
       } 
      } 
     } 

     bw.close(); 
     br.close(); 
     return Errors.Success; 
    } 

    private boolean shouldIncludeLine(String line) { 
     return line.length() != 0; 
    } 

    private String transformLine(String line) { 
     return line.toUpperCase(); 
    } 
} 
+0

我不認爲我的1,2,3是單獨的問題。他們只是我的OP的子問題,「他們是使用異常處理的原因嗎?」。謝謝你的回答,先生。 – Cataclysm

+0

對於你的子程序#3,你想說「不....異常處理不是爲了避免程序終止。你可以用其他方式跳過java的默認異常處理而不用自己的異常處理?」。 – Cataclysm

+0

@Cataclysm:我不明白你最後的問題。在程序的每個級別,您都可以選擇處理或聲明可能發生的錯誤。在程序的頂層,您可以選擇以任何方式自己處理這些問題,然後或者不終止(如果可以恢復)或終止(如果不能)。 –

1

1)如果是不合理的代碼能夠處理異常,你可以捕捉從您的API調用拋出的checked異常,並在未經檢查的異常包裝它們。確保將原始檢查的異常保存爲新的未經檢查的異常。

2)您的示例代碼片段不會將業務邏輯中的錯誤處理分離出來,而是將它們拼湊在一起並混淆結果。在這裏拋出算術異常有兩個好處,而不是傳回一個默認值:a)很難區分傳遞來標記錯誤的值和作爲有效計算結果的值,並且b)進一步的業務邏輯步驟可能取決於在這裏計算了一個有效值,在這種情況下,您將不得不離開當前流程,您也可以使用該例外。

3)這取決於應用程序。對於一個簡單的控制檯程序,有時候最好的做法是讓錯誤終止程序。對於Web應用程序,異常通常會冒泡到全局異常處理程序,終止該請求但讓其他請求繼續。對於單元測試,測試運行器會捕獲異常並進行記錄,以便其他測試可以繼續進行。

+0

否#3 .....是的,先生..我忘了。我認爲Web應用程序也會因錯誤而終止爲簡單的控制檯程序。 「......終止該請求,但讓其他請求繼續進行」謝謝先生。 – Cataclysm