2016-01-07 42 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