为什么我应该在Java中使用Exception处理?

时间:2016-01-07 15:44:56

标签: java exception

我在SO上阅读了很多关于java异常处理的帖子,但我确实得到了满意的答案。为什么我应该把它们放在我的代码中呢?

  1. 我想使用一些JRE的api方法,这些方法是用经过检查的异常制作的。因此,如果我想使用它们,我需要抛出或捕获异常(例如.Java I / O)。这是在我班级中使用例外的合理规则吗?
  2. 我听说过这个
  3.   

    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的默认异常处理使标准输出中显示异常信息并终止程序。我是否自己使用异常处理以避免终止我的程序?

2 个答案:

答案 0 :(得分:5)

这是三个问题,但这不是第一次发生在这里。 : - )

  1. 是的,您必须处理它们或声明它们,因为它们是经过检查的例外情况。您必须这样做的原因是,调用代码的代码知道代码可能失败的方式(因为您已经声明了它可以抛出的异常)。

  2. 该片段非常简单,因此分离和好处并不是那么清楚。但考虑打开两个流,使用转换代码(包括对从属方法的调用)从一个流复制到另一个流。最终得到一个方法体,其中包含10-20个语句。您只需编写包含在IOException处理程序中的逻辑,而不是每个I / O语句都必须检查它是否有效,因为知道任何I / O异常都会跳出主逻辑进入处理程序。 / p>

  3. 这取决于您编写的程序类型,但通常您会在最合适的级别处理异常,这通常在程序中的多个级别。最外层,只处理真正的,非常不寻常的,不可恢复的异常,要么只是让默认处理执行它所做的事情,要么使用catch-all处理程序做类似但可能(尝试)记录失败其他地方(如日志文件):

    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
           }
        }
    }
    
  4. 要强调#2中的要点,请考虑两个process方法,一个是Java中的异常,另一个是假设的Java类语言,没有例外:

    Java one:

    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添加一个,然后我们从null检查new FileReader等等,并从读写操作中检查-1等。

    如果您感兴趣,这里是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 :(得分:1)

1)如果您的代码能够处理异常是不合理的,那么您可以捕获从API调用中抛出的已检查异常,并将它们包装在未经检查的异常中。确保将原始已检查的异常保存为新的未经检查的异常中的原因。

2)您的示例代码段没有将错误处理与业务逻辑分开,它将它们混合在一起并混淆了结果。这里抛出算术异常有两个好处,而不是传回一个默认值:a)很难区分传递给标记错误的值和有效计算结果的值和b)进一步的业务逻辑步骤可能取决于在这里计算了一个有效值,在这种情况下你无论如何都必须保留当前流量,你也可以使用例外。

3)这取决于应用程序。对于一个简单的控制台程序,有时最好的办法就是让错误终止程序。对于Web应用程序,异常通常会冒泡到全局异常处理程序,终止该请求但允许其他请求继续。对于单元测试,测试运行器会捕获异常并进行记录,以便其他测试可以继续进行。