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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/499437/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 15:24:41  来源:igfitidea点击:

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

javaexception

提问by Hosam Aly

Possible Duplicate:
When to choose checked and unchecked exceptions

可能的重复:
何时选择已检查和未检查的异常

When should I create a checked exception, and when should I make a runtime exception?

我什么时候应该创建一个检查异常,什么时候我应该创建一个运行时异常?

For example, suppose I created the following class:

例如,假设我创建了以下类:

public class Account {
    private float balance;

    /* ... constructor, getter, and other fields and methods */

    public void transferTo(Account other, float amount) {
        if (amount > balance)
            throw new NotEnoughBalanceException();
        /* ... */
    }
}

How should I create my NotEnoughBalanceException? Should it extend Exceptionor RuntimeException? Or should I just use IllegalArgumentExceptioninstead?

我应该如何创建我的NotEnoughBalanceException?应该延长Exception还是延长RuntimeException?或者我应该只使用它IllegalArgumentException

采纳答案by Don Branson

There's a LOT of disagreement on this topic. At my last job, we ran into some real issues with Runtime exceptions being forgotten until they showed up in production (on agedwards.com), so we resolved to use checked exceptions exclusively.

在这个话题上有很多分歧。在我的上一份工作中,我们遇到了一些实际问题,即运行时异常被遗忘,直到它们出现在生产环境中(在agedwards.com 上),因此我们决定只使用受检异常。

At my current job, I find that there are many who are for Runtime exceptions in many or all cases.

在我目前的工作中,我发现有很多人在许多或所有情况下都适用于运行时异常。

Here's what I think: Using CheckedExceptions, I am forced at compile time to at least acknowledge the exception in the caller. With Runtime exceptions, I am not forced to by the compiler, but can write a unit test that makes me deal with it. Since I still believe that the earlier a bug is caught the cheaper it is to fix it, I prefer CheckedExceptions for this reason.

这就是我的想法:使用 CheckedExceptions,我被迫在编译时至少确认调用者中的异常。对于运行时异常,编译器不会强迫我这样做,但可以编写一个单元测试来处理它。因为我仍然相信越早发现错误修复它的成本越低,因此我更喜欢 CheckedExceptions。

From a philosophical point of view, a method call is a contract to some degree between the caller and the called. Since the compiler enforces the types of parameters that are passed in, it seems symmetrical to let it enforce the types on the way out. That is, return values or exceptions.

从哲学的角度来看,方法调用在某种程度上是调用者和被调用者之间的契约。由于编译器强制执行传入的参数类型,因此让它在输出时强制执行类型似乎是对称的。即,返回值或异常。

My experience tells me that I get higher quality, that is, code that JUST WORKS, when I'm using checked exceptions. Checked exceptions may clutter code, but there are techniques to deal with this. I like to translate exceptions when passing a layer boundary. For example, if I'm passing up from my persistence layer, I would like to convert an SQL exception to a persistence exception, since the next layer up shouldn't care that I'm persisting to a SQL database, but will want to know if something could not be persisted. Another technique I use is to create a simple hierarchy of exceptions. This lets me write cleaner code one layer up, since I can catch the superclass, and only deal with the individual subclasses when it really matters.

我的经验告诉我,当我使用受检异常时,我获得了更高质量的代码,即可以正常工作的代码。检查异常可能会使代码混乱,但有一些技术可以解决这个问题。我喜欢在通过层边界时转换异常。例如,如果我从持久层传递过来,我想将 SQL 异常转换为持久性异常,因为下一层不应该关心我是否持久化到 SQL 数据库,但会想要知道是否有些事情无法持久化。我使用的另一种技术是创建一个简单的异常层次结构。这让我可以在上一层编写更清晰的代码,因为我可以捕获超类,并且只在真正重要时才处理各个子类。

回答by Henrik Paul

IMHO, it shouldn't be an exception at all. An exception, in my mind, should be used when exceptional things happen, and not as flow controls.

恕我直言,它根本不应该是一个例外。在我看来,异常应该在发生异常时使用,而不是作为流程控制。

In your case, it isn't at all an exceptional status that someone tries to transfer more money than the balance allows. I figure these things happen very often in the real world. So you should program against these situations. An exception might be that your if-statement evaluates the balance good, but when the money is actually being subtracted from the account, the balance isn't good anymore, for some strange reason.

在您的情况下,有人试图转移比余额允许的更多的钱,这根本不是一种特殊情况。我认为这些事情在现实世界中经常发生。所以你应该针对这些情况进行编程。一个例外可能是您的 if 语句评估余额良好,但是当实际从帐户中减去资金时,由于某些奇怪的原因,余额不再好。

An exception might be that, just before calling transferTo(), you checked that the line was open to the bank. But inside the transferTo(), the code notices that the line isn't open any more, although, by all logic, it should be. THATis an exception. If the line can't be opened, that's not an exception, that's a plausible situation.

一个例外可能是,就在调用 之前transferTo(),您检查了该线路是否对银行开放。但是在 内部transferTo(),代码注意到该行不再打开,尽管按照所有逻辑,它应该打开。是个例外。如果无法打开线路,那不是例外,这是一种似是而非的情况。

IMHO recap: Exceptions == weird black magic.

恕我直言:例外==奇怪的黑魔法。

being-constructive-edit:

建设性编辑:

So, not to be all too contradictive, the method itself might very well throw an exception. But the use of the method should be controlled: You first check the balance (outside of the transferTo()method), and if the balance is good, only then call transferTo(). If transferTo()notices that the balance, for some odd reason, isn't good anymore, you throw the exception, which you diligently catch.

所以,不要太矛盾,方法本身很可能会抛出异常。但是要控制方法的使用:首先检查余额(transferTo()方法外),如果余额良好,则调用transferTo(). 如果transferTo()注意到由于某种奇怪的原因,平衡不再好,你抛出异常,你努力捕捉。

In that case, you have all your ducks in a row, and know that there's nothing more you can do (because what was truebecame false, as if by itself), other than log the exception, send a notification to someone, and tell the customer politely that someone didn't sacrifice their virgins properly during the last full moon, and the problem will be fixed at the first possible moment.

在这种情况下,您将所有的鸭子排成一排,并且知道除了记录异常,向某人发送通知并告诉客户之外,您无能为力(因为true变成了false,就像它自己一样)礼貌地说,有人没有在最后一次满月期间适当地牺牲他们的处女,问题将在第一时间得到解决。

less-enterprisey-suggestion-edit:

少企业建议编辑:

If you are doing this for your own pleasure (and the case seems to be this, see comments), I'd suggest returning a boolean instead. The usage would be something like this:

如果您这样做是为了自己的乐趣(情况似乎就是这样,请参阅评论),我建议您返回一个布尔值。用法是这样的:

// ...
boolean success = transferTo(otherAccount, ONE_MILLION_DOLLARS_EXCLAMATION);

if (!success) {
  UI.showMessage("Aww shucks. You're not that rich");
  return; // or something...
} else {
  profit();
}
// ...

回答by duffymo

A checked exception means that clients of your class are forced to deal with it by the compiler. Their code cannot compile unless they add a try/catch block.

已检查异常意味着您的类的客户端被编译器强制处理。除非他们添加 try/catch 块,否则他们的代码无法编译。

The designers of C# have decided that unchecked exceptions are preferred.

C# 的设计者已经决定首选未经检查的异常。

Or you can follow the C-style and check return values and not throw exceptions.

或者您可以遵循 C 风格并检查返回值而不抛出异常。

Exceptions do have a cost, so they shouldn't be used for control flow, as noted earlier. But the one thing they have going for them is that they can't be ignored.

异常确实有成本,所以它们不应该用于控制流,如前所述。但他们为他们做的一件事是他们不能被忽视。

If you decide that in this case to eschew exceptions, you run the risk that a client of your class will ignore the return value or fail to check the balance before trying to transfer.

如果您决定在这种情况下避开异常,您将面临这样的风险:您的类的客户端将忽略返回值或在尝试转移之前无法检查余额。

I'd recommend an unchecked exception, and I'd give it a descriptive name like InsufficientFundsException to make it quite clear what was going on.

我会推荐一个未经检查的异常,我会给它一个描述性的名字,比如 InsufficientFundsException 来清楚地说明发生了什么。

回答by Peter ?tibrany

Line is not always clear, but for me usually RuntimeException = programming errors, checked exceptions = external errors. This is very rough categorization though. Like others say, checked exceptions force you to handle, or at least think for a very tiny fraction of time, about it.

行并不总是很清楚,但对我来说通常RuntimeException = programming errorschecked exceptions = external errors。不过,这是非常粗略的分类。就像其他人说的那样,受检异常迫使你去处理,或者至少在很短的时间内思考它。

回答by Bob Cross

My feeling is that the checked exception is a useful contract that should be used sparingly. The classic example of where I think a checked exception is a good idea is an InterruptedException. My feeling is that I do want to be able to stop a thread / process when I want it to stop, regardless of how long someone has specified to Thread.sleep().

我的感觉是受检异常是一个有用的契约,应该谨慎使用。我认为检查异常是个好主意的经典示例是InterruptedException。我的感觉是,我确实希望能够在我想要停止线程/进程时停止它,无论有人为 Thread.sleep() 指定了多长时间。

So, trying to answer your specific question, is this something that you absolutely want to make sure that everyone deals with? To my mind, a situation where an Accountdoesn't have enough money is a serious enough problem that you have to deal with it.

所以,试图回答你的具体问题,这是你绝对想要确保每个人都处理的事情吗?在我看来,Account没有足够的钱是一个严重的问题,你必须处理它。

In response to Peter's comment: here's an example using InterruptedException as concrete case of an exception that should be handled and you need to have a useful default handler. Here is what I strongly recommend, certainly at my real job. You should at least do this:

回应Peter的评论:这是一个使用 InterruptedException 作为应该处理的异常的具体案例的示例,您需要有一个有用的默认处理程序。这是我强烈推荐的,当然是在我真正的工作中。你至少应该这样做:

catch (InterruptedException ie) {
    Thread.currentThread().interrupt();
}

That handler will ensure that the code catches the checked exception and does exactly what you want: get this thread to stop. Admittedly, if there's another exception handler / eater upstream, it's not impossible that it will handle the exception less well. Even so, FindBugscan help you find those.

该处理程序将确保代码捕获已检查的异常并执行您想要的操作:让该线程停止。诚然,如果上游有另一个异常处理程序/食者,它处理异常不太好的并非不可能。尽管如此,FindBugs可以帮助您找到这些。

Now, reality sets in: you can't necessarily force everyone who writes an exception handler for your checked exception to handle it well. That said, at least you'll be able to "Find Usages" and know where it is used and give some advice.

现在,现实出现了:您不一定要强迫每个为您检查的异常编写异常处理程序的人都很好地处理它。也就是说,至少您将能够“查找用法”并知道它的使用位置并提供一些建议。

Short form: you're inflicting a load the users of your method if you use a checked exception. Make sure that there's a good reason for it, recommend a correct handling method and document all this extensively.

简短形式:如果您使用已检查的异常,则会对您的方法的用户造成负担。确保有充分的理由,推荐正确的处理方法并广泛记录所有这些。

回答by Yoni

Simply put, use checked exception only as part of external contract for a library, and only if the client wants/needs to catch it. Remember, when using checked exception you are forcing yourself on the caller. With runtime exception, if they are well-documented, you are giving the caller a choice.

简而言之,仅将检查异常用作库的外部合同的一部分,并且仅当客户端想要/需要捕获它时。请记住,当使用受检异常时,您是在强迫自己在调用者身上。除了运行时例外,如果它们被很好地记录下来,你就给了调用者一个选择。

It is a known problem that checked exceptions are over-used in Java, but it doesn't mean that they are all bad. That's why it is such in integral part of the Spring philosophy, for example (http://www.springsource.org/about)

在 Java 中过度使用检查异常是一个已知的问题,但这并不意味着它们都是坏的。这就是为什么它是 Spring 哲学不可或缺的一部分,例如 ( http://www.springsource.org/about)

回答by Jason Day

The advantage of checked exceptions is that the compiler forces the developer to deal with them earlier. The disadvantage, in my mind anyway, is that developers tend to be lazy and impatient, and stub out the exception-handling code with the intention of coming back and fixing it later. Which, of course, rarely happens.

检查异常的优点是编译器会强制开发人员更早地处理它们。无论如何,在我看来,缺点是开发人员倾向于懒惰和不耐烦,并且将异常处理代码存根,以便稍后返回并修复它。当然,这种情况很少发生。

Bruce Eckel, author of Thinking in Java, has a nice essayon this topic.

Thinking in Java 的作者 Bruce Eckel有一篇关于这个主题的好文章

回答by Zach Scrivena

I don't think the scenario (insufficient funds) warrants throwing an Exception--- it's simply notexceptional enough, and should be handled by the normal control flow of the program. However, if I really had to throw an exception, I would choose a checked exception, by extending Exception, not RuntimeExceptionwhich is unchecked. This forces me to handle the exception explicitly (I need to declare it to be thrown, or catch it somewhere).

我不认为这种情况(资金不足)值得抛出Exception--- 它根本不够特殊,应该由程序的正常控制流处理。然而,如果我真的不得不抛出一个异常,我会选择一个受检异常,通过扩展Exception,而不是RuntimeException未经检查的异常。这迫使我显式处理异常(我需要声明它被抛出,或者在某处捕获它)。

IllegalArgumentExceptionis a subclass of RuntimeException, which makes it an unchecked exception. I would only consider throwing this if the caller has some convenient way of determining whether or not the method arguments are legal. In your particular code, it's not clear if the caller has access to balance, or whether the whole "check balance and transfer funds" is an atomic operation (if it isn't then the caller really has no convenient way of validating the arguments).

IllegalArgumentException是 的子类RuntimeException,这使其成为未经检查的异常。如果调用者有一些方便的方法来确定方法参数是否合法,我只会考虑抛出这个。在您的特定代码中,不清楚调用者是否可以访问balance,或者整个“检查余额和转移资金”是否是原子操作(如果不是,则调用者确实没有方便的方法来验证参数)。

EDIT: Clarified my position on throwing IllegalArgumentException.

编辑:澄清了我对 throw 的立场IllegalArgumentException

回答by kazanaki

My rule is

我的规则是

  • ifstatements for business logic errors (like your code)
  • cheched exceptions for environment errors where the application can recover
  • uncheched exception for environment errors where there is no recovery

    1. Example for checked exception: Network is down for an application that can work offline
    2. Example for uncheched exception: Database is down on a CRUD web application.
  • if业务逻辑错误的语句(如您的代码)
  • 检查应用程序可以恢复的环境错误的异常
  • 没有恢复的环境错误的检查异常

    1. 已检查异常示例:可以脱机工作的应用程序的网络已关闭
    2. 未检查异常的示例:CRUD Web 应用程序上的数据库已关闭。

There is much documentation on the subject. You can find a lot by browsing the Hibernate web pages since they changed all exceptions of Hibernate 2.x from checked to unchecked in version 3.x

有很多关于这个主题的文档。您可以通过浏览 Hibernate 网页找到很多内容,因为它们在 3.x 版中将 Hibernate 2.x 的所有异常从已选中更改为未选中

回答by Jonik

In general, I think the advice by Joshua Bloch in Effective Javabest summarises the answer to your question: Use checked expections for recoverable conditions and runtime exceptions for programming errors(Item 58 in 2nd edition).

总的来说,我认为 Joshua Bloch 在Effective Java 中的建议最好地总结了您的问题的答案:对可恢复条件使用检查期望和编程错误的运行时异常(第 58 项第 2 版)。

So in this case, if you really want to use exceptions, it should be a checked one. (Unless the documentation of transferTo()made it very clear that the method must notbe called without checking for sufficient balance first by using some other Accountmethod - but this would seem a bit awkward.)

所以在这种情况下,如果你真的要使用异常,它应该是一个被检查的。(除非 的文档transferTo()非常清楚地说明不得在不首先使用其他Account方法检查足够的余额的情况下调用该方法 - 但这看起来有点尴尬。)

But also note Items 59: Avoid unnecessary use of checked exceptionsand 57: Use exceptions only for exceptional conditions. As others have pointed out, this case may not warrant an exception at all. Consider returning false(or perhaps a status object with details about what happened) if there is not enough credit.

但还要注意条款 59:避免不必要地使用受检异常和 57:仅在异常情况下使用异常。正如其他人指出的那样,这种情况可能根本不值得例外。false如果没有足够的信用,请考虑返回(或者可能是一个状态对象,其中包含有关发生的事情的详细信息)。