有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java是一种过度使用异常处理的程序模型,在速度方面是否有效?

虽然这个问题是一般性的,但我要提到引发质疑的场景

场景

我对分析大量字符串(尤其是数字字符串)感兴趣。因此,我的第一项工作是过滤掉那些甚至只包含一个字符而不是数字的字符

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

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

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

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


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


共 (4) 个答案

  1. # 1 楼答案

    在应用程序的更大上下文中,这可能没有多大关系。像这样的微观优化很难猜测

    一种更好的方法是尽可能干净地编写代码,然后测量代码的性能以及瓶颈(如果有的话)所在的位置。如果你发现你的表现不可接受,找出最大的瓶颈,并尽可能解决它;冲洗并重复,直到性能合格

    问题是,我们中没有人足够聪明,能够“知道”问题出在哪里。您最好使用数据进行优化,而不是猜测

    在您的情况下,这是一个未经检查的异常。你可以忽略它,但这意味着一个坏的字符串会把你吹出循环。将catch放在循环中允许您容忍一小部分数字解析失败的输入字符串并继续

  2. # 2 楼答案

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

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

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

  3. # 3 楼答案

    这里的操作本质上是正确的,因为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
    }
    

    在我看来,使用这种方法将是一种典型的过早优化,导致代码的可维护性降低

  4. # 4 楼答案

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

    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);
            }
        }
    }
    

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

    正则表达式也不是最快的

    两种方法都试一下,看看哪一种更适合你