Java非检查/检查异常澄清
我一直在阅读有关未经检查与检查的问题的文章,没有任何在线资源真正清楚地说明了两者的区别以及何时使用两者。
据我了解,它们都在运行时抛出,它们都表示超出逻辑预期范围的程序状态,但必须显式捕获已检查的异常,而未检查的异常则不然。
我的问题是,假设为了论证,我有一个方法可以除两个数字
double divide(double numerator, double denominator)
{ return numerator / denominator; }
,还有一个方法需要在某处进行除法
void foo()
{ double a = divide(b, c); }
谁负责检查分母为零的情况,以及是否应该检查或取消检查异常(忽略Java内置的除法)检查)?
那么,divide 方法是否会按原样声明,或者声明
double divide(double numerator, double denominator) throws DivideByZeroException
{
if(denominator == 0) throw DivideByZeroException
else ...
}
void foo()
{
try{
double a = divide(b, c);
}
catch(DivideByZeroException e)
{}
}
为不带检查异常,如 is:
double divide(double numerator, double denominator)
{
if(denominator == 0) throw DivideByZeroException
else ...
}
void foo()
{
if(c != 0)
double a = divide(b, c);
}
并允许 foo 进行除以零检查?
这个问题最初出现在我编写的一个数学程序中,用户输入数字,逻辑类执行计算。我从来不确定 GUI 是否应该立即检查不正确的值,或者内部逻辑是否应该在计算过程中捕获它们并抛出异常。
I've been reading about unchecked versus checked questions, none of the online resources have been truly clear about the difference and when to use both.
From what I understand, both of them get thrown at runtime, both of them represent program states that are outside the expected bounds of the logic, but checked exceptions must be explicitly caught while unchecked ones do not.
My question is, suppose for argument's sake I have a method that divides two numbers
double divide(double numerator, double denominator)
{ return numerator / denominator; }
and a method that requires divison somewhere
void foo()
{ double a = divide(b, c); }
Who is responsible for checking the case of the denominator being zero, and should an exception be checked or unchecked (ignoring Java's built in divison checks)?
So, would the divide method be declared as is or as
double divide(double numerator, double denominator) throws DivideByZeroException
{
if(denominator == 0) throw DivideByZeroException
else ...
}
void foo()
{
try{
double a = divide(b, c);
}
catch(DivideByZeroException e)
{}
}
or without a checked exception, as is:
double divide(double numerator, double denominator)
{
if(denominator == 0) throw DivideByZeroException
else ...
}
void foo()
{
if(c != 0)
double a = divide(b, c);
}
and allow foo to make the divide by zero check?
This problem originally arose in a mathematical program I wrote in which users entered numbers and logic classes performed calculations. I was never sure whether the GUI should check immediately for improper values, or whether the internal logic should catch them during calculation and throw exceptions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
确实是有趣的话题!
在阅读并尝试了多种处理一般错误和具体异常的方法后,我学会了区分程序员错误和预期错误。
程序员错误永远不应该被发现,而应该尽早且严重地崩溃(!)。程序员的错误是由于逻辑错误造成的,应该解决根本原因。
应始终捕获预期错误。此外,当发现预期错误时,必须向用户显示一条消息。这有一个重要的含义 - 如果预期的错误不应该显示错误,那么最好检查该方法是否会抛出而不是让它抛出。
因此,应用于您的示例时,我会想“这对用户来说应该是什么样子?”
旁注:我从不抛出
DivideByZeroException
或NullPointerException
- 我让 JVM 为我抛出这些异常。在这种情况下,您可以编写自己的异常类或使用合适的内置检查异常。Interesting topic indeed!
After reading and trying lots of way to deal with errors in general and exceptions specifically I learned to differ between programmer errors and a expected errors.
Programmer errors should never be caught, but rather crash (!) early and hard. A programmer error is due to a logical fault, and the root cause should be fixed.
Expected errors should always be caught. Also when a expected error is caught a message must be displayed for the user. This has an important implication - If a expected error should not display an error, it's better to check whether the method will throw instead of letting it throw.
So applied to your example I would think "How should this look to the user?"
On a sidenote: I never throw
DivideByZeroException
norNullPointerException
- I let the JVM throw those for me. In this case you could brew your own exception-class or use a suitable built-in checked exception.我最喜欢的关于 Java 中检查异常和非检查异常之间哲学差异的讨论:
http:// /www.javapractices.com/topic/TopicAction.do?Id=129
My favorite discussion on the difference in philosophy between checked and unchecked exceptions in Java:
http://www.javapractices.com/topic/TopicAction.do?Id=129
假设由于数学运算的结果引发了已检查的异常。例如部门(根据您的帖子)。
这意味着每个整数除法都应该出现在 try 块中!
实际上除法会抛出 ArithmeticException,这是未经检查的异常,因此不需要捕获它。
实际上您不应该捕获它,因为这是发生的异常情况,通常只能通过代码更正来解决。
在您的情况下,您的代码应该之前执行一些操作来实际除以零。
如果您已经达到允许实际除以零的步骤,那么您无能为力。该程序是错误的,最好进行修复,而不是尝试通过抛出/捕获异常来掩盖它
Assume that a checked exception is thrown as a result of a mathematical operation. E.g division (as per your post).
This would mean that every integer division should appear in a try block!
Actually division can throw an ArithmeticException which is unchecked exception so there is no need to catch it.
Actually you should not catch it, since it is an exceptional condition that occured and usually can only be solved by code correction.
In your case your code should have done something prior to actually divide by zero.
If you have reached the step where you allow to actually do the division by zero then there is nothing you can do. The program is erroneous and it is best to be fixed than try to somehow disguise it by throwing/catching an exception
Java 异常仅由编译器检查,但是 Java 设计者决定将它们分为多个类别,基本上涉及扩展的超类
catch
块中的处理,而不仅仅是)java.lang。 Error
- 错误,也是未经检查的,很少需要由用户空间代码处理,但了解它们及其差异是一个主要优点。它们包括(最著名的):链接错误、stackoverflow、内存不足、断言错误java.lang.Throwable
- 已检查! 以及所有异常之母,很少需要直接子类化它,但有些出于未知原因这样做,因此需要声明异常并处理适当的传播(仅在编译级别),未经检查的异常会自动传播,除非需要,否则开发人员不应提供处理。
检查通常是预期会发生的,并且需要在 java 中额外的冗长,已经很蓬松的代码。
最糟糕的做法包括:
catch (Throwable t){}
,出于多种原因,除非必要,否则通常不会处理错误,而且大多数错误通常都会导致线程死亡。Java exceptions are checked only by the compiler, however java designers decided to split them into multiple categories, basically involving the superclass being extended
java.lang.Exception
- known as checked exceptionsjava.lang.RuntimeException
known as UNchecked exceptions - as bonus java.land.RuntimeException extends java.lang.Exception (to ease the handling incatch
blocks, and not only)java.lang.Error
- errors, also unchecked and rarely needed to be handled by user-space code, but knowing them and their variance is a major plus. They include (most famous): linkage error, stackoverflow, out of memory, assertion errorsjava.lang.Throwable
- Checked! and the mother of all exceptions, few need to directly subclass it, but some does for unknown reasonsSo it's about need to declare the exceptions and taking care of proper propagation (on compile only level), unchecked ones are auto-propagated and the developer is not expected to provide handling of unless needed.
Checked ones are generally expected to happen and require extra verbosity in the java, already fluffy code.
Worst practices include:
catch (Throwable t){}
, for many a reason, usually errors shall not be handled unless necessary and most errors usually spell the thread death either ways.简短的回答是一些优点和缺点:这是个人或组织风格的问题。没有一个在功能上比另一个更好。您(或您的项目)必须自行决定是否使用检查异常或非检查异常,或两者都使用。
Oracle 的 Java 教程 建议您对所有错误使用检查异常应用程序可以从错误中恢复,而未经检查的异常则适用于应用程序无法从中恢复的错误。但根据我的经验,大多数应用程序可能会从大多数(可能不是在启动期间)异常中恢复。失败的操作将被中止,但应用程序仍保持活动状态。
我宁愿只使用已检查的异常或未检查的异常。混合可能会导致混乱和使用不一致。务实一点。做对你的情况有意义的事情。
Short answer as some pros and cons have been named: It is a matter of personal or organisational style. None is functionally better than the other. You (or your project) will have to make your own decisions about whether to use checked or unchecked exceptions, or both.
Oracle's Java Tutorial advices you to use checked exceptions for all errors the application can recover from, and unchecked exceptions for the errors the application cannot recover from. But from my experience most applications may recover from most (maybe not during startup) exceptions. The action that failed will be aborted but the application stays alive.
I would rather only use either checked exceptions or unchecked exceptions. Mixing may result in confusion and inconsistent use. Be pragmatic. Do what makes sense in your situation.
切勿显式抛出 RuntimeException。如果您认为需要,那么只需让运行时执行即可,而不是使用
throw
。Never explicitly throw
RuntimeException
s. If you ever think you need to then just let the runtime do it rather than usingthrow
.