在Java中哪个更有效:检查错误值以防止异常或让异常发生并捕获它们?
以下是两段示例代码来说明这种差异:
void doSomething(type value1) {
ResultType result = genericError;
if (value1 == badvalue || value1 == badvalue2 || ...) {
result = specificError;
} else {
DoSomeActionThatFailsIfValue1IsBad(value1);
// ...
result = success;
}
callback(result);
}
与
void doSomething(type value1) {
ResultType result = genericError;
try {
DoSomeActionThatFailsIfValue1IsBad(value1);
// ...
result = success;
} catch (ExceptionType e) {
result = specificError;
} finally {
callback(result);
}
}
一方面,你总是在进行比较。另一方面,老实说,我不知道系统的内部做什么来生成异常,抛出它,然后触发catch子句。它有效率较低的声音,但如果它不会增加非错误情况下的开销,那么它的平均效率会更高。这是什么?它是否会添加类似的检查?是否在为异常处理添加的隐式代码中检查,即使有额外的显式检查层?也许它总是取决于异常的类型?我不考虑什么?
让我们假设所有“坏值”都是已知的 - 这是一个明显的问题。如果您不知道所有错误的值 - 或者列表太长且不规则 - 那么异常处理可能是唯一的方法,无论如何。
那么,每种方法的优点和缺点是什么?为什么?
需要考虑的问题:
与SO的相似之处:
this one非常相似,但我没有找到问题的答案。
类似于要列出的太多其他问题,除了:
我不是在问理论最佳实践。我要求更多关于运行时性能和效率(这应该意味着,对于特定情况,有非意见答案),尤其是在资源有限的平台上。例如,如果唯一的错误值只是一个空对象,那么检查它或者只是尝试使用它并捕获异常会更好/更有效吗?
答案 0 :(得分:9)
“如果价值在大多数情况下是”坏“(会抛出异常),你的答案会如何变化?”我认为那是关键。“与比较相比,例外是昂贵的,因此您确实希望使用例外条件的例外。
同样,关于这个答案如何根据语言/环境而变化的问题与此相关:异常的费用在不同的环境中是不同的。例如,.Net 1.1和2.0在第一次抛出异常时令人难以置信地慢。
答案 1 :(得分:6)
纯粹从效率的角度来看,并且考虑到您的代码示例,我认为这取决于您期望看到错误值的频率。如果不好的值不太常见,那么进行比较会更快,因为异常是昂贵的。但是,如果错误值很少,则使用异常可能会更快。
但最重要的是,如果您正在寻找性能,请分析您的代码。这段代码甚至可能不是一个问题。如果是,那么尝试两种方式,看看哪个更快。同样,这取决于您期望看到不良价值的频率。
答案 2 :(得分:3)
我很难找到关于抛出异常的成本的当前信息。很明显,必须有一些,你正在创建一个对象,并可能获得堆栈跟踪信息。
在具体的例子中,你谈到:
if (value1 == badvalue || value1 == badvalue2 || ...) {
result = specificError;
} else {
DoSomeActionThatFailsIfValue1IsBad(value1);
// ...
result = success;
}
这里的问题是,如果(可能不完全)复制调用者中应该由您正在调用的方法拥有的逻辑,那么您就处于危险之中。
因此我不会执行这些检查。您的代码没有执行实验,它确实“知道”它应该发送的数据我猜想?因此,抛出异常的可能性应该很低。因此,保持简单,让被叫方进行检查。
答案 3 :(得分:2)
在我看来,如果只是为了拥有一个安全的运行系统,你应该在可能引发异常的任何东西周围尝试/捕获块。如果您检查可能的数据错误,则可以更好地控制错误响应。所以我建议两者兼顾。
答案 4 :(得分:2)
嗯,例外是更昂贵的,是的,但对我来说,它是关于加重效率与糟糕设计的成本。除非您的用例需要它,否则始终坚持最佳设计。
问题是,你何时抛出异常?在特殊情况下。
如果您的参数不在您要查找的范围内,我建议您返回错误代码或布尔值。
例如,一个方法,
public int IsAuthenticated(String username, String password)
{
if(!Validated(username,password)
{
// just an error
// log it
return -2;
}
// contacting the Database here
if cannot connect to db
{
// woww this is HUUGE
throw new DBException('cannot connect'); // or something like that
}
// validate against db here
if validated, return 0;
// etc etc
}
那是我的2美分
答案 5 :(得分:1)
我个人的观点是异常表明某些东西被破坏了 - 这可能是一个被非法参数调用的API,或者被零除或未找到文件等。这意味着可以通过检查值来抛出异常。
对于你的代码的读者 - 再次是我的个人意见 - 如果你可以确定它不会被各种奇怪的抛出(如果用作伪装,它本质上是伪装的程序流程的一部分)。你只需要考虑一下。
这在我看来是件好事。 “智能”代码很难包裹。
另一方面 - JVM变得更加智能 - 效率编码通常无法获得回报。
答案 6 :(得分:1)
通常,人们会认为try-catch更昂贵,因为它在代码中看起来更重,但这完全取决于JIT。我的猜测是,如果没有真实案例和一些性能测量,就无法分辨。比较可能会更昂贵,例如,当您有许多值时,或者因为equals()
因为==
而无法在多数情况下无法工作,因此需要调用{{1}}。
至于应该选择哪一个(如“代码样式”),我的答案是:确保用户在失败时收到有用的错误消息。其他任何事情都是品味问题,我不能给你规则。
答案 7 :(得分:1)
为安全起见,假设例外情况很昂贵。他们经常是,如果他们不是,它至少会促使你明智地使用例外。 (输入一个try块通常很便宜,因为实现者尽力做到这一点,即使以使异常更加昂贵为代价。毕竟,如果正确使用异常,代码将经常多次进入try块它会抛出。)
更重要的是,例外是一种风格问题。异常条件的例外使代码更简单,因为错误检查代码更少,因此实际功能更清晰,更紧凑。
但是,如果在更正常的情况下可能会抛出异常,那么读者必须记住无形的控制流,与Intercal的COME FROM...UNLESS...
语句相比。 (Intercal是最早的笑话语言之一。)这非常令人困惑,很容易导致误读和误解代码。
我的建议,适用于我所知道的每种语言和环境:
这里不要担心效率。除了效率之外,有充分的理由以一种证明有效的方式使用异常。
自由使用try块。
对特殊情况使用例外。如果可能发生异常,请对其进行测试并以其他方式处理。
答案 8 :(得分:1)
这样的问题就像问,
“使用所有抽象函数编写接口或基类是否更有效”
哪个更有效率是否重要?对于特定情况,只有其中一种是正确的方法
答案 9 :(得分:0)
请注意,如果您的代码没有抛出异常,那么它并不总是暗示输入在边界内。依赖标准Java(API + JVM)抛出异常,例如NullPointerException
或ArrayIndexOutOfBoundsExceptions
是一种非常不健康的验证输入的方法。 Garbage-in 有时会生成垃圾 - 但不会例外。
是的,例外情况非常昂贵。在正常的处理流程中不应抛出它们。
答案 10 :(得分:0)
在优化方面,我认为你会发现它可能是一种清洗。他们都表现得很好,我不认为例外投掷会成为你的瓶颈。您应该更关心Java的设计目标(以及其他Java程序员所期望的)以及抛出的异常。 Java是围绕抛出/捕获异常而设计的,你可以打赌设计师使这个过程尽可能高效。
我认为这主要是哲学和语言文化。在Java中,普遍接受的做法是方法签名是方法和调用它的代码之间的契约。因此,如果您收到一个不正确的值,通常会抛出一个未经检查的异常并让它在更高级别处理:
public void setAge(int age)
{
if(age < 0)
{
throw new IllegalArgumentException("Array can't be negative");
}
this.age = age;
}
在这种情况下,调用者打破了他们的合同结束,所以你将他们的输入吐回到他们身边,但有一个例外。当您由于某种原因无法履行合同时,“投掷”条款将被使用。
public void readFile(String filename) throws IOException
{
File myfile = new File(filename);
FileInputStream fis = new FileInputStream(myfile);
//do stuff
fis.read();
//do more stuff
}
在这种情况下,作为方法编写者,您已经打破了合同的结束,因为用户提供了有效的输入,但由于IOException,您无法完成他们的请求。
希望有点让你走上正轨。祝你好运!