了解Java中的已检查异常与未检查异常


703

约书亚·布洛赫(Joshua Bloch)在《有效的Java》中说

将检查的异常用于可恢复的条件,将运行时异常用于编程错误(第二版中的项目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{

}

为什么他们让异常冒出来?处理错误不是更好吗?为什么冒泡?

6.我应该冒充确切的异常还是使用Exception屏蔽它?

以下是我的读物

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

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


6
我有一个很好的例子,一个未经检查的异常。我有一个DataSeries类,用于保存必须始终基于时间顺序的数据。有一种方法可以DataPoint在末尾添加新内容DataSeries。如果我的所有代码在整个项目中均能正常工作,DataPoint则永远不要将a添加到末尾,因为a的日期早于末尾的日期。整个项目中的每个模块都是按照这种原则构建的。但是,我检查了这种情况,并在发生这种情况时抛出了未经检查的异常。为什么?如果发生这种情况,我想知道谁在执行此操作并修复它。
艾里克·罗伯逊

3
更增加了混乱。大约10年前,许多人提倡检查异常,但如今,越来越多的观点转向“检查异常是不好的”。(不过,我不同意这一点)
Kaj

10
它仅在处理异常有用时才有用,否则应让调用方处理它。记录并假装没有发生通常是没有用的。仅仅重新抛出它是没有意义的。包装RuntimeException并不像某些人想象的那样有用,它只是使编译器停止帮助您。(恕我直言)
彼得·劳里

40
我们应该停止使用已检查/未检查的异常情况的全面误导性术语。应将它们称为检查强制与不检查异常。
Blessed Geek 2014年

3
我还认为,第5点public void method_name会引发Exception {},为什么有人这样做?
行家ツ

Answers:


474

许多人说,根本不应该使用检查异常(即应明确捕获或重新抛出的异常)。例如,它们在C#中已被淘汰,并且大多数语言都没有它们。因此,您始终可以抛出RuntimeException(未经检查的异常)的子类

但是,我认为检查异常很有用-当您要强制API用户考虑如何处理特殊情况(如果可恢复)时,可以使用它们。只是在Java平台中过度使用了检查异常,这使人们讨厌它们。

这是我对该主题的扩展看法

至于特定的问题:

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

  2. RuntimeException未经检查的异常吗?
    对,就是这样。

  3. 我该怎么办?
    这取决于该代码在哪里以及您想要发生什么。如果它在UI层中-捕获并显示警告;如果它在服务层中-根本不要抓住它-让它冒泡。只是不要吞下异常。如果在大多数情况下发生异常,则应选择以下一种:

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

  5. 人们为什么Exception在throws子句中添加类?
    大多数情况下,是因为人们懒于考虑要捕获什么和重新抛出什么。投掷Exception是一种不良做法,应避免。

las,没有一个单一的规则可以让您确定何时捕获,何时重新抛出,何时使用已检查的异常以及何时使用未检查的异常。我同意这会引起很多混乱和很多错误代码。Bloch陈述了一般原则(您引用了其中一部分)。通常的原则是将异常抛出到可以处理它的层。


36
关于抛出异常,并不总是因为人们很懒惰,而是常见的是,当您实现框架时,让框架的用户能够抛出任何异常。您可以例如在JSE
Kaj

10
@Kaj-是的,像Callable,interceptors之类的一般事物是特殊情况。但是在大多数情况下,这是因为人们很懒惰:)
博佐

7
回复:3.1“记录并返回”明智地这样做。这非常接近饮食或躲藏和例外。我这样做的目的并不代表有问题,那并不是真正的例外。日志容易被淹没和忽略。
克里斯(Chris)

4
“当您要迫使您的API用户考虑如何处理特殊情况时” –您不能强迫任何人去考虑是否愿意。如果他们不想思考,他们将编写一个不良的异常块,该异常块根本什么也不做,或者更糟的是,删除或干扰关键错误信息。这就是为什么检查的异常是失败的原因。
adrianos 2012年

3
@adrianos“ ...您不能强迫任何人考虑是否不想....”通过这种思路,我们还可以消除编译错误....我并不是真的以您为目标,我听说过一次又一次地找到参数,仍然发现它是将Checked Exceptions标记为失败的最差的解释。附带说明一下,我之前见过这样的语言,通过设计,实际上无法进行编译(实际上也包括运行时错误)。那条路通往一些非常黑暗的地方。
Newtopian

233

某项是否是“受检查的异常”与您是否捕获它或在catch块中执行的操作无关。这是异常类的属性。凡是是的一个子类Exception ,除了RuntimeException和它的子类是经过检查的异常。

Java编译器迫使您要么捕获检查的异常,要么在方法签名中声明它们。本来可以提高程序安全性,但是大多数人似乎认为这样做不值得产生设计问题。

为什么他们让异常冒出来?处理错误越早越好吗?为什么冒泡?

因为这是整个异常。没有这种可能性,您将不需要例外。它们使您能够在选择的级别上处理错误,而不是强迫您使用错误最初发生的低级方法进行处理。


3
谢谢!有时我会因为抛出胡扯的原则而抛出异常。我团队中的一名开发人员想要输入一个无效的xpath表达式,由他们自己来处理异常。在极少数情况下,他们会捕获异常,并且什么也不做,他们不会在代码审查中听到有关此异常的消息。
jeremyjjbrown

12
“除RuntimeException及其子类之外,任何Throwable子类的子对象都是已检查的异常。” -您的陈述不正确。错误还会继承Throwable,并且未经检查。
巴特兹拉

8
@JonasEicher:基本上,异常的主要优点是它们使您可以选择要在调用堆栈中处理错误的位置,该位置通常非常高,同时使各层之间完全没有错误处理的构件。受检查的异常恰好破坏了这一优势。另一个问题是,已检查/未检查的区别与异常类相关联,该异常类还表示异常的概念分类-混合了两个根本不必相关的方面。
Michael Borgwardt

2
“但是大多数人的意见似乎是,它造成的设计问题不值得。” -请引用?
凯文2015年

3
@Bartzilla是的。为完整起见,正如javadoc Throwable所说:“ Throwable和Throwable的任何子类都不是RuntimeException或Error的子类,都被视为检查异常”
Bart van Heukelom 2015年

74
  1. 以上是否被视为检查异常?如果您正在处理异常,则不能将其Checked Exception设为a RuntimeException

  2. RuntimeExceptionunchecked exception?是

Checked Exceptionssubclassesjava.lang.Exception Unchecked Exceptionssubclassesjava.lang.RuntimeException

引发检查异常的调用需要包含在try {}块中,或在该方法的调用者中的更高级别中进行处理。在那种情况下,当前方法必须声明它抛出了所述异常,以便调用者可以做出适当的安排来处理该异常。

希望这可以帮助。

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

答:是的,这是一个非常好的问题,也是重要的设计考虑因素。Exception类是一个非常通用的异常类,可用于包装内部低级异常。您最好创建一个自定义异常并将其包装在其中。但是,还有一个很大的问题-永远不要掩盖潜在的根本原因。例如,Don't 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

RuntimeException一般而言,不应尝试使用。它们通常表示发生编程错误,应单独使用。相反,程序员应在调用某些可能会导致的代码之前检查错误情况RuntimeException。例如:

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

这是不好的编程习惯。相反,应该执行null检查,例如-

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()方法内复制所有字符串到整数的转换代码-如果由开发人员实现,则容易出错。因此,最好不要尝试捕获。

因此NullPointerExceptionNumberFormatException两者都是RuntimeExceptions,在捕获异常NullPointerException时应将其替换为优美的null检查,而我建议您NumberFormatException明确捕获该异常,以避免可能引入的容易出错的代码。


谢谢。当鼓吹气泡时exception,还有一个问题,我应该冒出确切的异常还是用掩盖它Exception。我在一些遗留代码之上编写代码,然后Exception到处冒泡。我想知道这是否是正确的行为?
唐潘

1
这是一个非常重要的问题,编辑了我的答案以包括说明。
d现场直播

非常感谢你。您可以告诉我内容LoginFailureException(sqle)吗?
唐法(Thang Pham)

1
我没有这些东西的任何代码,我只是整理了名称等。如果您看到java.lang.Exception,它有4个构造函数,其中两个接受java.lang.Throwable。在上面的代码片段中,我假设LoginFailureException扩展Exception并声明了一个构造函数public LoginFailureException(Throwable cause) { super(cause) }
d-live

关于该主题的最佳答案。我认为不应捕获运行时异常,因为这些异常是由于缺乏良好的编程而发生的。我完全同意“吃掉原始根本原因,埋葬了无法恢复的实际原因是生产支持团队的噩梦,在生产支持团队中,他们只能访问应用程序日志和错误消息。”
huseyin '16

19

1。如果不确定异常,请检查API:

 java.lang.Object
 extended by java.lang.Throwable
  extended by java.lang.Exception
   extended by java.lang.RuntimeException  //<-NumberFormatException is a RuntimeException  
    extended by java.lang.IllegalArgumentException
     extended by java.lang.NumberFormatException

2。是的,以及扩展它的每个异常。

3。无需捕获并抛出相同的异常。在这种情况下,您可以显示一个新的文件对话框。

4。FileNotFoundException已经经过检查的异常。

5。如果期望该方法调用someMethod能够捕获异常,则可以抛出该异常。它只是“传球”。例如,如果您想将其放在自己的私有方法中,而在公共方法中处理该异常,则它的用法例如。

Oracle文档本身就是一本好书: http //download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

设计人员为什么决定强制使用一种方法来指定可在其范围内抛出的所有未捕获的检查异常?一个方法可以抛出的任何异常都是该方法的公共编程接口的一部分。那些调用方法的人必须知道方法可能引发的异常,以便他们可以决定如何处理这些异常。这些异常与该方法的参数和返回值一样,也是该方法的编程接口的一部分。

下一个问题可能是:“如果很好地记录一个方法的API,包括它可以抛出的异常,为什么不还要指定运行时异常呢?” 运行时异常表示由编程问题引起的问题,因此,无法合理地期望API客户端代码从它们中恢复或以任何方式进行处理。这些问题包括算术异常,例如除以零;指针异常,例如尝试通过空引用访问对象;以及索引异常,例如尝试通过太大或太小的索引访问数组元素。

Java语言规范中还有一些重要的信息:

throws子句中命名的已检查异常类是方法或构造函数的实现者与用户之间的合同的一部分

恕我直言,最重要的是,您可以捕获任何RuntimeException,但不是必须的,并且实际上,不需要维护实现所引发的相同的未经检查的异常,因为它们不是合同的一部分。


谢谢。当鼓吹气泡时exception,还有一个问题,我应该冒出确切的异常还是用掩盖它Exception。我在一些遗留代码之上编写代码,然后Exception到处冒泡。我想知道这是否是正确的行为?
唐潘

1
@Harry我将让人们有更多的知识比我回答说:stackoverflow.com/questions/409563/...
Aleadam

10

1)不,NumberFormatException是未经检查的异常。即使您抓住了它(也不需要),因为它未被选中。这是因为它是的子类,IllegalArgumentException而是的子类RuntimeException

2)RuntimeException是所有未经检查的异常的根源。的每个子类RuntimeException均未选中。所有其他异常和Throwable被检查,但错误除外(该错误位于Throwable)。

3/4)您可以提醒用户他们选择了不存在的文件,并要求新的文件。或者只是退出以通知用户他们输入的内容无效。

5)投掷和接住 'Exception'是不好的做法。但更一般而言,您可能会引发其他异常,以便调用方可以决定如何处理它。例如,如果您编写了一个库来处理读取某些文件输入,而您的方法被传递了不存在的文件,则您不知道如何处理该文件。呼叫者想再次询问还是退出?因此,您可以将Exception链抛回到调用方。

在很多情况下,unchecked Exception发生这种情况是因为程序员没有验证输入(在NumberFormatException第一个问题中为)。这就是为什么选择它们来捕获它们的原因,因为有更优雅的方法来避免生成这些异常。


谢谢。当鼓吹气泡时exception,还有一个问题,我应该冒出确切的异常还是用掩盖它Exception。我在一些遗留代码之上编写代码,然后Exception到处冒泡。我想知道这是否是正确的行为?
唐潘

您既可以让您的方法也抛出Exception(这是不理想的)。或者捕获Exception并抛出更好的Exception(例如IOException之类的东西)。所有异常都可以在其构造函数中将异常作为“原因”,因此您应该使用它。
dontocsata

8

已检查-容易发生。在编译时签入。

例如:FileOperations

未检查-由于数据错误。签入运行时。

例如..

String s = "abc";
Object o = s;
Integer i = (Integer) o;

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Sample.main(Sample.java:9)

这里的异常是由于错误的数据引起的,决不能在编译期间确定。


6

被检查的异常由JVM及其与资源(文件/ db /流/套接字等)相关的编译时进行检查。检查异常的动机是,在编译时,如果资源不可用,应用程序应在catch / finally块中定义替代行为来处理此问题。

未经检查的异常纯粹是程序错误,错误的计算,空数据甚至业务逻辑故障都可能导致运行时异常。处理/捕获代码中未经检查的异常绝对好。

解释来自http://coder2design.com/java-interview-questions/


5

绝对喜欢Java教程跟踪文章“ Unchecked Exceptions-The Conversversy ” 提供了关于未检查的异常和已检查的异常之间差异的描述(很抱歉,这篇文章中的所有基本知识都很少,但是,有时候基础知识是最好的):

这是底线准则:如果可以合理地预期客户端将从异常中恢复,则将其设置为已检查的异常。如果客户端无法采取任何措施来从异常中恢复,请将其设置为未经检查的异常

“抛出什么类型的异常”的核心是语义(在某种程度上),上面的引用提供了出色的指导原则(因此,我仍然对C#摆脱检查异常的观念感到震惊-特别是Liskov主张有用)。

其余的则变得合乎逻辑:编译器希望我明确地响应哪些异常?您希望客户端从中恢复的服务器。


5

要回答最后一个问题(上面的其他问题似乎已经完全回答了),“我应该冒充确切的异常还是使用Exception屏蔽它?”

我假设您的意思是这样的:

public void myMethod() throws Exception {
    // ... something that throws FileNotFoundException ...
}

不,总是声明尽可能精确的异常或此类异常的列表。您声明您的方法可以抛出的异常是您的方法与调用者之间的合同的一部分。抛出"FileNotFoundException"表示文件名无效,并且找不到文件;呼叫者将需要智能地处理它。投掷的Exception意思是“嘿,发生了。交易。” 这是一个很穷的人API

在第一篇文章的评论中,有一些示例,其中“ throws Exception”是有效且合理的声明,但是对于大多数normal您将要编写的代码而言,情况并非如此。


确实,将检查异常声明作为代码文档的一部分,并为使用软件的人员提供帮助。
萨尔瓦多·瓦伦西亚

5

运行时异常:运行时异常称为未经检查的异常。所有其他异常都是已检查的异常,它们不是从java.lang.RuntimeException派生的。

检查异常:必须在代码中的某个地方捕获受检查的异常。如果您调用的方法引发了已检查的异常,但是没有在某个地方捕获到该检查的异常,则您的代码将无法编译。这就是为什么将它们称为检查异常:编译器进行检查以确保已对它们进行处理或声明的原因。

Java API中的许多方法都会抛出已检查的异常,因此您经常会编写异常处理程序来应对未编写的方法所生成的异常。


3

为什么他们让异常冒出来?处理错误不是更好吗?为什么冒泡?

例如,假设您有一些客户端-服务器应用程序,并且客户端请求了一些无法找到的资源,或者由于某些其他错误,在处理用户请求时服务器端可能发生了某些错误,那么这就是责任服务器告诉客户端为什么他不能得到他所请求的东西,因此要在服务器端实现这一点,编写代码以使用throw关键字而不是吞咽或处理该异常来抛出异常。如果服务器处理/吞咽它,那么就没有机会向客户暗示发生了什么错误。

注意:为了清楚地说明发生了什么错误类型,我们可以创建自己的Exception对象并将其扔给客户端。


好点子。这意味着将其扩展到最负责的层,该层控制逻辑流并监督应用程序的业务逻辑。例如,数据库层将无法与客户端进行通信,以告知关键事项丢失或无响应。当它到达最顶层的服务器层时,它会立即通过严重错误消息刷新客户端的视图。
萨尔瓦多·瓦伦西亚


3

我只想添加一些根本不使用检查异常的理由。这不是一个完整的答案,但我认为它确实回答了您的部分问题,并补充了许多其他答案。

每当涉及检查的异常时,throws CheckedException方法签名中都会有一个地方(CheckedException可以是任何检查的异常)。签名不会引发异常,引发异常是实现的一个方面。接口,方法签名,父类,所有这些都不应该取决于其实现。这里使用检查异常(实际上是必须throws在方法签名中声明的事实)将您的高层接口与这些接口的实现绑定在一起。

让我给你看一个例子。

让我们有一个如此漂亮干净的界面

public interface IFoo {
    public void foo();
}

现在我们可以编写方法的许多实现foo(),例如

public class Foo implements IFoo {
    @Override
    public void foo() {
        System.out.println("I don't throw and exception");
    }
}

Foo类非常好。现在让我们第一次尝试Bar类

public class Bar implements IFoo {
    @Override
    public void foo() {
        //I'm using InterruptedExcepton because you probably heard about it somewhere. It's a checked exception. Any checked exception will work the same.
        throw new InterruptedException();
    }
}

此类Bar将不会编译。由于InterruptedException是一个已检查的异常,因此您必须捕获它(在foo()方法内部使用try-catch捕获)或声明您正在抛出它(添加throws InterruptedException到方法签名中)。由于我不想在这里捕获此异常(我希望它向上传播,以便我可以在其他地方适当地处理它),因此让我们更改签名。

public class Bar implements IFoo {
    @Override
    public void foo() throws InterruptedException {
        throw new InterruptedException();
    }
}

此类Bar也不会编译!Bar的方法foo()不会覆盖IFoo的方法foo(),因为它们的签名不同。我可以删除@Override批注,但是我想针对IFoo接口进行编程,IFoo foo;然后再决定要使用哪种实现foo = new Bar();。如果Bar的foo()方法没有覆盖IFoo的foo方法,那么当我这样做时foo.foo();,它将不会调用Bar的foo()的实现。

为了使Bar public void foo() throws InterruptedException覆盖IFoo,public void foo()我必须添加throws InterruptedExceptionIFoo的方法签名。但是,这将导致我的Foo类出现问题,因为它的foo()方法签名不同于IFoo的方法签名。此外,如果我将throws InterruptedExceptionFoo的方法foo()添加到Foo的方法中,则会收到另一个错误,指出Foo的方法foo()声明它抛出了InterruptedException,但从未抛出InterruptedException。

如您所见(如果我在解释这些内容时做得不错),我抛出了InterruptedException之类的受检查异常的事实迫使我将IFoo接口与其实现之一绑定在一起,这反过来又导致IFoo的破坏其他实现!

这是为什么检查异常是BAD的一大原因。大写。

一种解决方案是捕获已检查的异常,将其包装在未检查的异常中,然后抛出未检查的异常。


2
是的,这很糟糕,因为您说过您不想抓住它。但是,为了避免影响IFOO的签名,您将必须这样做。我宁愿这样做,而不是重新平衡我所有的接口签名,以避免捕获异常(仅因为异常是BAD)。
萨尔瓦多·巴伦西亚

是的,我同意。我有点不清楚。我希望传播一个异常,以便可以在其他地方处理它。一种解决方案是捕获InterruptedException并引发未经检查的异常。即,我们避免检查异常并绕过未检查异常(即使它们仅作为包装器有意义)
Blueriver

“但是,这将导致我的Foo类出现问题,因为它的foo()方法的签名不同于IFoo的方法签名”。我刚刚测试了您的想法,即使我们添加throws InterruptedException了IFoo的方法签名,也可以在不执行任何实现的情况下进行编译。因此,它实际上不会引起任何问题。如果在接口中使每个方法签名均抛出Exception,则它仅使实现可以选择抛出或不抛出异常(任何异常,因为Exception封装了所有异常)。
Flyout91

但是我承认这可能会造成混淆,因为当您实现这样的接口并单击“添加未实现的方法”之类的内容时throw Exception,即使您的实现不会抛出任何内容,也可能是一个更具体的例外。但是我仍然觉得总是对接口的方法抛出Exception是一个好习惯,因为它再次使用户可以选择是否抛出任何异常。
Flyout91

这错过了整个重点。接口的目的是声明客户需要满足的合同。这可能包括它能够处理的故障情况。当实现遇到错误时,应将该错误映射到客户端接口声明的相应抽象故障。
erickson

3
  • Java区分两种类别的异常(已检查和未检查)。
  • Java对检查的异常强制执行catch或声明的要求。
  • 异常的类型确定是否选中了异常。
  • 类的直接或间接subclasses的所有异常类型RuntimeException 都是未经检查的异常。
  • 所有继承自class的类Exception均不RuntimeException视为checked exceptions
  • 继承自Error类的类被视为未选中。
  • 编译器检查每个方法调用和减速度以确定该方法是否抛出checked exception
    • 如果是这样,编译器将确保捕获异常或在throws子句中声明该异常。
  • 为了满足catch-or-declare要求的声明部分,生成异常的方法必须提供throws包含的子句checked-exception
  • Exception 当类被认为足够重要以进行捕获或声明时,将定义这些类以进行检查。

2

这是一条可以帮助您做出决定的简单规则。它与Java中如何使用接口有关。

以您的类为例,并设想为其设计一个接口,以使该接口描述该类的功能,但不描述任何基础实现(如接口应这样)。假设您可能以另一种方式实现该类。

查看接口的方法,并考虑它们可能引发的异常:

如果方法可以引发异常,而无论其基础实现如何(换句话说,它仅描述功能),则它可能应该是接口中的已检查异常。

如果异常是由基础实现引起的,则该异常不应在接口中。因此,它必须是您的类中的一个未检查的异常(因为未检查的异常不需要出现在接口签名中),或者您必须包装它并将其作为接口方法一部分的被检查的异常重新抛出。

要决定是否应该包装并重新抛出,您应该再次考虑对于接口用户必须立即处理异常情况是否有意义,或者该异常是如此普遍以至于您无能为力,因此应该向上传播。当表示为您正在定义的新接口的功能时,包装的异常是否有意义?或者它只是一堆可能的错误情况的载体,而其他方法也可能会发生这种情况?如果是前者,它可能仍然是检查异常,否则应取消选中。

通常,您不应该计划“增强”异常(捕获和重新抛出)。要么由调用方处理异常(在这种情况下将其选中),要么将其一直处理到高级处理程序(在这种情况下,如果不对其进行检查则最容易)。


2

只是要指出,如果在代码中引发了检查的异常,并且catch在上面几层,则需要在您和catch之间的每个方法的签名中声明异常。因此,封装被破坏了,因为throw路径中的所有函数都必须知道该异常的详细信息。


2

简而言之,您上面的一个或多个模块应该在运行时处理的异常称为检查异常;其他则是RuntimeException或的未经检查的异常Error

在此视频中,它说明了Java中已检查和未检查的异常:https :
//www.youtube.com/watch?v=ue2pOqLaArw


1

所有这些都是检查异常。未检查的异常是RuntimeException的子类。决定不是如何处理它们,应该由您的代码将它们抛出。如果您不希望编译器告诉您尚未处理异常,则可以使用未经检查的(RuntimeException的子类)异常。这些内容应保存在无法恢复的情况下,例如内存不足错误等。


嗯 如您所说,如果NumberFormatException是一个检查的异常,这是否与从RuntimeException继承的事实相矛盾?
eis 2012年

抱歉,我不太清楚。我指的是FileNotFoundException而不是NumberFormatException。根据他的#2和#4,似乎他认为Checked vs. Unchecked是基于您在捕获异常之后如何处理它的。不是它的定义方式。
2012年

-1

如果有人在乎另一种证明不喜欢检查异常的证据,请参见流行的JSON库的前几段:

“尽管这是一个已检查的异常,但是它几乎是不可恢复的。大多数调用者应该简单地将此异常包装到一个未检查的异常中并重新抛出:”

那么,如果我们应该“简单地包装它”,那么为什么世界上会有人让开发人员继续检查该异常呢?大声笑

http://developer.android.com/reference/org/json/JSONException.html


4
因为只有大多数呼叫者(而不是所有呼叫者)才应该包装并重新抛出。检查异常的事实意味着调用者必须考虑他们是“最多”的调用者之一,还是可以并且应该处理该异常的少数群体之一。
沃伦·露

1
如果您想检查每次调用的错误,请“返回”C。异常是一种将正常程序执行与异常分开的方式,而不会污染您的代码。异常确保您不能在某种程度上默默地忽略错误。
斯洛沃米尔

-1

已检查的异常

  • 由编译器检查以便在运行时顺利执行程序的异常称为“检查异常”。

  • 这些发生在编译时。

  • 如果这些处理不当,它们将给出编译时错误(Not Exception)。
  • 除RuntimeException外,Exception类的所有子类均为Checked Exception。

    假设示例 -假设您要离开家进行考试,但是如果您检查自己是否在家里(编译时)拿了Hall Ticket,那么在Exam Hall(运行时)就不会有任何问题。

未检查的异常

  • 编译器未检查的异常称为未检查的异常。

  • 这些发生在运行时。

  • 如果这些异常处理不当,则不会产生编译时错误。但是该程序将在运行时过早终止。

  • RunTimeException和Error的所有子类都是未经检查的异常。

    假设示例 -假设您在考场中,但您的学校因某种原因发生了火灾(在运行时发生),当时您什么也不能做,但可以在编译前进行预防。


-2

所有异常都必须是检查异常。

  1. 未检查的异常是不受限制的异常。无限制的goto被认为是一件坏事。

  2. 未检查的异常会破坏封装。为了正确处理它们,必须知道抛出器和捕获器之间的调用树中的所有函数,以避免错误。

  3. 异常是引发异常的函数中的错误,而不是处理异常的函数中的错误。异常的目的是通过将是否是错误的决定推迟到另一个上下文中,从而使程序有第二次机会。只有在其他情况下,才能做出正确的决定。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.