繁体   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