Java 反对检查异常的情况
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/613954/
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
The case against checked exceptions
提问by TofuBeer
For a number of years now I have been unable to get a decent answer to the following question: why are some developers so against checked exceptions? I have had numerous conversations, read things on blogs, read what Bruce Eckel had to say (the first person I saw speak out against them).
多年来,我一直无法得到以下问题的体面答案:为什么有些开发人员如此反对受检异常?我进行了无数次对话,在博客上阅读了一些内容,阅读了 Bruce Eckel 所说的话(我看到的第一个反对他们的人)。
I am currently writing some new code and paying very careful attention to how I deal with exceptions. I am trying to see the point of view of the "we don't like checked exceptions" crowd and I still cannot see it.
我目前正在编写一些新代码,并非常注意我如何处理异常。我试图看到“我们不喜欢检查异常”人群的观点,但我仍然看不到它。
Every conversation I have ends with the same question going unanswered... let me set it up:
我的每一次对话都以同样的问题结束……让我设置一下:
In general (from how Java was designed),
一般来说(从 Java 的设计方式来看),
Error
is for things that should never be caught (VM has a peanut allergy and someone dropped a jar of peanuts on it)RuntimeException
is for things that the programmer did wrong (programmer walked off the end of an array)Exception
(exceptRuntimeException
) is for things that are out of the programmer's control (disk fills up while writing to the file system, file handle limit for the process has been reached and you cannot open any more files)Throwable
is simply the parent of all of the exception types.
Error
用于永远不应该被捕获的东西(VM 对花生过敏,有人在上面掉了一罐花生)RuntimeException
用于程序员做错的事情(程序员走出数组的末尾)Exception
(exceptRuntimeException
) 用于程序员无法控制的事情(写入文件系统时磁盘已满,已达到进程的文件句柄限制,您无法再打开任何文件)Throwable
只是所有异常类型的父级。
A common argument I hear is that if an exception happens then all the developer is going to do is exit the program.
我听到的一个常见论点是,如果发生异常,那么开发人员要做的就是退出程序。
Another common argument I hear is that checked exceptions make it harder to refactor code.
我听到的另一个常见论点是检查异常使重构代码变得更加困难。
For the "all I am going to do is exit" argument I say that even if you are exiting you need to display a reasonable error message. If you are just punting on handling errors then your users won't be overly happy when the program exits without a clear indication of why.
对于“我要做的就是退出”的论点,我说即使您要退出,也需要显示合理的错误消息。如果您只是在处理错误,那么当程序退出而没有明确说明原因时,您的用户将不会过于高兴。
For the "it makes it hard to refactor" crowd, that indicates that the proper level of abstraction wasn't chosen. Rather than declare a method throws an IOException
, the IOException
should be transformed into an exception that is more suited for what is going on.
对于“很难重构”的人群,这表明没有选择适当的抽象级别。与其声明一个方法抛出 an IOException
,不如IOException
将 转化为更适合正在发生的事情的异常。
I don't have an issue with wrapping Main with catch(Exception)
(or in some cases catch(Throwable)
to ensure that the program can exit gracefully - but I always catch the specific exceptions I need to. Doing that allows me to, at the very least, display an appropriate error message.
我在用catch(Exception)
(或在某些情况下catch(Throwable)
确保程序可以正常退出)包装 Main 没有问题- 但我总是捕获我需要的特定异常。这样做至少可以让我显示适当的错误信息。
The question that people never reply to is this:
人们永远不会回答的问题是:
If you throw
RuntimeException
subclasses instead ofException
subclasses then how do you know what you are supposed to catch?
如果你抛出
RuntimeException
子类而不是Exception
子类,那么你怎么知道你应该捕捉什么?
If the answer is catch Exception
then you are also dealing with programmer errors the same way as system exceptions. That seems wrong to me.
如果答案是catch,Exception
那么您也在以与系统异常相同的方式处理程序员错误。这对我来说似乎是错误的。
If you catch Throwable
then you are treating system exceptions and VM errors (and the like) the same way. That seems wrong to me.
如果您捕获,Throwable
那么您正在以相同的方式处理系统异常和 VM 错误(等等)。这对我来说似乎是错误的。
If the answer is that you catch only the exceptions you know are thrown then how do you know what ones are thrown? What happens when programmer X throws a new exception and forgot to catch it? That seems very dangerous to me.
如果答案是你只捕获你知道抛出的异常,那么你怎么知道抛出了什么异常?当程序员 X 抛出一个新异常并忘记捕获它时会发生什么?这对我来说似乎很危险。
I would say that a program that displays a stack trace is wrong. Do people who don't like checked exceptions not feel that way?
我会说显示堆栈跟踪的程序是错误的。不喜欢受检异常的人不会有这种感觉吗?
So, if you don't like checked exceptions can you explain why not AND answer the question that doesn't get answered please?
所以,如果你不喜欢检查异常,你能解释一下为什么不并回答没有得到回答的问题吗?
Edit: I am not looking for advice on when to use either model, what I am looking for is whypeople extend from RuntimeException
because they don't like extending from Exception
and/or why they catch an exception and then rethrow a RuntimeException
rather than add throws to their method. I want to understand the motivation for disliking checked exceptions.
编辑:我不是在寻求关于何时使用任何一种模型的建议,我正在寻找的是为什么人们扩展RuntimeException
因为他们不喜欢扩展Exception
和/或为什么他们捕获异常然后重新抛出RuntimeException
而不是添加抛出他们的方法。我想了解不喜欢受检异常的动机。
回答by tsimon
I initially agreed with you, as I've always been in favour of checked exceptions, and began to think about why I don't like not having checked exceptions in .Net. But then I realised that I don't infact like checked exceptions.
我最初同意你的看法,因为我一直支持受检异常,并开始思考为什么我不喜欢在 .Net 中没有受检异常。但后来我意识到我实际上并不喜欢受检异常。
To answer you question, yes, I like my programs to show stack traces, preferably really ugly ones. I want the application to explode into a horrible heap of the ugliest error messages you could ever want to see.
回答你的问题,是的,我喜欢我的程序显示堆栈跟踪,最好是非常丑陋的。我希望应用程序爆炸成一堆你可能想看到的最丑陋的错误消息。
And the reason is because, if it does that, I have to fix it, and I have to fix it right away. I want to know immediately that there is a problem.
原因是,如果它这样做了,我必须修复它,而且我必须立即修复它。我想立即知道有问题。
How many times do you actually handle exceptions? I'm not talking about catching exceptions -- I'm talking about handling them? It's too easy to write the following:
你实际处理过多少次异常?我不是在谈论捕获异常——我在谈论处理它们?编写以下内容太容易了:
try {
thirdPartyMethod();
} catch(TPException e) {
// this should never happen
}
And I know you can say that it's bad practice, and that 'the answer' is to do something with the exception (let me guess, log it?), but in the Real World (tm), most programmers just don't do it.
我知道你可以说这是不好的做法,“答案”是做一些例外的事情(让我猜猜,记录它?),但在现实世界(tm)中,大多数程序员只是不这样做它。
So yes, I don't want to catch exceptions if I don't have to do so, and I want my program to blow up spectacularly when I screw up. Silently failing is the worst possible outcome.
所以是的,如果我不需要的话,我不想捕获异常,并且我希望我的程序在我搞砸时爆炸。默默地失败是最糟糕的结果。
回答by finnw
Here's one argument against checked exceptions (from joelonsoftware.com):
这是反对检查异常的一个论点(来自 joelonsoftware.com):
The reasoning is that I consider exceptions to be no better than "goto's", considered harmful since the 1960s, in that they create an abrupt jump from one point of code to another. In fact they are significantly worse than goto's:
- They are invisible in the source code. Looking at a block of code, including functions which may or may not throw exceptions, there is no way to see which exceptions might be thrown and from where. This means that even careful code inspection doesn't reveal potential bugs.
- They create too many possible exit points for a function. To write correct code, you really have to think about every possible code path through your function. Every time you call a function that can raise an exception and don't catch it on the spot, you create opportunities for surprise bugs caused by functions that terminated abruptly, leaving data in an inconsistent state, or other code paths that you didn't think about.
理由是我认为异常并不比“goto”更好,自 1960 年代以来就被认为是有害的,因为它们会造成从一个代码点到另一个代码点的突然跳转。事实上,它们比 goto 的要差很多:
- 它们在源代码中是不可见的。查看一个代码块,包括可能会或可能不会抛出异常的函数,没有办法看到哪些异常可能会被抛出以及从哪里抛出。这意味着即使仔细检查代码也不会发现潜在的错误。
- 它们为函数创建了太多可能的退出点。要编写正确的代码,您确实必须考虑通过您的函数的每个可能的代码路径。每次调用一个可以引发异常但不能当场捕获它的函数时,都会为突然终止的函数、使数据处于不一致状态或其他你没有的代码路径引起的意外错误创造机会想一想。
回答by Mario Ortegón
I have been working with several developers in the last three years in relatively complex applications. We have a code base that uses Checked Exceptions quite often with proper error handling, and some other that doesn't.
在过去的三年中,我一直在与几位开发人员合作开发相对复杂的应用程序。我们有一个代码库,它经常使用检查异常并进行适当的错误处理,而其他一些则没有。
So far, I have it found easier to work with the code base with Checked Exceptions. When I am using someone else's API, it is nice that I can see exactly what kind of error conditions I can expect when I call the code and handle them properly, either by logging, displaying or ignoring (Yes, there is valid cases for ignoring exceptions, such as a ClassLoader implementation). That gives the code I am writing an opportunity to recover. All runtime exceptions I propagate up until they are cached and handled with some generic error handling code. When I find a checked exception that I don't really want to handle at a specific level, or that I consider a programming logic error, then I wrap it into a RuntimeException and let it bubble up. Never, ever swallow an exception without a good reason (and good reasons for doing this are rather scarce)
到目前为止,我发现使用 Checked Exceptions 更容易使用代码库。当我使用其他人的 API 时,当我调用代码并正确处理它们时,通过记录、显示或忽略(是的,有忽略的有效情况),我可以准确地看到我可以预期的错误条件异常,例如 ClassLoader 实现)。这给了我正在编写的代码一个恢复的机会。我传播的所有运行时异常,直到它们被缓存并使用一些通用错误处理代码进行处理。当我发现我真的不想在特定级别处理的已检查异常,或者我认为是编程逻辑错误时,然后我将它包装到 RuntimeException 中并让它冒泡。永远不要在没有充分理由的情况下吞下异常(并且这样做的充分理由相当少)
When I work with the codebase that does not have checked exceptions, it makes it to me a little bit harder to know before hand what can I expect when calling the function, which can break some stuff terribly.
当我使用没有检查异常的代码库时,我很难事先知道调用函数时我能期待什么,这可能会严重破坏某些东西。
This is all of course a matter of preference and developer skill. Both ways of programming and error handling can be equally effective (or noneffective), so I wouldn't say that there is The One Way.
这当然是偏好和开发人员技能的问题。编程和错误处理的两种方式都可以同样有效(或无效),所以我不会说有一种方式。
All in all, I find it easier to work with Checked Exceptions, specially in large projects with lot of developers.
总而言之,我发现使用 Checked Exceptions 更容易,特别是在拥有大量开发人员的大型项目中。
回答by Richard Levasseur
Well, it's not about displaying a stacktrace or silently crashing. It's about being able to communicate errors between layers.
嗯,这与显示堆栈跟踪或静默崩溃无关。这是关于能够在层之间传达错误。
The problem with checked exceptions is they encourage people to swallow important details (namely, the exception class). If you choose not to swallow that detail, then you have to keep adding throws declarations across your whole app. This means 1) that a new exception type will affect lots of function signatures, and 2) you can miss a specific instance of the exception you actually -want- to catch (say you open a secondary file for a function that writes data to a file. The secondary file is optional, so you can ignore its errors, but because the signature throws IOException
, it's easy to overlook this).
检查异常的问题在于它们鼓励人们吞下重要的细节(即异常类)。如果您选择不吞下那个细节,那么您必须在整个应用程序中不断添加 throws 声明。这意味着 1) 新的异常类型将影响许多函数签名,并且 2) 您可能会错过您实际想要捕获的异常的特定实例(假设您打开一个将数据写入一个函数的辅助文件)文件。二级文件是可选的,所以你可以忽略它的错误,但因为签名throws IOException
,很容易忽略这一点)。
I'm actually dealing with this situation now in an application. We repackaged almost exceptions as AppSpecificException. This made signatures really clean and we didn't have to worry about exploding throws
in signatures.
我现在正在一个应用程序中处理这种情况。我们将几乎异常重新打包为 AppSpecificException。这使得签名非常干净,我们不必担心throws
签名爆炸。
Of course, now we need to specialize the error handling at the higher levels, implementing retry logic and such. Everything is AppSpecificException, though, so we can't say "If an IOException is thrown, retry" or "If ClassNotFound is thrown, abort completely". We don't have a reliable way of getting to the realexception because things get repackaged again and again as they pass between our code and third-party code.
当然,现在我们需要专门处理更高级别的错误处理,实现重试逻辑等。但是,一切都是 AppSpecificException,因此我们不能说“如果抛出 IOException,则重试”或“如果抛出 ClassNotFound,则完全中止”。我们没有找到真正异常的可靠方法,因为在我们的代码和第三方代码之间传递时,事情会一次又一次地重新打包。
This is why I'm a big fan of the exception handling in python. You can catch only the things you want and/or can handle. Everything else bubbles up as if you rethrew it yourself (which you have done anyways).
这就是为什么我非常喜欢 python 中的异常处理。您只能捕获您想要和/或可以处理的东西。其他一切都冒泡了,就好像你自己把它扔了一样(反正你已经做了)。
I've found, time and time again, and throughout the project I mentioned, that exception handling falls into 3 categories:
我一次又一次地发现,在我提到的整个项目中,异常处理分为 3 类:
- Catch and handle a specificexception. This is to implement retry logic, for example.
- Catch and rethrow otherexceptions. All that happens here is usually logging, and its usually a trite message like "Unable to open $filename". These are errors you can't do anything about; only a higher levels knows enough to handle it.
- Catch everything and display an error message. This is usually at the very root of a dispatcher, and all it does it make sure it can communicate the error to the caller via a non-Exception mechanism (popup dialogue, marshaling an RPC Error object, etc).
- 捕获并处理特定的异常。例如,这是为了实现重试逻辑。
- 捕获并重新抛出其他异常。这里发生的所有事情通常都是日志记录,它通常是一条陈腐的消息,如“无法打开 $filename”。这些是你无能为力的错误;只有更高的级别知道足以处理它。
- 捕获所有内容并显示错误消息。这通常位于调度程序的最根部,它所做的一切都是为了确保它可以通过非异常机制(弹出对话、编组 RPC 错误对象等)将错误传达给调用者。
回答by oxbow_lakes
I think that this is an excellent question and not at all argumentative. I think that 3rd party libraries should (in general) throw uncheckedexceptions. This means that you can isolate your dependencies on the library (i.e. you don't have to either re-throw their exceptions or throw Exception
- usually bad practice). Spring's DAO layeris an excellent example of this.
我认为这是一个很好的问题,而且完全没有争论性。我认为 3rd 方库应该(通常)抛出未经检查的异常。这意味着您可以隔离对库的依赖关系(即您不必重新抛出异常或抛出Exception
- 通常是不好的做法)。Spring 的DAO 层就是一个很好的例子。
On the other hand, exceptions from the core Java API should in general be checked if they could everbe handled. Take FileNotFoundException
or (my favourite) InterruptedException
. These conditions should almost alwaysbe handled specifically (i.e. your reaction to an InterruptedException
is not the same as your reaction to an IllegalArgumentException
). The fact that your exceptions are checked forces developers to think about whether a condition is handle-able or not. (That said, I've rarely seen InterruptedException
handled properly!)
在另一方面,核心Java API的异常一般应进行检查,如果他们能永远进行处理。采取FileNotFoundException
或(我最喜欢的)InterruptedException
。这些条件几乎总是要特别处理(即您对 anInterruptedException
的反应与对 an 的反应不同IllegalArgumentException
)。检查异常的事实迫使开发人员考虑条件是否可处理。(也就是说,我很少看到InterruptedException
处理得当!)
One more thing - a RuntimeException
is not always "where a developer got something wrong". An illegal argument exception is thrown when you try and create an enum
using valueOf
and there's no enum
of that name. This is not necessarily a mistake by the developer!
还有一件事 - aRuntimeException
并不总是“开发人员出错的地方”。当您尝试创建enum
usingvalueOf
并且没有enum
该名称时,会引发非法参数异常。这不一定是开发人员的错误!
回答by Chuck Conway
Anders speaks about the pitfalls of checked exceptions and why he left them out of C# in episode 97of Software Engineering radio.
Anders 在Software Engineering radio 的第 97 集中谈到了受检异常的陷阱以及他为什么将它们排除在 C# 之外。
回答by Le Dude
Artima published an interviewwith one of the architects of .NET, Anders Hejlsberg, which acutely covers the arguments against checked exceptions. A short taster:
Artima发表了对 .NET 架构师 Anders Hejlsberg的采访,其中敏锐地涵盖了反对受检异常的论点。一个简短的品尝者:
The throws clause, at least the way it's implemented in Java, doesn't necessarily force you to handle the exceptions, but if you don't handle them, it forces you to acknowledge precisely which exceptions might pass through. It requires you to either catch declared exceptions or put them in your own throws clause. To work around this requirement, people do ridiculous things. For example, they decorate every method with, "throws Exception." That just completely defeats the feature, and you just made the programmer write more gobbledy gunk. That doesn't help anybody.
throws 子句,至少它在 Java 中的实现方式,并不一定会强制您处理异常,但是如果您不处理它们,它会迫使您准确地确认哪些异常可能会通过。它要求您要么捕获声明的异常,要么将它们放在您自己的 throws 子句中。为了解决这个要求,人们做了一些荒谬的事情。例如,他们用“抛出异常”来装饰每个方法。这完全破坏了该功能,并且您只是让程序员编写了更多狼吞虎咽的垃圾。这对任何人都没有帮助。
回答by David Lichteblau
In short:
简而言之:
Exceptions are an API design question.-- No more, no less.
异常是一个 API 设计问题。——不多也不少。
The argument for checked exceptions:
检查异常的参数:
To understand why checked exceptions might not be good thing, let's turn the question around and ask: When or why are checked exceptions attractive, i.e. why would you want the compiler to enforce declaration of exceptions?
要理解为什么检查异常可能不是一件好事,让我们把问题反过来问:检查异常何时或为什么有吸引力,即为什么您希望编译器强制声明异常?
The answer is obvious: Sometimes you needto catch an exception, and that is only possible if the code being called offers a specific exception class for the error that you are interested in.
答案很明显:有时您需要捕获异常,并且只有当被调用的代码为您感兴趣的错误提供特定的异常类时才有可能。
Hence, the argument forchecked exceptions is that the compiler forces programmers to declare which exceptions are thrown, and hopefullythe programmer will then also document specific exception classes and the errors that cause them.
因此,争论的checked异常是编译器迫使程序员宣布其抛出异常,并希望程序员也就那么也文档特定的异常类,并导致他们的错误。
In reality though, ever too often a package com.acme
only throws an AcmeException
rather than specific subclasses. Callers then need to handle, declare, or re-signal AcmeExceptions
, but still cannot be certain whether an AcmeFileNotFoundError
happened or an AcmePermissionDeniedError
.
但实际上,一个包经常com.acme
只抛出一个AcmeException
而不是特定的子类。然后调用者需要处理、声明或重新发出信号AcmeExceptions
,但仍然无法确定是AcmeFileNotFoundError
发生了还是AcmePermissionDeniedError
.
So if you're only interested in an AcmeFileNotFoundError
, the solution is to file a feature request with the ACME programmers and tell them to implement, declare, and document that subclass of AcmeException
.
所以,如果你只是在一个感兴趣的AcmeFileNotFoundError
,该解决方案是将文件与ACME编程功能请求,告诉他们实施,申报,而子类文档AcmeException
。
So why bother?
那么何必呢?
Hence, even with checked exceptions, the compiler cannot force programmers to throw usefulexceptions. It is still just a question of the API's quality.
因此,即使有检查异常,编译器也不能强迫程序员抛出有用的异常。这仍然只是 API 质量的问题。
As a result, languages without checked exceptions usually do not fare much worse. Programmers might be tempted to throw unspecific instances of a general Error
class rather than an AcmeException
, but if they care at all about their API quality, they will learn to introduce an AcmeFileNotFoundError
after all.
因此,没有检查异常的语言通常不会更糟。程序员可能倾向于抛出通用Error
类的非特定实例而不是AcmeException
,但如果他们完全关心 API 质量,他们终将学会引入AcmeFileNotFoundError
。
Overall, the specification and documentation of exceptions is not much different from the specification and documentation of, say, ordinary methods. Those, too, are an API design question, and if a programmer forgot to implement or export a useful feature, the API needs to be improved so that you can work with it usefully.
总的来说,异常的规范和文档与普通方法的规范和文档没有太大区别。这些也是 API 设计问题,如果程序员忘记实现或导出有用的功能,则需要改进 API,以便您可以有效地使用它。
If you follow this line of reasoning, it should be obvious that the "hassle" of declaring, catching, and re-throwing of exceptions that is so common in languages like Java often adds little value.
如果您遵循这条推理路线,很明显,在 Java 等语言中非常常见的声明、捕获和重新抛出异常的“麻烦”通常几乎没有增加任何价值。
It is also worth noting that the Java VM does nothave checked exceptions -- only the Java compiler checks them, and class files with changed exception declarations are compatible at run time. Java VM security is not improved by checked exceptions, only coding style.
还值得一提的是,Java虚拟机并没有检查了例外-只是Java编译器检查它们,类文件以改变异常声明是在运行时兼容。Java VM 安全性不是通过检查异常来提高的,只是编码风格。
回答by bobince
The thing about checked exceptions is that they are not really exceptions by the usual understanding of the concept. Instead, they are API alternative return values.
关于受检异常的事情是,按照通常对概念的理解,它们并不是真正的异常。相反,它们是 API 替代返回值。
The whole idea of exceptions is that an error thrown somewhere way down the call chain can bubble up and be handled by code somewhere further up, without the intervening code having to worry about it. Checked exceptions, on the other hand, require every level of code between the thrower and the catcher to declare they know about all forms of exception that can go through them. This is really little different in practice to if checked exceptions were simply special return values which the caller had to check for. eg.[pseudocode]:
异常的整个想法是,调用链下游某处抛出的错误可以冒泡并由更远的代码处理,而无需干预代码担心它。另一方面,受检异常需要抛出器和捕获器之间的每一级代码声明它们知道可以通过它们的所有形式的异常。这在实践中与是否检查异常只是调用者必须检查的特殊返回值几乎没有什么不同。例如。[伪代码]:
public [int or IOException] writeToStream(OutputStream stream) {
[void or IOException] a= stream.write(mybytes);
if (a instanceof IOException)
return a;
return mybytes.length;
}
Since Java can't do alternative return values, or simple inline tuples as return values, checked exceptions are are a reasonable response.
由于 Java 不能将替代返回值或简单的内联元组作为返回值,因此检查异常是合理的响应。
The problem is that a lot of code, including great swathes of the standard library, misuse checked exceptions for real exceptional conditions that you might very well want to catch several levels up. Why is IOException not a RuntimeException? In every other language I can let an IO exception happen, and if I do nothing to handle it, my application will stop and I'll get a handy stack trace to look at. This is the best thing that can happen.
问题是很多代码,包括大量的标准库,在真正的异常情况下滥用检查异常,你可能很想赶上几个级别。为什么 IOException 不是 RuntimeException?在所有其他语言中,我都可以让 IO 异常发生,如果我不采取任何措施来处理它,我的应用程序将停止,我会得到一个方便的堆栈跟踪来查看。这是可能发生的最好的事情。
Maybe two methods up from the example you want to catch all IOExceptions from the whole writing-to-stream process, abort the process and jump into the error reporting code; in Java you can't do that without adding ‘throws IOException' at every call level, even levels that themselves do no IO. Such methods should not need?to know about the exception handling; having to add exceptions to their signatures:
也许你想从整个写入流过程中捕获所有 IOExceptions 的示例中的两个方法,中止该过程并跳转到错误报告代码;在 Java 中,如果不在每个调用级别添加 'throws IOException',你就无法做到这一点,即使是那些本身没有 IO 的级别。这样的方法应该不需要了解异常处理;必须在他们的签名中添加例外:
- unnecessarily increases coupling;
- makes interface signatures very brittle to change;
- makes the code less readable;
- is so annoying that it the common programmer reaction is to defeat the system by doing something horrible like ‘throws Exception', ‘catch (Exception e) {}', or wrapping everything in a RuntimeException (which makes debugging harder).
- 不必要地增加耦合;
- 使界面签名非常难以更改;
- 降低代码可读性;
- 太烦人了,以至于程序员的常见反应是通过执行诸如“抛出异常”、“捕获(异常 e){}”或将所有内容包装在 RuntimeException 中(这使调试更加困难)之类的可怕事情来击败系统。
And then there's plenty of just ridiculous library exceptions like:
然后还有很多荒谬的图书馆例外,例如:
try {
httpconn.setRequestMethod("POST");
}?catch (ProtocolException e) {
throw new CanNeverHappenException("oh dear!");
}
When you have to clutter up your code with ludicrous crud like this, it is no wonder checked exceptions receive a bunch of hate, even though really this is just simple poor API design.
当你不得不像这样用荒谬的 crud 把你的代码弄得乱七八糟时,难怪检查异常会收到一堆讨厌的东西,尽管这实际上只是简单的糟糕的 API 设计。
Another particular bad effect is on Inversion of Control, where component A supplies a callback to generic component B. Component A wants to be able to let an exception throw from its callback back to the place where it called component B, but it can't because that would change the callback interface which is fixed by B. A can only do it by wrapping the real exception in a RuntimeException, which is yet more exception-handling boilerplate to write.
另一个特别不好的影响是控制反转,其中组件 A 向通用组件 B 提供回调。组件 A 希望能够让异常从其回调返回到它调用组件 B 的位置,但它不能因为这会改变由 B 修复的回调接口。 A 只能通过将真正的异常包装在 RuntimeException 中来做到这一点,这是要编写的更多异常处理样板。
Checked exceptions as implemented in Java and its standard library mean boilerplate, boilerplate, boilerplate. In an already verbose language this is not a win.
在 Java 及其标准库中实现的检查异常意味着样板、样板、样板。在已经很冗长的语言中,这不是一场胜利。
回答by cletus
Rather than rehash all the (many) reasons against checked exceptions, I'll pick just one. I've lost count of the number of times I've written this block of code:
与其针对受检异常重新讨论所有(许多)原因,我只会选择一个。我已经记不清我写这段代码的次数了:
try {
// do stuff
} catch (AnnoyingcheckedException e) {
throw new RuntimeException(e);
}
99% of the time I can't do anything about it. Finally blocks do any necessary cleanup (or at least they should).
99% 的时间我对此无能为力。最后块做任何必要的清理(或至少他们应该)。
I've also lost count of the number of times I've seen this:
我也记不清看到这个的次数了:
try {
// do stuff
} catch (AnnoyingCheckedException e) {
// do nothing
}
Why? Because someone had to deal with it and was lazy. Was it wrong? Sure. Does it happen? Absolutely. What if this were an unchecked exception instead? The app would've just died (which is preferable to swallowing an exception).
为什么?因为有人不得不处理它并且很懒惰。错了吗?当然。会发生吗?绝对地。如果这是一个未经检查的异常怎么办?该应用程序将刚刚死亡(这比吞下异常更可取)。
And then we have infuriating code that uses exceptions as a form of flow control, like java.text.Formatdoes. Bzzzt. Wrong. A user putting "abc" into a number field on a form is not an exception.
然后我们有令人愤怒的代码,它使用异常作为一种流控制形式,就像java.text.Format那样。呸。错误的。用户将“abc”放入表单上的数字字段也不例外。
Ok, i guess that was three reasons.
好吧,我想这是三个原因。