程序模型是否在速度方面过度使用异常处理?

时间:2012-06-15 15:30:57

标签: java exception-handling

虽然问题是通用的,但我会提到引发查询的情景。

方案

我有兴趣分析大量字符串(特别是数字字符串)。因此,我的第一份工作是过滤那些甚至包含除数字之外的单个字符的工作。

一种简单的方法是(在Java中):

for (String val : stringArray){
   try{
     int num = Integer.parseInt(val);
     doSomething(num);
   }
   catch(NumberFormatException nfe){}
}

我必须提到的另一点是,数组中只有大约5%的字符串是纯数字的。因此,简而言之,将涉及大量的捕捉。

我想知道的是,这是否是设计方面的有效方式,还是我应该考虑其他方法来做同样的事情?


基于答案的结论:例外确实很昂贵,将它们用作控制语句的形式并不是一个很好的设计实践。 因此,人们应该尽可能地寻找替代方案,如果仍然有例外情况似乎更清楚/更容易,那么应该记录下来。

4 个答案:

答案 0 :(得分:2)

你在这里做的本质上是正确的,因为在java中没有其他标准方法可以检查字符串是否为数字。

如果a profiling证明此操作太长,您可以尝试自己执行in the parseInt method,但JVM将无法执行相同的优化,因此我不建议它。您将看到JVM经过大量优化以处理异常,并且它可以很好地完成这项工作。

作为好奇心,这里有几种方法可以在java中实现:

http://rosettacode.org/wiki/Determine_if_a_string_is_numeric#Java

指向其他语言的链接,但您的解决方案是标准的和惯用的解决方案,我怀疑您会通过重写它来找到重大差异,如示例所示:

private static final boolean isNumeric(final String s) {
  if (s == null || s.isEmpty()) return false;
  for (int x = 0; x < s.length(); x++) {
    final char c = s.charAt(x);
    if (x == 0 && (c == '-')) continue;  // negative
    if ((c >= '0') && (c <= '9')) continue;  // 0 - 9
    return false; // invalid
  }
  return true; // valid
}

在我看来,使用它可能是过早优化的典型案例,导致代码维护较少。

答案 1 :(得分:1)

效率不高。 您可以在网上查找大量资源,了解为什么抛出异常被认为是昂贵的,例如:http://www.yoda.arachsys.com/csharp/exceptions.html

不幸的是,Java并没有提供这样的实用方法OOTB(比如C#的tryParse)。您可以枚举字符串的字符并使用Character.isDigit方法(您甚至可以将验证和转换交织成int)。

异常应该用于某些流程的异常终止。 执行可能引发异常的操作时,应始终考虑是否可以执行检查以节省成本,尤其是处理异常的代码。例如,检查一个字符串是否是一个数字而不是试图解析它并依赖异常机制告诉你它是否不是。

答案 2 :(得分:0)

在您的应用程序的更大范围内,这不太重要。像这样的微观优化很难猜到。

更好的方法是尽可能干净地编写代码,然后进行测量以查看其性能是什么以及瓶颈(如果有)存在于何处。如果您发现您的表现不可接受,请找出最大的瓶颈,并在可能的情况下解决;冲洗并重复,直至表现可以接受。

问题在于,我们都不够聪明,无法“知道”问题所在。你最好不要用数据进行优化而不是猜测。

在您的情况下,这是一个未经检查的例外。你可以忽略它,但这意味着一个坏的字符串会让你无法摆脱循环。将catch放在循环中允许您容忍那些未通过数值解析并继续的输入字符串的小百分比。

答案 3 :(得分:0)

检查仅数字字符串的基于非异常的方法是使用正则表达式。例如:

public static void main(String[] args) throws Exception {
    String[] array = {
            "abc",
            "123",
            "12A",
    };
    Pattern p = Pattern.compile("\\d*");
    for (String s: array) {
        Matcher m = p.matcher(s);
        if (m.matches()) {
            System.out.println(s);
        }
    }
}

基于异常的处理可能很昂贵。

正则表达式也不是最快的。

尝试两者,看看哪个更快。