使用try / catch而不是多个IF语句更好吗?
在Java中使用try/catch
块而不是使用多个If
语句检查用户输入是否更好,更便宜或更易读?
解析Date
字符串时的示例,使用try / catch块直接解析而不是编写查找非法字符的多个语句不是更好。
在另一个例子中,假设我想要读取文件或流,而不是使用Scanner
,我只是强制该方法并等待发生exception。
这是一种健康的编程方法吗? 它在虚拟机上更便宜吗?
UPDATE
这是我在使用DateFormatexception时的意思的一个例子,有时候捕获错误可能是一个真正的问题,这样做,你能保证你的复杂(通常不可读)代码容易出错吗?
将exception用于流控制是一种不好的做法。
一些引用:
由于exception是为在特殊情况下使用而设计的,因此很少有JVM实现尝试优化其性能。 创建,抛出和捕获exception通常很昂贵。
在存在不相关的错误的情况下,这个成语可以无声地失败并掩盖错误,使调试过程变得非常复杂。
更新:据说(我记得我在Josh Bloch的博客中也发现了相同的声明)使用流量控制的exception就像使用GOTO一样。 你可以阅读有趣的Dijkstra文章,了解为什么GOTO是坏的。
一般而言,例外意味着……好的,特殊事件。 If
是针对在正常事件过程中可能发生的事情。
通常情况下,如果您想处理一个没有良好本地解决方案的案例,请使用例外将其向上传播给可以更好地处理它的人。 这比if-else
更加昂贵,这是不滥用它的另一个原因。 第三,恕我直言同样重要的关注点是可读性:在throw
后执行流继续的地方要比阅读一系列if
语句要困难得多。
如果你想在本地处理一个案例,大多数时候最好使用一个简单的if
。
例外情况适用于特殊情况。 使程序逻辑依赖于抛出的exception是一个坏主意。
使用Exception代替If会更昂贵,因为编译器和jvm将有更多的工作和困难来优化这些块的控制流,并且通常例外是exception。
例外情况对性能不利,因为它们是针对特殊情况而设计的,因此有一些权衡可以使非特殊情况更快,但代价是减少exception。 话虽如此,但如果不对特定情况进行基准测试,则无法说明在特定情况下差异是否显着。
但还有另一个更重要的考虑因素:你应该避免重复逻辑。 复制日期解析逻辑以避免exception绝对不是好事。 不幸的是,Java没有.NET框架中的TryParse()
方法,它允许您使用框架的解析逻辑进行健全性测试而无需例外。
在这种情况下,我倾向于使用exception,除非探查器已将其识别为性能瓶颈。 但是对于更简单的测试(空值,文件结尾),我强烈避免使用exception作为if子句的替代。
我认为try catch捕获exception会更加昂贵,而if语句可能看起来更干净。
抛出exception时,消息堆栈将复制到新的Exception对象中,以启用调试和printStackTrace()。 这很贵。
如果您的内容过多,请考虑流量控制模式,例如策略,状态和命令模式。
尝试catch只在抛出exception时很昂贵,我相信这是因为堆栈跟踪创建。 我运行以下基准来validation这一点:
public class TestTryCatchVsIfElseVsNoBlock { private static final int numberOfIteration = 1000000; public static void main(String[] args) { //measureExIfElse for (int i = 0; i < numberOfIteration; i++) { measureIfElse(null); } long start = System.nanoTime(); for (int i = 0; i < numberOfIteration; i++) { measureIfElse(null); } final long ExIfElse = (System.nanoTime() - start); //measureExTryCatch for (int i = 0; i < numberOfIteration; i++) { measureTryCatch(null); } start = System.nanoTime(); for (int i = 0; i < numberOfIteration; i++) { measureTryCatch(null); } final long ExTryCatch = (System.nanoTime() - start); //measureIfElse for (int i = 0; i < numberOfIteration; i++) { measureIfElse("Nitin"); } start = System.nanoTime(); for (int i = 0; i < numberOfIteration; i++) { measureIfElse("Nitin"); } final long IfElse = (System.nanoTime() - start); //measureTryCatch for (int i = 0; i < numberOfIteration; i++) { measureTryCatch("Nitin"); } start = System.nanoTime(); for (int i = 0; i < numberOfIteration; i++) { measureTryCatch("Nitin"); } final long TryCatch = (System.nanoTime() - start); //WithoutAnyBlock for (int i = 0; i < numberOfIteration; i++) { measureWithoutAnyBlock("Nitin"); } start = System.nanoTime(); for (int i = 0; i < numberOfIteration; i++) { measureWithoutAnyBlock("Nitin"); } final long WithoutAnyBlock = (System.nanoTime() - start); System.err.println("ExIfElse: "+ ExIfElse/(float)numberOfIteration); // 3.563198 System.err.println("ExTryCatch: "+ ExTryCatch/(float)numberOfIteration); // 15.924681 System.err.println("IfElse: "+ IfElse/(float)numberOfIteration); // 1.683819 System.err.println("TryCatch: "+ TryCatch/(float)numberOfIteration); // 1.507893 System.err.println("WithoutAnyBlock: "+ WithoutAnyBlock/(float)numberOfIteration); // 1.750418 } private static int i = 0; private static void measureTryCatch(String s) { try { s.length(); } catch (Exception e) { ++i; } } private static void measureWithoutAnyBlock(String s) { s.length(); } private static void measureIfElse(String s) { if(s!=null) { s.length(); } else { ++i; } } }