Java:检查与未经检查的异常说明

我已经阅读了StackOverFlow中有关检查与未检查异常的多篇文章。 我仍然不确定如何正确使用它们。

Joshua Bloch在“Effective Java”中表示

对可恢复条件和运行时异常使用已检查的异常进行编程错误(第2版中的项目58)

让我们看看我是否正确理解这一点。

这是我对被检查的异常的理解:

try{
    String userInput = //read in user input
    Long id = Long.parseLong(userInput);
}catch(NumberFormatException e){
    id = 0; //recover the situation by setting the id to 0
}

1.上述是否考虑检查异常?

2. RuntimeException是一个未经检查的异常吗?

这是我对未经检查的例外的理解:

try{
    File file = new File("my/file/path");
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){

//3. What should I do here?
    //Should I "throw new FileNotFoundException("File not found");"?
    //Should I log?
    //Or should I System.exit(0);?
}

4.现在,上面的代码不能成为检查异常吗? 我可以尝试恢复这种情况? 我可以吗? (注意:我的第三个问题在上面的catch

try{
    String filePath = //read in from user input file path
    File file = new File(filePath);
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){
    //Kindly prompt the user an error message
    //Somehow ask the user to re-enter the file path.
}

5.为什么人们这样做?

public void someMethod throws Exception{

}

他们为什么让这个例外冒出来? 没有更好地处理错误? 为什么冒泡?

编辑:我应该冒出确切的异常或使用异常掩盖它?

以下是我的读物

在Java中,什么时候应该创建一个检查的异常,什么时候应该是一个运行时异常?

何时选择已检查和未检查的异常


许多人说,检查异常(即应该明确捕获或重新抛出的异常)根本不应该使用。 例如,它们在C#中被淘汰,大多数语言都没有它们。 所以你总是可以抛出一个RuntimeException的子类(未经检查的异常)

然而,我认为检查异常是有用的 - 当你想强制你的API的用户考虑如何处理异常情况(如果它是可恢复的)时,它们会被使用。 只是检查的异常在Java平台中被滥用,这让人们讨厌它们。

这是我对这个话题的扩展观点。

至于具体问题:

  • NumberFormatException是否考虑检查异常?
    NumberFormatException选中(=是RuntimeException子类)。 为什么? 我不知道。 (但应该有一个方法isValidInteger(..)

  • RuntimeException是一个未经检查的异常?
    对,就是这样。

  • 我应该在这里做什么?
    这取决于这个代码在哪里以及你想要发生什么。 如果它在UI层 - 抓住它并显示警告; 如果它位于服务层 - 完全不理解它 - 让它冒泡。 只是不要吞下例外。 如果在大多数情况下发生异常,您应该选择其中的一种:

  • 记录并返回
  • 重新抛出它(声明它由方法抛出)
  • 通过在构造函数中传递当前构造函数来构造一个新的异常
  • 现在,上面的代码不能成为检查异常吗? 我可以尝试恢复这种情况? 我可以吗?
    它可能是。 但是,没有什么能够阻止你捕捉未经检查的异常

  • 为什么人们在throws子句中添加类Exception
    通常是因为人们懒得考虑要捕捉什么和重新抛出什么。 抛出Exception是一种不好的做法,应该避免。

  • 唉,没有一个规则可以让你确定何时捕捉,何时重新抛出,何时使用检查以及何时使用未检查的异常。 我同意这会导致很多混淆和很多错误的代码。 Bloch声明了一般原则(你引用了它的一部分)。 总的原则是重新抛出一个异常到你可以处理它的层。


    无论你是否抓住它,或者你在捕获块中做什么,是否有什么是“检查异常”都没有关系。 这是异常类的属性。 除RuntimeException及其子类外的任何属于Exception的子类的是检查的异常。

    Java编译器强制您捕获检查的异常或在方法签名中声明它们。 这本来是为了提高程序的安全性,但大多数人的意见似乎是不值得它创造的设计问题。

    他们为什么让这个例外冒出来? 不是处理错误越快越好? 为什么冒泡?

    因为这是例外的完整点。 没有这种可能性,你不需要例外。 它们使您能够按照您选择的级别处理错误,而不是强迫您使用最初出现的低级别方法处理错误。


  • 以上是否考虑检查异常? 否如果它是RuntimeException,则处理异常的事实不会使其成为Checked Exception。

  • RuntimeException是一个未经检查的异常? 是

  • 检查异常是java.lang.Exception的子类Unchecked Exceptions是java.lang.RuntimeException的子类

    调用抛出检查异常需要放在一个try {}块中,或者在方法的调用者的上一级处理。 在这种情况下,当前方法必须声明它抛出所述异常,以便调用者可以做出适当的安排来处理异常。

    希望这可以帮助。

    问:我应该冒出确切的异常还是使用异常屏蔽它?

    答:是的,这是一个非常好的问题和重要的设计考虑因素。 类Exception是一个非常普遍的异常类,可以用来包装内部的低级异常。 你最好创建一个自定义异常并将其包装在其中。 但是,也是一个很大的问题 - 永远不要掩盖潜在的根本原因。 为前, Dont ever做以下 -

    try {
         attemptLogin(userCredentials);
    } catch (SQLException sqle) {
         throw new LoginFailureException("Cannot login!!"); //<-- Eat away original root cause, thus obscuring underlying problem.
    }
    

    而是做以下事情:

    try {
         attemptLogin(userCredentials);
    } catch (SQLException sqle) {
         throw new LoginFailureException(sqle); //<-- Wrap original exception to pass on root cause upstairs!.
    }
    

    消除原始根本原因掩盖了超出恢复范围的实际原因对生产支持团队来说是一场噩梦,因为他们可以访问应用程序日志和错误消息。 虽然后者是一个更好的设计,但很多人不经常使用它,因为开发人员无法将底层消息传递给调用者。 因此,请牢记:无论是否包含任何特定于应用程序的异常, Always pass on the actual exception传回。

    尝试捕获RuntimeExceptions

    作为一般规则的RuntimeExceptions不应该被试用。 它们通常表示编程错误,应该单独放置。 相反,程序员应该在调用可能导致RuntimeException的代码之前检查错误条件。 例如:

    try {
        setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
    } catch (NullPointerException npe) {
       sendError("Sorry, your userObject was null. Please contact customer care.");
    }
    

    这是一个糟糕的编程习惯。 相反,应该完成一个空检查 -

    if (userObject != null) {
        setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
    } else {
       sendError("Sorry, your userObject was null. Please contact customer care.");
    }
    

    但有时候这种错误检查是昂贵的,如数字格式化,请考虑这一点 -

    try {
        String userAge = (String)request.getParameter("age");
        userObject.setAge(Integer.parseInt(strUserAge));
    } catch (NumberFormatException npe) {
       sendError("Sorry, Age is supposed to be an Integer. Please try again.");
    }
    

    在这里,预调用错误检查不值得付出努力,因为它实际上意味着在parseInt()方法内复制所有字符串到整数的转换代码 - 并且如果由开发人员实施,则容易出错。 所以最好是消除尝试抓住。

    因此,NullPointerException和NumberFormatException都是RuntimeException,因此捕获NullPointerException应该用优雅的空值检查替代,而我建议显式捕获NumberFormatException以避免可能引入容易出错的代码。

    链接地址: http://www.djcxy.com/p/17965.html

    上一篇: Java: checked vs unchecked exception explanation

    下一篇: Do try/catch blocks hurt performance when exceptions are not thrown?