我有一个这样的循环:
for (int i = 0; i < max; i++) {
String myString = ...;
float myNum = Float.parseFloat(myString);
myFloats[i] = myNum;
}
这是一个方法的主要内容,该方法的唯一目的是返回浮点数数组。我想让这个方法在出现错误时返回null,所以我把循环放在try…Catch block,像这样:
try {
for (int i = 0; i < max; i++) {
String myString = ...;
float myNum = Float.parseFloat(myString);
myFloats[i] = myNum;
}
} catch (NumberFormatException ex) {
return null;
}
但后来我也想到试一试……Catch块在循环中,像这样:
for (int i = 0; i < max; i++) {
String myString = ...;
try {
float myNum = Float.parseFloat(myString);
} catch (NumberFormatException ex) {
return null;
}
myFloats[i] = myNum;
}
是否有任何理由,性能或其他方面,更喜欢其中一个?
编辑:共识似乎是,将循环放在try/catch中更干净,可能是在它自己的方法中。然而,关于哪个速度更快仍存在争议。有人能测试一下并给出一个统一的答案吗?
我同意所有关于性能和可读性的帖子。然而,在某些情况下,这确实很重要。其他一些人也提到了这一点,但通过例子可能更容易理解。
考虑这个稍微修改过的例子:
public static void main(String[] args) {
String[] myNumberStrings = new String[] {"1.2345", "asdf", "2.3456"};
ArrayList asNumbers = parseAll(myNumberStrings);
}
public static ArrayList parseAll(String[] numberStrings){
ArrayList myFloats = new ArrayList();
for(int i = 0; i < numberStrings.length; i++){
myFloats.add(new Float(numberStrings[i]));
}
return myFloats;
}
如果你想让parseAll()方法在有任何错误时返回null(就像原来的例子一样),你可以把try/catch放在外面,像这样:
public static ArrayList parseAll1(String[] numberStrings){
ArrayList myFloats = new ArrayList();
try{
for(int i = 0; i < numberStrings.length; i++){
myFloats.add(new Float(numberStrings[i]));
}
} catch (NumberFormatException nfe){
//fail on any error
return null;
}
return myFloats;
}
实际上,您可能应该在这里返回一个错误,而不是null,通常我不喜欢有多个返回,但您可以理解。
另一方面,如果你想让它忽略问题,并解析任何它能解析的字符串,你可以把try/catch放在循环的内部,像这样:
public static ArrayList parseAll2(String[] numberStrings){
ArrayList myFloats = new ArrayList();
for(int i = 0; i < numberStrings.length; i++){
try{
myFloats.add(new Float(numberStrings[i]));
} catch (NumberFormatException nfe){
//don't add just this one
}
}
return myFloats;
}
My perspective would be try/catch blocks are necessary to insure proper exception handling, but creating such blocks has performance implications. Since, Loops contain intensive repetitive computations, it is not recommended to put try/catch blocks inside loops. Additionally, it seems where this condition occurs, it is often "Exception" or "RuntimeException" which is caught. RuntimeException being caught in code should be avoided. Again, if if you work in a big company it's essential to log that exception properly, or stop runtime exception to happen. Whole point of this description is PLEASE AVOID USING TRY-CATCH BLOCKS IN LOOPS
性能:就像Jeffrey在他的回复中所说的,在Java中这并没有太大的区别。
通常,为了代码的可读性,在哪里捕获异常的选择取决于您是否希望循环继续处理。
在您的示例中,您在捕获异常时返回。在这种情况下,我会在循环中放入try/catch。如果你只是想捕捉一个坏值,但继续处理,把它放在里面。
第三种方法:您总是可以编写自己的静态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;
}
}
好吧,在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;
}
}
}
我使用javap检查了结果字节码,以确保没有任何内容得到内联。
结果表明,假设JIT优化微不足道,Jeffrey是正确的;在Java 6、Sun客户端VM上绝对没有性能差异(我没有访问其他版本)。整个测试的总时间差在几毫秒的数量级上。
因此,唯一要考虑的是什么看起来最干净。我发现第二种方式很难看,所以我要么坚持第一种方式,要么坚持雷·海耶斯的方式。