了解 Java 中的检查异常与非检查异常

发布于 2024-11-09 19:05:50 字数 1784 浏览 0 评论 0原文

Joshua Bloch 在《Effective 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 中,什么时候应该创建检查异常,什么时候应该是运行时异常?

何时选择检查和非检查异常

Joshua Bloch in "Effective Java" said that

Use checked exceptions for
recoverable conditions and runtime
exceptions for programming errors
(Item 58 in 2nd edition)

Let's see if I understand this correctly.

Here is my understanding of a checked exception:

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. Is the above considered a checked exception?

2. Is RuntimeException an unchecked exception?

Here is my understanding of an unchecked exception:

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. Now, couldn't the above code also be a checked exception? I can try to recover the situation like this? Can I? (Note: my 3rd question is inside the catch above)

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. Why do people do this?

public void someMethod throws Exception{

}

Why do they let the exception bubble up? Isn't handling the error sooner better? Why bubble up?

6. Should I bubble up the exact exception or mask it using Exception?

Below are my readings

In Java, when should I create a checked exception, and when should it be a runtime exception?

When to choose checked and unchecked exceptions

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(21

夕嗳→ 2024-11-16 19:05:51
  1. 以上是否被认为是受检查的异常?

    如果您正在处理异常,但如果它是 RuntimeException,则不会使其成为 Checked Exception

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

受检异常java.lang.Exception子类
Unchecked Exceptionsjava.lang.RuntimeException子类

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

希望这有帮助。

问:我应该冒出确切的信息吗?
异常或使用异常屏蔽它?

答:是的,这是一个非常好的问题,也是重要的设计考虑因素。 Exception 类是一个非常通用的异常类,可用于包装内部低级异常。您最好创建一个自定义异常并将其包装在其中。但是,还有一个大问题——永远不要掩盖根本原因。例如,永远不要执行以下操作 -

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!.
}

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

关于尝试捕获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.");
}

这是一种不好的编程习惯。相反,应该进行空检查,例如 -

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() 方法内的整数转换代码 - 如果由开发人员实现,则容易出错。所以最好还是取消 try-catch。

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

  1. Is the above considered to be a checked exception?
    No
    The fact that you are handling an exception does not make it a Checked Exception if it is a RuntimeException.

  2. Is RuntimeException an unchecked exception?
    Yes

Checked Exceptions are subclasses of java.lang.Exception
Unchecked Exceptions are subclasses of java.lang.RuntimeException

Calls throwing checked exceptions need to be enclosed in a try{} block or handled in a level above in the caller of the method. In that case the current method must declare that it throws said exceptions so that the callers can make appropriate arrangements to handle the exception.

Hope this helps.

Q: should I bubble up the exact
exception or mask it using Exception?

A: Yes this is a very good question and important design consideration. The class Exception is a very general exception class and can be used to wrap internal low level exceptions. You would better create a custom exception and wrap inside it. But, and a big one - Never ever obscure in underlying original root cause. For ex, Don't ever do following -

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

Instead do following:

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

Eating away original root cause buries the actual cause beyond recovery is a nightmare for production support teams where all they are given access to is application logs and error messages.
Although the latter is a better design but many people don't use it often because developers just fail to pass on the underlying message to caller. So make a firm note: Always pass on the actual exception back whether or not wrapped in any application specific exception.

On try-catching RuntimeExceptions

RuntimeExceptions as a general rule should not be try-catched. They generally signal a programming error and should be left alone. Instead the programmer should check the error condition before invoking some code which might result in a RuntimeException. For ex:

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

This is a bad programming practice. Instead a null-check should have been done like -

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

But there are times when such error checking is expensive such as number formatting, consider this -

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.");
}

Here pre-invocation error checking is not worth the effort because it essentially means to duplicate all the string-to-integer conversion code inside parseInt() method - and is error prone if implemented by a developer. So it is better to just do away with try-catch.

So NullPointerException and NumberFormatException are both RuntimeExceptions, catching a NullPointerException should replaced with a graceful null-check while I recommend catching a NumberFormatException explicitly to avoid possible introduction of error prone code.

为你鎻心 2024-11-16 19:05:51

1.如果您不确定是否存在异常,请检查 API:

 java.lang.Object
 由 java.lang.Throwable 扩展
  由 java.lang.Exception 扩展
   由 java.lang.RuntimeException 扩展 //<-NumberFormatException 是一个 RuntimeException  
    由 java.lang.IllegalArgumentException 扩展
     由 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,但您不需要这样做,事实上,实现不需要维护抛出的相同的非检查异常,因为这些不是合同的一部分。

1 . If you are unsure about an exception, check the 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 . Yes, and every exception that extends it.

3 . There is no need to catch and throw the same exception. You can show a new File Dialog in this case.

4 . FileNotFoundException is already a checked exception.

5 . If it is expected that the method calling someMethod to catch the exception, the latter can be thrown. It just "passes the ball". An example of it usage would be if you want to throw it in your own private methods, and handle the exception in your public method instead.

A good reading is the Oracle doc itself: http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

Why did the designers decide to force a method to specify all uncaught checked exceptions that can be thrown within its scope? Any Exception that can be thrown by a method is part of the method's public programming interface. Those who call a method must know about the exceptions that a method can throw so that they can decide what to do about them. These exceptions are as much a part of that method's programming interface as its parameters and return value.

The next question might be: "If it's so good to document a method's API, including the exceptions it can throw, why not specify runtime exceptions too?" Runtime exceptions represent problems that are the result of a programming problem, and as such, the API client code cannot reasonably be expected to recover from them or to handle them in any way. Such problems include arithmetic exceptions, such as dividing by zero; pointer exceptions, such as trying to access an object through a null reference; and indexing exceptions, such as attempting to access an array element through an index that is too large or too small.

There's also an important bit of information in the Java Language Specification:

The checked exception classes named in the throws clause are part of the contract between the implementor and user of the method or constructor.

The bottom line IMHO is that you can catch any RuntimeException, but you are not required to and, in fact the implementation is not required to maintain the same non-checked exceptions thrown, as those are not part of the contract.

永言不败 2024-11-16 19:05:51

1) 不,NumberFormatException 是未经检查的异常。即使你发现了它(你不需要这样做),因为它是未经检查的。这是因为它是 IllegalArgumentException 的子类,而 IllegalArgumentExceptionRuntimeException 的子类。

2) RuntimeException 是所有未检查异常的根源。 RuntimeException 的每个子类都未经检查。除错误(位于 Throwable 下)之外,所有其他异常和 Throwable 都会被检查。

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

5) 抛出和捕获'Exception'是不好的做法。但更一般地说,您可能会抛出其他异常,以便调用者可以决定如何处理它。例如,如果您编写了一个库来处理读取某些文件输入,并且您的方法传递了一个不存在的文件,那么您不知道如何处理它。打电话的人是想再问还是退出?因此,您将异常沿着链抛出回调用者。

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

1) No, a NumberFormatException is an unchecked Exception. Even though you caught it (you aren't required to) because it's unchecked. This is because it is a subclass of IllegalArgumentException which is a subclass of RuntimeException.

2) RuntimeException is the root of all unchecked Exceptions. Every subclass of RuntimeException is unchecked. All other Exceptions and Throwable are checked except for Errors ( Which comes under Throwable).

3/4) You could alert the user that they picked a non-existent file and ask for a new one. Or just quit informing the user that they entered something invalid.

5) Throwing and catching 'Exception' is bad practice. But more generally, you might throw other exceptions so the caller can decide how to deal with it. For example, if you wrote a library to handle reading some file input and your method was passed a non-existent file, you have no idea how to handle that. Does the caller want to ask again or quit? So you throw the Exception up the chain back to the caller.

In many cases, an unchecked Exception occurs because the programmer did not verify inputs (in the case of NumberFormatException in your first question). That's why its optional to catch them, because there are more elegant ways to avoid generating those exceptions.

゛时过境迁 2024-11-16 19:05:51

检查 - 容易发生。检查编译时。

例如.. 文件操作

未选中 - 由于数据错误。签入运行时。

例如..

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)

这里的异常是由于错误数据造成的,并且在编译时无法确定它。

Checked - Prone to happen. Checked in Compile time.

Eg.. FileOperations

UnChecked - Due to Bad data. Checked in Run time.

Eg..

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)

Here exception is due to bad data and in no way it can be determined during compile time.

惯饮孤独 2024-11-16 19:05:51

运行时异常
运行时异常称为未经检查的异常。所有其他例外情况
是受检查的异常,并且它们不是从 java.lang.RuntimeException 派生的。

检查异常
必须在代码中的某个位置捕获已检查的异常。如果你调用一个
抛出已检查异常但您没有捕获已检查异常的方法
在某个地方,你的代码将无法编译。这就是为什么他们被称为checked
异常:编译器检查以确保它们被处理或声明。

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

Runtime Exceptions :
Runtime exceptions are referring to as unchecked exceptions. All other exceptions
are checked exceptions, and they don't derive from java.lang.RuntimeException.

Checked Exceptions :
A checked exception must be caught somewhere in your code. If you invoke a
method that throws a checked exception but you don't catch the checked exception
somewhere, your code will not compile. That's why they're called checked
exceptions : the compiler checks to make sure that they're handled or declared.

A number of the methods in the Java API throw checked exceptions, so you will often write exception handlers to cope with exceptions generated by methods you didn't write.

悍妇囚夫 2024-11-16 19:05:51

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

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

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

Checked exceptions are checked at compile time by the JVM and its related to resources(files/db/stream/socket etc). The motive of checked exception is that at compile time if the resources are not available the application should define an alternative behaviour to handle this in the catch/finally block.

Unchecked exceptions are purely programmatic errors, wrong calculation, null data or even failures in business logic can lead to runtime exceptions. Its absolutely fine to handle/catch unchecked exceptions in code.

Explanation taken from http://coder2design.com/java-interview-questions/

清风不识月 2024-11-16 19:05:51

最喜欢关于未检查异常和检查异常之间差异的描述是由 Java 教程跟踪文章“未检查的异常 - 争议”(很抱歉在这篇文章中了解了所有基础知识 - 但是,嘿,基础知识有时是最好的):

这是底线指南:如果客户可以合理地
预期从异常中恢复,使其成为受检查的异常。如果
客户端无法执行任何操作来从异常中恢复,使其成为
未经检查的异常

”的核心是语义(在某种程度上),上面的引用提供了很好的指导(因此,我仍然对 C# 摆脱了检查异常的想法感到震惊 - 特别是 Liskov争论它们的有用性)。

然后剩下的就变得合乎逻辑了:编译器希望我显式地响应哪些异常?您期望客户从中恢复的那些。

My absolute favorite description of the difference between unchecked and checked exceptions is provided by the Java Tutorial trail article, "Unchecked Exceptions - the Controversy" (sorry to get all elementary on this post - but, hey, the basics are sometimes the best):

Here's the bottom line guideline: If a client can reasonably be
expected to recover from an exception, make it a checked exception. If
a client cannot do anything to recover from the exception, make it an
unchecked exception

The heart of "what type of exception to throw" is semantic (to some degree) and the above quote provides and excellent guideline (hence, I am still blown away by the notion that C# got rid of checked exceptions - particularly as Liskov argues for their usefulness).

The rest then becomes logical: to which exceptions does the compiler expect me to respond, explicitly? The ones from which you expect client to recover.

各空 2024-11-16 19:05:51

为了回答最后一个问题(其他问题似乎在上面得到了彻底的回答),“我应该冒出确切的异常还是使用异常屏蔽它?”

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

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

不,总是声明可能的最精确异常,或者这样的列表。您将方法声明为能够抛出的异常是您的方法与调用者之间契约的一部分。抛出"FileNotFoundException"意味着文件名可能无效并且找不到文件;调用者需要明智地处理这个问题。抛出 Exception 意味着“嘿,糟糕的事情发生了。成交。”这是一个非常糟糕的API

在第一篇文章的评论中,有一些示例,其中“抛出 Exception” 是有效且合理的声明,但对于您将要使用的大多数“正常”代码而言,情况并非如此。曾经写过。

To answer the final question (the others seem thoroughly answered above), "Should I bubble up the exact exception or mask it using Exception?"

I am assuming you mean something like this:

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

No, always declare the most precise exception possible, or a list of such. The exceptions you declare your method as capable of throwing are a part of the contract between your method and the caller. Throwing "FileNotFoundException" means that it is possible the file name isn't valid and the file will not be found; the caller will need to handle that intelligently. Throwing Exception means "Hey, sh*t happens. Deal." Which is a very poor API.

In the comments on the first article there are some examples where "throws Exception" is a valid and reasonable declaration, but that's not the case for most "normal" code you will ever write.

眼泪也成诗 2024-11-16 19:05:51

我认为检查异常对于使用外部库的开发人员来说是一个很好的提醒,在特殊情况下该库中的代码可能会出现问题。

I think that checked exceptions are a good reminder for the developer that uses an external library that things can go wrong with the code from that library in exceptional situations.

相思故 2024-11-16 19:05:51

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

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

注意:为了清楚地描述发生的错误类型,我们可以创建自己的 Exception 对象并将其抛出给客户端。

Why do they let the exception bubble up? Isn't handling the error sooner better? Why bubble up?

For example let say you have some client-server application and client had made a request for some resource that couldn't be find out or for something else error some might have occurred at the server side while processing the user request then it is the duty of the server to tell the client why he couldn't get the thing he requested for,so to achieve that at server side, code is written to throw the exception using throw keyword instead of swallowing or handling it.if server handles it/swallow it, then there will be no chance of intimating to the client that what error had occurred.

Note:To give a clear description of what the error type has occurred we can create our own Exception object and throw it to the client.

ζ澈沫 2024-11-16 19:05:51

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

每当涉及受检查的异常时,方法签名中的某处都会有一个 throws CheckedExceptionCheckedException 可以是任何受检查的异常)。签名不会抛出异常,抛出异常是实现的一个方面。接口、方法签名、父类,所有这些东西都不应该依赖于它们的实现。这里使用受检查的异常(实际上您必须在方法签名中声明抛出)将您的更高级别接口与这些接口的实现绑定在一起。

让我给你举个例子。

让我们有一个像这样漂亮干净的接口

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 InterruptedException 添加到 IFoo 的方法签名中。然而,这将导致我的 Foo 类出现问题,因为它的 foo() 方法的签名与 IFoo 的方法签名不同。此外,如果我将 throws InterruptedException 添加到 Foo 的方法 foo() 中,我会收到另一个错误,指出 Foo 的方法 foo() 声明它抛出 InterruptedException,但它从不抛出 InterruptedException。

正如您所看到的(如果我在解释这些东西方面做得不错的话),事实上,我抛出像 InterruptedException 这样的检查异常,迫使我将我的接口 IFoo 绑定到它的其中一个实现,这反过来又对 IFoo 造成严重破坏其他实现!

这是检查异常不好的一大原因。大写字母。

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

I just want to add some reasoning for not using checked exceptions at all. This is not a full answer, but I feel it does answer part of your question, and complements many other answers.

Whenever checked exceptions are involved, there's a throws CheckedException somewhere in a method signature (CheckedException could be any checked exception). A signature does NOT throw an Exception, throwing Exceptions is an aspect of implementation. Interfaces, method signatures, parent classes, all these things should NOT depend on their implementations. The usage of checked Exceptions here (actually the fact that you have to declare the throws in the method signature) is binding your higher-level interfaces with your implementations of these interfaces.

Let me show you an example.

Let's have a nice and clean interface like this

public interface IFoo {
    public void foo();
}

Now we can write many implementations of method foo(), like these

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

Class Foo is perfectly fine. Now let's make a first attempt at class 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();
    }
}

This class Bar won't compile. As InterruptedException is a checked exception, you must either capture it (with a try-catch inside method foo()) or declare that you're throwing it (adding throws InterruptedException to the method signature). As I don't want to capture this exception here (I want it to propagate upwards so I can properly deal with it somewhere else), let's alter the signature.

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

This class Bar won't compile either! Bar's method foo() does NOT override IFoo's method foo() since their signatures are different. I could remove the @Override annotation, but I want to program against interface IFoo like IFoo foo; and later on decide on which implementation I want to use, like foo = new Bar();. If Bar's method foo() doesn't override IFoo's method foo, when I do foo.foo(); it won't call Bar's implementation of foo().

To make Bar's public void foo() throws InterruptedException override IFoo's public void foo() I MUST add throws InterruptedException to IFoo's method signature. This, however, will cause problems with my Foo class, since it's foo() method's signature differs from IFoo's method signature. Furthermore, if I added throws InterruptedException to Foo's method foo() I would get another error stating that Foo's method foo() declares that it throws an InterruptedException yet it never throws an InterruptedException.

As you can see (if I did a decent job at explaining this stuff), the fact that I'm throwing a checked exception like InterruptedException is forcing me to tie my interface IFoo to one of it's implementations, which in turn causes havoc on IFoo's other implementations!

This is one big reason why checked exceptions are BAD. In caps.

One solution is to capture the checked exception, wrap it in an unchecked exception and throw the unchecked exception.

み格子的夏天 2024-11-16 19:05:51
  • Java 区分两类异常(已检查和未检查)。
  • Java 对检查异常强制执行 catch 或声明要求。
  • 异常的类型决定异常是被检查还是未被检查。
  • 所有属于 RuntimeException 类的直接或间接子类的异常类型
    是未经检查的异常。
  • 所有继承自 Exception 类但不是 RuntimeException 的类都被视为检查异常
  • 从 Error 类继承的类被认为是未选中的。
  • 编译器检查每个方法的调用和减速,以确定是否
    方法抛出检查异常

    • 如果是这样,编译器将确保异常被捕获或在 throws 子句中声明。
  • 为了满足 catch-or-declare 要求的声明部分,生成的方法
    异常必须提供包含 checked-exceptionthrows 子句。
  • Exception 类被定义为当它们被认为重要到足以捕获或声明时进行检查。
  • Java distinguishes between two categories of exceptions (checked & unchecked).
  • Java enforces a catch or declared requirement for checked exceptions.
  • An exception's type determines whether an exception is checked or unchecked.
  • All exception types that are direct or indirect subclasses of class RuntimeException
    are unchecked exception.
  • All classes that inherit from class Exception but not RuntimeException are considered to be checked exceptions.
  • Classes that inherit from class Error are considered to be unchecked.
  • Compiler checks each method call and deceleration to determine whether the
    method throws checked exception.

    • If so the compiler ensures the exception is caught or is declared in a throws clause.
  • To satisfy the declare part of the catch-or-declare requirement, the method that generates
    the exception must provide a throws clause containing the checked-exception.
  • Exception classes are defined to be checked when they are considered important enough to catch or declare.
雪化雨蝶 2024-11-16 19:05:51

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

以您的类为例,想象为其设计一个接口,以便该接口描述该类的功能,但不描述任何底层实现(接口应该如此)。假设您可能会以另一种方式实现该类。

查看接口的方法并考虑它们可能抛出的异常:

如果方法可以抛出异常,无论底层实现如何(换句话说,它仅描述功能),那么它可能应该是检查异常界面。

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

要决定是否应该换行并重新抛出,您应该再次考虑接口的用户必须立即处理异常情况是否有意义,或者异常如此普遍以至于您无能为力,并且应该这样做向上传播堆栈。当表达为您定义的新接口的功能时,包装的异常是否有意义,或者它只是一包可能发生在其他方法上的可能错误条件的载体?如果是前者,它可能仍然是一个已检查的异常,否则它应该是未检查的。

您通常不应该计划“冒泡”异常(捕获并重新抛出)。异常要么应该由调用者处理(在这种情况下会被检查),要么应该一直上升到高级处理程序(在这种情况下,如果不检查它是最简单的)。

Here is a simple rule that can help you decide. It is related to how interfaces are used in Java.

Take your class and imagine designing an interface for it such that the interface describes the functionality of the class but none of the underlying implementation (as an interface should). Pretend perhaps that you might implement the class in another way.

Look at the methods of the interface and consider the exceptions they might throw:

If an exception can be thrown by a method, regardless of the underlying implementation (in other words, it describes the functionality only) then it should probably be a checked exception in the interface.

If an exception is caused by the underlying implementation, it should not be in the interface. Therefore, it must either be an unchecked exception in your class (since unchecked exceptions need not appear in the interface signature), or you must wrap it and rethrow as a checked exception that is part of the interface method.

To decide if you should wrap and rethrow, you should again consider whether it makes sense for a user of the interface to have to handle the exception condition immediately, or the exception is so general that there is nothing you can do about it and it should propagate up the stack. Does the wrapped exception make sense when expressed as functionality of the new interface you are defining or is it just a carrier for a bag of possible error conditions that could also happen to other methods? If the former, it might still be a checked exception, otherwise it should be unchecked.

You should not usually plan to "bubble-up" exceptions (catch and rethrow). Either an exception should be handled by the caller (in which case it is checked) or it should go all the way up to a high level handler (in which case it is easiest if it is unchecked).

萌化 2024-11-16 19:05:51

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

Just to point out that if you throw a checked exception in a code and the catch is few levels above, you need to declare the exception in the signature of each method between you and the catch. So, encapsulation is broken because all functions in the path of throw must know about details of that exception.

爱她像谁 2024-11-16 19:05:51

简而言之,上面的模块应该在运行时处理的异常称为检查异常;其他是未经检查的异常,即 RuntimeExceptionError

在本视频中,它解释了 Java 中的检查和非检查异常:
https://www.youtube.com/watch?v=ue2pOqLaArw

In short, exceptions which your module or modules above are supposed to handle during runtime are called checked exceptions; others are unchecked exceptions which are either RuntimeException or Error.

In this video, it explains checked and unchecked exceptions in Java:
https://www.youtube.com/watch?v=ue2pOqLaArw

各自安好 2024-11-16 19:05:51

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

All of those are checked exceptions. Unchecked exceptions are subclasses of RuntimeException. The decision is not how to handle them, it's should your code throw them. If you don't want the compiler telling you that you haven't handled an exception then you use an unchecked (subclass of RuntimeException) exception. Those should be saved for situations that you can't recover from, like out of memory errors and the like.

落花浅忆 2024-11-16 19:05:51

如果有人关心另一个不喜欢检查异常的证据,请参阅流行的 JSON 库的前几段:

“虽然这是一个检查异常,但它很少可恢复。大多数调用者应该简单地将此异常包装在未检查异常中并重新抛出:那么

,如果我们应该“简单地包装它”,为什么会有人让开发人员不断检查异常呢?哈哈

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

If anybody cares for yet another proof to dislike checked exceptions, see the first few paragraphs of the popular JSON library:

"Although this is a checked exception, it is rarely recoverable. Most callers should simply wrap this exception in an unchecked exception and rethrow: "

So why in the world would anyone make developers keep checking the exception, if we should "simply wrap it" instead? lol

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

巷雨优美回忆 2024-11-16 19:05:51

受检异常

  • 编译器在运行时为了程序顺利执行而检查的异常称为受检异常。

  • 这些发生在编译时。

  • 如果处理不当,它们将给出编译时错误(不是异常)。
  • Exception 类的所有子类(除了 RuntimeException 之外)都是 Checked Exception。

    假设示例 - 假设您要离开家去参加考试,但如果您检查是否在家中携带了大厅门票(编译时),那么就不会'考试大厅(运行时)不会有任何问题。

Unchecked Exception :

  • 编译器不检查的异常称为 Unchecked Exception。

  • 这些发生在运行时。

  • 如果这些异常处理不当,它们不会给出编译时错误。但程序将在运行时提前终止。

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

    假设示例 - 假设您在考试大厅,但不知何故,您的学校发生了火灾事故(指运行时),当时您无法做任何事情但可以在(编译时)之前做好预防措施。

Checked Exceptions :

  • The exceptions which are checked by the compiler for smooth execution of the program at runtime are called Checked Exception.

  • These occur at compile time.

  • If these are not handled properly, they will give compile time error (Not Exception).
  • All subclasses of Exception class except RuntimeException are Checked Exception.

    Hypothetical Example - Suppose you are leaving your house for the exam, but if you check whether you took your Hall Ticket at home(compile time) then there won't be any problem at Exam Hall(runtime).

Unchecked Exception :

  • The exceptions which are not checked by the compiler are called Unchecked Exceptions.

  • These occur at runtime.

  • If these exceptions are not handled properly, they don’t give compile time error. But the program will be terminated prematurely at runtime.

  • All subclasses of RunTimeException and Error are unchecked exceptions.

    Hypothetical Example - Suppose you are in your exam hall but somehow your school had a fire accident (means at runtime) where you can't do anything at that time but precautions can be made before (compile time).

岁月苍老的讽刺 2024-11-16 19:05:51

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

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

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

  3. 异常是抛出它们的函数中的错误,但不是处理它们的函数中的错误。异常的目的是通过将是否错误的决定推迟到另一个上下文来为程序提供第二次机会。只有在其他上下文中才能做出正确的决定。

All exceptions must be checked exceptions.

  1. Unchecked exceptions are unrestricted gotos. And unrestricted gotos are considered a bad thing.

  2. Unchecked exceptions break encapsulation. To process them correctly, all the functions in the call tree between the thrower and the catcher must be known to avoid bugs.

  3. Exceptions are errors in the function that throws them but not errors in the function that processes them. The purpose of exceptions is to give the program a second chance by deferring the decision of whether it's an error or not to another context. It's only in the other context can the correct decision be made.

有木有妳兜一样 2024-11-16 19:05:50

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

然而,我认为受检查的异常是有用的——当你想要强迫 API 的用户思考如何处理异常情况(如果它是可恢复的)时,就会使用它们。只是受检异常在Java平台中被过度使用,这使得人们讨厌它们。

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

至于特定问题:

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

  2. RuntimeException 是未经检查的异常吗?
    是的,完全正确。

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

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

  2. 为什么人们在 throws 子句中添加类 Exception
    最常见的原因是人们懒于考虑捕捉什么以及重新扔掉什么。抛出异常是一种不好的做法,应该避免。

遗憾的是,没有单一的规则可以让您确定何时捕获、何时重新抛出、何时使用检查异常以及何时使用未检查异常。我同意这会导致很多混乱和很多糟糕的代码。布洛赫(Bloch)阐述了总体原则(您引用了其中的一部分)。一般原则是将异常重新抛出到可以处理的层。

Many people say that checked exceptions (i.e. these that you should explicitly catch or rethrow) should not be used at all. They were eliminated in C# for example, and most languages don't have them. So you can always throw a subclass of RuntimeException (unchecked exception).

However, I think checked exceptions are useful - they are used when you want to force the user of your API to think how to handle the exceptional situation (if it is recoverable). It's just that checked exceptions are overused in the Java platform, which makes people hate them.

Here's my extended view on the topic.

As for the particular questions:

  1. Is the NumberFormatException considered a checked exception?
    No. NumberFormatException is unchecked (= is subclass of RuntimeException). Why? I don't know. (but there should have been a method isValidInteger(..))

  2. Is RuntimeException an unchecked exception?
    Yes, exactly.

  3. What should I do here?
    It depends on where this code is and what you want to happen. If it is in the UI layer - catch it and show a warning; if it's in the service layer - don't catch it at all - let it bubble. Just don't swallow the exception. If an exception occurs, in most of the cases, you should choose one of these:

  • log it and return
  • rethrow it (declare it to be thrown by the method)
  • construct a new exception by passing the current one in constructor
  1. Now, couldn't the above code also be a checked exception? I can try to recover the situation like this? Can I?
    It could've been. But nothing stops you from catching the unchecked exception as well.

  2. Why do people add class Exception in the throws clause?
    Most often because people are lazy to consider what to catch and what to rethrow. Throwing Exception is a bad practice and should be avoided.

Alas, there is no single rule to let you determine when to catch, when to rethrow, when to use checked and when to use unchecked exceptions. I agree this causes much confusion and a lot of bad code. The general principle is stated by Bloch (you quoted a part of it). And the general principle is to rethrow an exception to the layer where you can handle it.

慕烟庭风 2024-11-16 19:05:50

某件事是否是“检查异常”与您是否捕获它或您在 catch 块中执行的操作无关。它是异常类的属性。任何 RuntimeException 及其子类的 Exception except 子类都是受检查异常。

Java 编译器强制您捕获已检查的异常或在方法签名中声明它们。它本应提高程序安全性,但大多数人的观点似乎是不值得它所造成的设计问题。

为什么他们让异常冒泡
向上?是不是越早处理错误
更好的?为什么会冒泡?

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

Whether something is a "checked exception" has nothing to do with whether you catch it or what you do in the catch block. It's a property of exception classes. Anything that is a subclass of Exception except for RuntimeException and its subclasses is a checked exception.

The Java compiler forces you to either catch checked exceptions or declare them in the method signature. It was supposed to improve program safety, but the majority opinion seems to be that it's not worth the design problems it creates.

Why do they let the exception bubble
up? Isnt handle error the sooner the
better? Why bubble up?

Because that's the entire point of exceptions. Without this possibility, you would not need exceptions. They enable you to handle errors at a level you choose, rather than forcing you to deal with them in low-level methods where they originally occur.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文