在Java中,何时应该创建一个已检查的异常,何时应该是运行时异常? [重复]

时间:2022-01-21 23:18:06

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 Exception or RuntimeException? Or should I just use IllegalArgumentException instead?

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

14 个解决方案

#1


101  

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,我在编译时*至少在调用者中确认异常。对于运行时异常,我不会被编译器强迫,但可以编写一个单元测试,让我处理它。因为我仍然认为越早发现一个bug就越便宜,我就更喜欢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.

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

#2


39  

In general, I think the advice by Joshua Bloch in Effective Java best 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中的建议最能总结出你的问题的答案:使用已检查的可恢复条件和编程错误的运行时异常(第2版第58项)。

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 not be called without checking for sufficient balance first by using some other Account method - but this would seem a bit awkward.)

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

But also note Items 59: Avoid unnecessary use of checked exceptions and 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(或者可能是状态对象,其中包含发生的事件的详细信息)。

#3


33  

When to use checked exceptions? Honestly? In my humble opinion... never. I think it's been about 6 years since I last created a checked exception.

何时使用已检查的例外?说实话?以我的拙见......永远不会。我认为自从我上次创建一个检查异常以来已经过去了大约6年。

You can't force someone to deal with an error. Arguably it makes code worse not better. I can't tell you the number of times I've come across code like this:

你不能强迫某人处理错误。可以说,它使代码变得更糟,而不是更好。我不能告诉你我遇到这样的代码的次数:

try {
  ...
} catch (IOException e) {
  // do nothing
}

Whereas I have countless times written code like this:

虽然我有无数次编写这样的代码:

try {
  ...
} catch (IOException e) {
  throw new RuntimeExceptione(e);
}

Why? Because a condition (not necessarily IOException; that's just an example) wasn't recoverable but was forced down my throat anyway and I am often forced to make the choice between doing the above and polluting my API just to propagate a checked exception all the way to the top where it's (rightlfully) fatal and will be logged.

为什么?因为一个条件(不一定是IOException;这只是一个例子)是不可恢复的,但无论如何都*放下我的喉咙而且我经常*做出上述操作并污染我的API只是为了传播一个检查过的异常到顶部它(正确地)致命并将被记录。

There's a reason Spring's DAO helper classes translate the checked SQLException into the unchecked DataAccessException.

Spring的DAO帮助程序类将检查的SQLException转换为未经检查的DataAccessException是有原因的。

If you have things like lack of write permissions to a disk, lack of disk space or other fatal conditions you want to be making as much noise as possible and the way to do this is with... unchecked exceptions (or even Errors).

如果您对磁盘缺少写入权限,缺少磁盘空间或其他致命条件,您希望尽可能多地产生噪声,并且执行此操作的方法是使用...未经检查的异常(甚至是错误)。

Additionally, checked exceptions break encapsulation.

此外,已检查的异常会破坏封装。

This idea that checked exceptions should be used for "recoverable" errors is really pie-in-the-sky wishful thinking.

检查异常的这个想法应该被用于“可恢复的”错误,这实际上是天上一厢情愿的想法。

Checked exceptions in Java were an experiment... a failed experiment. We should just cut our losses, admit we made a mistake and move on. IMHO .Net got it right by only having unchecked exceptions. Then again it had the second-adopter advantage of learning from Java's mistakes.

Java中检查的异常是一个实验......一个失败的实验。我们应该减少损失,承认我们犯了错误并继续前进。恕我直言.Net通过仅具有未经检查的异常使其正确。然后,它再次获得了从Java的错误中学习的第二个优势。

#4


8  

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. THAT is 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 true became 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.

在这种情况下,你有你所有的鸭子,并且知道你无能为力(因为真的变成了假,就好像它本身一样),除了记录异常,向某人发送通知,并告诉客户礼貌地说,有人在上一次满月期间没有正确地牺牲他们的处女,问题将在第一个可能的时刻得到解决。

less-enterprisey-suggestion-edit:

不太enterprisey暗示编辑:

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

#5


7  

I recently had a problem with exceptions, code threw NullPointerException and I had no idea why, after some investigation it turned out that real exception was swallowed(it was in new code, so its still being done) and method just returned null. If you do checked exceptions you must understand that bad programmers will just try catch it and ignore exception.

我最近遇到了异常问题,代码抛出了NullPointerException,我不知道为什么,经过一些调查后发现真正的异常被吞噬了(它是在新代码中,所以它仍在进行中)并且方法只返回n​​ull。如果你确实检查了异常,你必须明白坏程序员只会尝试捕获它并忽略异常。

#6


6  

My rule is

我的规则是

  • if statements for business logic errors (like your code)
  • if语句的业务逻辑错误(如代码)
  • 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. 已检查例外的示例:对于可脱机工作的应用程序,网络已关闭
    3. Example for uncheched exception: Database is down on a CRUD web application.
    4. 未经检查的异常的示例:数据库在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的例外从已检查更改为未选中

#7


6  

From Unchecked Exceptions -- The Controversy:

来自未经检查的例外 - 争议:

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.

如果可以合理地期望客户端从异常中恢复,请将其作为已检查的异常。如果客户端无法执行任何操作以从异常中恢复,请将其设置为未经检查的异常。

Note that an unchecked exception is one derived from RuntimeException and a checked exception is one derived from Exception.

请注意,未经检查的异常是从RuntimeException派生的异常,并且已检查的异常是从Exception派生的异常。

Why throw a RuntimeException if a client cannot do anything to recover from the exception? The article explains:

如果客户端无法执行任何从异常中恢复的操作,为什么抛出RuntimeException?文章解释说:

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.

运行时异常表示编程问题导致的问题,因此,无法合理地期望API客户端代码从它们恢复或以任何方式处理它们。这些问题包括算术异常,例如除以零;指针异常,例如尝试通过空引用访问对象;索引异常,例如尝试通过索引太大或太小来访问数组元素。

#8


5  

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 Account doesn't have enough money is a serious enough problem that you have to deal with it.

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

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, FindBugs can 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.

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

#9


3  

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这样的描述性名称,以便清楚地说明发生了什么。

#10


3  

Line isn't always clear, but for me usually runtime exceptions = 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.

行并不总是清楚,但对我来说通常运行时异常=编程错误,检查异常=外部错误。这是非常粗略的分类。像其他人说的那样,经过检查的例外情况会迫使你处理,或者至少在很短的时间内考虑它。

#11


3  

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)

#12


3  

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 essay on this topic.

Thinking in Java的作者Bruce Eckel对这个主题有一篇很好的文章。

#13


3  

I don't think the scenario (insufficient funds) warrants throwing an Exception --- it's simply not exceptional 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 RuntimeException which is unchecked. This forces me to handle the exception explicitly (I need to declare it to be thrown, or catch it somewhere).

我不认为情景(资金不足)保证抛出异常 - 它根本不够特别,应该由程序的正常控制流来处理。但是,如果我真的不得不抛出异常,我会选择一个已检查的异常,通过扩展Exception而不是未选中的RuntimeException。这迫使我明确地处理异常(我需要声明它被抛出,或者在某处捕获它)。

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

EDIT: Clarified my position on throwing IllegalArgumentException.

编辑:澄清了我抛出IllegalArgumentException的立场。

#14


1  

Myself, I prefer using checked exceptions as I can.

我自己,我更喜欢使用经过检查的例外情况。

If you are an API Developer (back-end developer), use checked exceptions, otherwise, use Runtime exceptions.

如果您是API Developer(后端开发人员),请使用已检查的异常,否则,请使用运行时异常。

Also note that, using Runtime exceptions in some situations is to be considered a big mistake, for example if you are to throw runtime exceptions from your session beans (see : http://m-hewedy.blogspot.com/2010/01/avoid-throwing-runtimeexception-from.html for more info about the problem from using Runtime excpetions in session beans).

另请注意,在某些情况下使用运行时异常会被视为一个大错误,例如,如果要从会话bean中抛出运行时异常(请参阅:http://m-hewedy.blogspot.com/2010/01/ avoid-throwing-runtimeexception-from.html,了解有关在会话bean中使用运行时激活的问题的更多信息)。

#1


101  

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,我在编译时*至少在调用者中确认异常。对于运行时异常,我不会被编译器强迫,但可以编写一个单元测试,让我处理它。因为我仍然认为越早发现一个bug就越便宜,我就更喜欢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.

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

#2


39  

In general, I think the advice by Joshua Bloch in Effective Java best 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中的建议最能总结出你的问题的答案:使用已检查的可恢复条件和编程错误的运行时异常(第2版第58项)。

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 not be called without checking for sufficient balance first by using some other Account method - but this would seem a bit awkward.)

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

But also note Items 59: Avoid unnecessary use of checked exceptions and 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(或者可能是状态对象,其中包含发生的事件的详细信息)。

#3


33  

When to use checked exceptions? Honestly? In my humble opinion... never. I think it's been about 6 years since I last created a checked exception.

何时使用已检查的例外?说实话?以我的拙见......永远不会。我认为自从我上次创建一个检查异常以来已经过去了大约6年。

You can't force someone to deal with an error. Arguably it makes code worse not better. I can't tell you the number of times I've come across code like this:

你不能强迫某人处理错误。可以说,它使代码变得更糟,而不是更好。我不能告诉你我遇到这样的代码的次数:

try {
  ...
} catch (IOException e) {
  // do nothing
}

Whereas I have countless times written code like this:

虽然我有无数次编写这样的代码:

try {
  ...
} catch (IOException e) {
  throw new RuntimeExceptione(e);
}

Why? Because a condition (not necessarily IOException; that's just an example) wasn't recoverable but was forced down my throat anyway and I am often forced to make the choice between doing the above and polluting my API just to propagate a checked exception all the way to the top where it's (rightlfully) fatal and will be logged.

为什么?因为一个条件(不一定是IOException;这只是一个例子)是不可恢复的,但无论如何都*放下我的喉咙而且我经常*做出上述操作并污染我的API只是为了传播一个检查过的异常到顶部它(正确地)致命并将被记录。

There's a reason Spring's DAO helper classes translate the checked SQLException into the unchecked DataAccessException.

Spring的DAO帮助程序类将检查的SQLException转换为未经检查的DataAccessException是有原因的。

If you have things like lack of write permissions to a disk, lack of disk space or other fatal conditions you want to be making as much noise as possible and the way to do this is with... unchecked exceptions (or even Errors).

如果您对磁盘缺少写入权限,缺少磁盘空间或其他致命条件,您希望尽可能多地产生噪声,并且执行此操作的方法是使用...未经检查的异常(甚至是错误)。

Additionally, checked exceptions break encapsulation.

此外,已检查的异常会破坏封装。

This idea that checked exceptions should be used for "recoverable" errors is really pie-in-the-sky wishful thinking.

检查异常的这个想法应该被用于“可恢复的”错误,这实际上是天上一厢情愿的想法。

Checked exceptions in Java were an experiment... a failed experiment. We should just cut our losses, admit we made a mistake and move on. IMHO .Net got it right by only having unchecked exceptions. Then again it had the second-adopter advantage of learning from Java's mistakes.

Java中检查的异常是一个实验......一个失败的实验。我们应该减少损失,承认我们犯了错误并继续前进。恕我直言.Net通过仅具有未经检查的异常使其正确。然后,它再次获得了从Java的错误中学习的第二个优势。

#4


8  

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. THAT is 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 true became 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.

在这种情况下,你有你所有的鸭子,并且知道你无能为力(因为真的变成了假,就好像它本身一样),除了记录异常,向某人发送通知,并告诉客户礼貌地说,有人在上一次满月期间没有正确地牺牲他们的处女,问题将在第一个可能的时刻得到解决。

less-enterprisey-suggestion-edit:

不太enterprisey暗示编辑:

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

#5


7  

I recently had a problem with exceptions, code threw NullPointerException and I had no idea why, after some investigation it turned out that real exception was swallowed(it was in new code, so its still being done) and method just returned null. If you do checked exceptions you must understand that bad programmers will just try catch it and ignore exception.

我最近遇到了异常问题,代码抛出了NullPointerException,我不知道为什么,经过一些调查后发现真正的异常被吞噬了(它是在新代码中,所以它仍在进行中)并且方法只返回n​​ull。如果你确实检查了异常,你必须明白坏程序员只会尝试捕获它并忽略异常。

#6


6  

My rule is

我的规则是

  • if statements for business logic errors (like your code)
  • if语句的业务逻辑错误(如代码)
  • 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. 已检查例外的示例:对于可脱机工作的应用程序,网络已关闭
    3. Example for uncheched exception: Database is down on a CRUD web application.
    4. 未经检查的异常的示例:数据库在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的例外从已检查更改为未选中

#7


6  

From Unchecked Exceptions -- The Controversy:

来自未经检查的例外 - 争议:

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.

如果可以合理地期望客户端从异常中恢复,请将其作为已检查的异常。如果客户端无法执行任何操作以从异常中恢复,请将其设置为未经检查的异常。

Note that an unchecked exception is one derived from RuntimeException and a checked exception is one derived from Exception.

请注意,未经检查的异常是从RuntimeException派生的异常,并且已检查的异常是从Exception派生的异常。

Why throw a RuntimeException if a client cannot do anything to recover from the exception? The article explains:

如果客户端无法执行任何从异常中恢复的操作,为什么抛出RuntimeException?文章解释说:

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.

运行时异常表示编程问题导致的问题,因此,无法合理地期望API客户端代码从它们恢复或以任何方式处理它们。这些问题包括算术异常,例如除以零;指针异常,例如尝试通过空引用访问对象;索引异常,例如尝试通过索引太大或太小来访问数组元素。

#8


5  

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 Account doesn't have enough money is a serious enough problem that you have to deal with it.

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

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, FindBugs can 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.

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

#9


3  

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这样的描述性名称,以便清楚地说明发生了什么。

#10


3  

Line isn't always clear, but for me usually runtime exceptions = 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.

行并不总是清楚,但对我来说通常运行时异常=编程错误,检查异常=外部错误。这是非常粗略的分类。像其他人说的那样,经过检查的例外情况会迫使你处理,或者至少在很短的时间内考虑它。

#11


3  

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)

#12


3  

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 essay on this topic.

Thinking in Java的作者Bruce Eckel对这个主题有一篇很好的文章。

#13


3  

I don't think the scenario (insufficient funds) warrants throwing an Exception --- it's simply not exceptional 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 RuntimeException which is unchecked. This forces me to handle the exception explicitly (I need to declare it to be thrown, or catch it somewhere).

我不认为情景(资金不足)保证抛出异常 - 它根本不够特别,应该由程序的正常控制流来处理。但是,如果我真的不得不抛出异常,我会选择一个已检查的异常,通过扩展Exception而不是未选中的RuntimeException。这迫使我明确地处理异常(我需要声明它被抛出,或者在某处捕获它)。

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

EDIT: Clarified my position on throwing IllegalArgumentException.

编辑:澄清了我抛出IllegalArgumentException的立场。

#14


1  

Myself, I prefer using checked exceptions as I can.

我自己,我更喜欢使用经过检查的例外情况。

If you are an API Developer (back-end developer), use checked exceptions, otherwise, use Runtime exceptions.

如果您是API Developer(后端开发人员),请使用已检查的异常,否则,请使用运行时异常。

Also note that, using Runtime exceptions in some situations is to be considered a big mistake, for example if you are to throw runtime exceptions from your session beans (see : http://m-hewedy.blogspot.com/2010/01/avoid-throwing-runtimeexception-from.html for more info about the problem from using Runtime excpetions in session beans).

另请注意,在某些情况下使用运行时异常会被视为一个大错误,例如,如果要从会话bean中抛出运行时异常(请参阅:http://m-hewedy.blogspot.com/2010/01/ avoid-throwing-runtimeexception-from.html,了解有关在会话bean中使用运行时激活的问题的更多信息)。