Java 应该 try...catch 进入循环内部还是外部?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/141560/
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
Should try...catch go inside or outside a loop?
提问by Michael Myers
I have a loop that looks something like this:
我有一个看起来像这样的循环:
for (int i = 0; i < max; i++) {
String myString = ...;
float myNum = Float.parseFloat(myString);
myFloats[i] = myNum;
}
This is the main content of a method whose sole purpose is to return the array of floats. I want this method to return null
if there is an error, so I put the loop inside a try...catch
block, like this:
这是一个方法的主要内容,其唯一目的是返回浮点数数组。null
如果出现错误,我希望此方法返回,因此我将循环放入一个try...catch
块中,如下所示:
try {
for (int i = 0; i < max; i++) {
String myString = ...;
float myNum = Float.parseFloat(myString);
myFloats[i] = myNum;
}
} catch (NumberFormatException ex) {
return null;
}
But then I also thought of putting the try...catch
block inside the loop, like this:
但后来我也想把try...catch
块放在循环中,像这样:
for (int i = 0; i < max; i++) {
String myString = ...;
try {
float myNum = Float.parseFloat(myString);
} catch (NumberFormatException ex) {
return null;
}
myFloats[i] = myNum;
}
Is there any reason, performance or otherwise, to prefer one over the other?
是否有任何理由,性能或其他原因,更喜欢一个?
Edit:The consensus seems to be that it is cleaner to put the loop inside the try/catch, possibly inside its own method. However, there is still debate on which is faster. Can someone test this and come back with a unified answer?
编辑:共识似乎是将循环放在 try/catch 中更干净,可能放在它自己的方法中。但是,对于哪个更快,仍然存在争议。有人可以对此进行测试并得出统一的答案吗?
采纳答案by Michael Myers
All right, after Jeffrey L Whitledge saidthat there was no performance difference (as of 1997), I went and tested it. I ran this small benchmark:
好吧,在Jeffrey L Whitledge 说没有性能差异(截至 1997 年)之后,我去测试了它。我运行了这个小基准:
public class Main {
private static final int NUM_TESTS = 100;
private static int ITERATIONS = 1000000;
// time counters
private static long inTime = 0L;
private static long aroundTime = 0L;
public static void main(String[] args) {
for (int i = 0; i < NUM_TESTS; i++) {
test();
ITERATIONS += 1; // so the tests don't always return the same number
}
System.out.println("Inside loop: " + (inTime/1000000.0) + " ms.");
System.out.println("Around loop: " + (aroundTime/1000000.0) + " ms.");
}
public static void test() {
aroundTime += testAround();
inTime += testIn();
}
public static long testIn() {
long start = System.nanoTime();
Integer i = tryInLoop();
long ret = System.nanoTime() - start;
System.out.println(i); // don't optimize it away
return ret;
}
public static long testAround() {
long start = System.nanoTime();
Integer i = tryAroundLoop();
long ret = System.nanoTime() - start;
System.out.println(i); // don't optimize it away
return ret;
}
public static Integer tryInLoop() {
int count = 0;
for (int i = 0; i < ITERATIONS; i++) {
try {
count = Integer.parseInt(Integer.toString(count)) + 1;
} catch (NumberFormatException ex) {
return null;
}
}
return count;
}
public static Integer tryAroundLoop() {
int count = 0;
try {
for (int i = 0; i < ITERATIONS; i++) {
count = Integer.parseInt(Integer.toString(count)) + 1;
}
return count;
} catch (NumberFormatException ex) {
return null;
}
}
}
I checked the resulting bytecode using javap to make sure that nothing got inlined.
我使用 javap 检查了生成的字节码,以确保没有内联任何内容。
The results showed that, assuming insignificant JIT optimizations, Jeffrey is correct; there is absolutely no performance difference on Java 6, Sun client VM(I did not have access to other versions). The total time difference is on the order of a few milliseconds over the entire test.
结果表明,假设 JIT 优化不重要,Jeffrey 是正确的;在 Java 6、Sun 客户端 VM 上绝对没有性能差异(我无法访问其他版本)。在整个测试中,总时间差约为几毫秒。
Therefore, the only consideration is what looks cleanest. I find that the second way is ugly, so I will stick to either the first way or Ray Hayes's way.
因此,唯一的考虑是看起来最干净的东西。我发现第二种方式很难看,所以我会坚持第一种方式或Ray Hayes 的方式。
回答by Jamie
In your examples there is no functional difference. I find your first example more readable.
在您的示例中,没有功能差异。我发现你的第一个例子更具可读性。
回答by Ray Hayes
Performance: as Jeffreysaid in his reply, in Java it doesn't make much difference.
性能:正如Jeffrey在他的回复中所说,在 Java 中它没有太大区别。
Generally, for readability of the code, your choice of where to catch the exception depends upon whether you want the loop to keep processing or not.
通常,为了代码的可读性,您选择在哪里捕获异常取决于您是否希望循环继续处理。
In your example you returned upon catching an exception. In that case, I'd put the try/catch around the loop. If you simply want to catch a bad value but carry on processing, put it inside.
在您的示例中,您在捕获异常时返回。在这种情况下,我会将 try/catch 放在循环中。如果你只是想捕捉一个坏的值但继续处理,把它放在里面。
The third way: You could always write your own static ParseFloat method and have the exception handling dealt with in that method rather than your loop. Making the exception handling isolated to the loop itself!
第三种方式:您始终可以编写自己的静态 ParseFloat 方法,并在该方法而不是您的循环中处理异常处理。使异常处理与循环本身隔离!
class Parsing
{
public static Float MyParseFloat(string inputValue)
{
try
{
return Float.parseFloat(inputValue);
}
catch ( NumberFormatException e )
{
return null;
}
}
// .... your code
for(int i = 0; i < max; i++)
{
String myString = ...;
Float myNum = Parsing.MyParseFloat(myString);
if ( myNum == null ) return;
myFloats[i] = (float) myNum;
}
}
回答by Orion Adrian
You should prefer the outer version over the inner version. This is just a specific version of the rule, move anything outside the loop that you can move outside the loop. Depending on the IL compiler and JIT compiler your two versions may or may not end up with different performance characteristics.
您应该更喜欢外部版本而不是内部版本。这只是规则的一个特定版本,将任何可以移动到循环外的东西移到循环之外。根据 IL 编译器和 JIT 编译器,您的两个版本可能会或可能不会具有不同的性能特征。
On another note you should probably look at float.TryParse or Convert.ToFloat.
另一方面,您可能应该查看 float.TryParse 或 Convert.ToFloat。
回答by Stephen Wrighton
If it's inside, then you'll gain the overhead of the try/catch structure N times, as opposed to just the once on the outside.
如果它在内部,那么您将获得 N 次 try/catch 结构的开销,而不仅仅是一次在外部。
Every time a Try/Catch structure is called it adds overhead to the execution of the method. Just the little bit of memory & processor ticks needed to deal with the structure. If you're running a loop 100 times, and for hypothetical sake, let's say the cost is 1 tick per try/catch call, then having the Try/Catch inside the loop costs you 100 ticks, as opposed to only 1 tick if it's outside of the loop.
每次调用 Try/Catch 结构时,都会为方法的执行增加开销。只是处理结构所需的一点内存和处理器滴答声。如果您运行一个循环 100 次,并且为了假设,假设每次 try/catch 调用的成本是 1 个滴答,那么在循环中使用 Try/Catch 将花费您 100 个滴答,而如果它是,则只有 1 个滴答在循环之外。
回答by Joel Coehoorn
If you put the try/catch inside the loop, you'll keep looping after an exception. If you put it outside the loop you'll stop as soon as an exception is thrown.
如果你把 try/catch 放在循环中,你会在异常之后继续循环。如果你把它放在循环之外,你会在抛出异常时立即停止。
回答by Joe Skora
If its an all-or-nothing fail, then the first format makes sense. If you want to be able to process/return all the non-failing elements, you need to use the second form. Those would be my basic criteria for choosing between the methods. Personally, if it is all-or-nothing, I wouldn't use the second form.
如果它的全有或全无失败,那么第一种格式是有意义的。如果您希望能够处理/返回所有非失败元素,则需要使用第二种形式。这些将是我在这些方法之间进行选择的基本标准。就个人而言,如果是全有或全无,我不会使用第二种形式。
回答by Matt
setting up a special stack frame for the try/catch adds additional overhead, but the JVM may be able to detect the fact that you're returning and optimize this away.
为 try/catch 设置一个特殊的堆栈帧会增加额外的开销,但 JVM 可能能够检测到您正在返回的事实并对其进行优化。
depending on the number of iterations, performance difference will likely be negligible.
根据迭代次数,性能差异可能可以忽略不计。
However i agree with the others that having it outside the loop make the loop body look cleaner.
但是我同意其他人的看法,将它放在循环之外会使循环体看起来更干净。
If there's a chance that you'll ever want to continue on with the processing rather than exit if there an invalid number, then you would want the code to be inside the loop.
如果您有可能希望继续处理而不是在存在无效数字时退出,那么您会希望代码位于循环内。
回答by Jeffrey L Whitledge
PERFORMANCE:
表现:
There is absolutely no performance difference in where the try/catch structures are placed. Internally, they are implemented as a code-range table in a structure that is created when the method is called. While the method is executing, the try/catch structures are completely out of the picture unless a throw occurs, then the location of the error is compared against the table.
放置 try/catch 结构的位置绝对没有性能差异。在内部,它们作为代码范围表在调用方法时创建的结构中实现。当方法正在执行时,除非发生抛出异常,否则 try/catch 结构完全不在画面中,然后将错误的位置与表进行比较。
Here's a reference: http://www.javaworld.com/javaworld/jw-01-1997/jw-01-hood.html
这是一个参考:http: //www.javaworld.com/javaworld/jw-01-1997/jw-01-hood.html
The table is described about half-way down.
该表描述了大约一半。
回答by wnoise
The whole point of exceptions is to encourage the first style: letting the error handling be consolidated and handled once, not immediately at every possible error site.
异常的全部意义在于鼓励第一种风格:让错误处理被合并和处理一次,而不是立即在每个可能的错误位置。