簡體   English   中英

為什么要在Java中使用異常處理?

[英]Why should I use Exception handlings in Java?

我讀了許多關於Java異常處理的文章,但我的確得到了滿意的答復。為什么要將它們放入我的代碼中?

  1. 我想使用JRE的一些api方法,並且這些方法是通過檢查的異常進行的。 因此,如果要使用它們,則需要引發或捕獲異常(例如Java I / O)。 這是在我的課堂上使用異常的合理規則嗎?
  2. 我聽說過

Java異常處理使錯誤處理代碼與我的業務邏輯分離

以下代碼段在哪里分隔錯誤處理?

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的默認異常處理使得在標准輸出中顯示異常信息並終止程序。 我是否自己使用異常處理來避免終止程序?

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

  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。

如果您有興趣,這里是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();
    }
}

1)如果您的代碼無法處理異常,則可以捕獲從API調用引發的已檢查異常,並將其包裝在未檢查異常中。 確保將原始已檢查的異常保存為新未檢查的異常中的原因。

2)您的示例代碼片段並未將錯誤處理與業務邏輯分開,而是將它們組合在一起並混淆了結果。 在這里拋出算術異常而不是傳遞默認值有兩個好處:a)很難區分傳遞標記為錯誤的值和有效計算的結果,b)進一步的業務邏輯步驟可能取決於此處計算的有效值,在這種情況下,無論如何您都將不得不離開當前流,您最好為此使用例外。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM