正则表达式或异常处理?

时间:2011-03-08 02:26:16

标签: java regex

以下哪一项更好的做法是检查字符串是否浮动?

try{
 Double.parseDouble(strVal);
}catch(NumberFormatException e){
 //My Logic
}

if(!strVal.matches("[-+]?\\d*\\.?\\d+")){
 //My Logic
}

在绩效,维护和可读性方面?

是的,我想知道哪一个是好编码练习?

7 个答案:

答案 0 :(得分:4)

  1. 性能:异常很慢,基于异常的逻辑也是如此,所以第二个会更快。
  2. 维护/可靠性:第一个非常清晰,将随着Java Framework的更新而不断更新。
  3. 话虽这么说,我个人更喜欢第一个。性能是您希望在架构,数据结构设计等方面整体考虑的问题,而不是逐行考虑。衡量性能并优化实际上很慢的内容,而不是您认为可能很慢的内容。

答案 1 :(得分:4)

个人意见 - 我见过的代码,我希望大多数开发人员会倾向于尝试 - 捕获块。 try catch在某种意义上也更具可读性,并假设在大多数情况下字符串将包含有效数字。但是你可以考虑一些可能影响你选择的例子。

  1. 您希望字符串多久不包含有效数字。
  2. 请注意,对于批量处理,您应该在循环外部创建Pattern对象。这将阻止代码每次都重新编译模式。
  3. 作为一般规则,您绝不应将期望用作逻辑流程。你的try-catch表示逻辑,如果它不是一个字符串,你的正则表达式表示逻辑,如果它是一个数字。因此,代码的上下文是什么并不明显。
  4. 如果你选择正则表达式技术,你可能仍然需要在某个时候转换,所以实际上,这可能是浪费精力。
  5. 最后,应用程序的性能要求是否足够重要,以保证在此级别进行分析。一般来说,我建议保持尽可能简单,使其工作,然后如果存在性能问题,使用一些代码分析工具找到瓶颈并调整它们。

答案 2 :(得分:2)

当字符串与double匹配时,第一个将比正则表达式更好。例如,当识别器被硬编码时,解析它的速度非常快,就像使用Double.parse一样。此外,没有任何东西可以维护它,无论Java定义什么,因为Double是一个字符串。更不用说Double.parseDouble()更容易阅读。

另一个解决方案不会被编译,所以正则表达式必须要做的第一件事是编译和解析正则表达式,然后它必须运行该表达式,然后你必须执行Double.parseDouble( )把它变成双重的。对于传递给它的每个数字都要做到这一点。您可以使用Pattern.compile()对其进行优化,但执行表达式会变慢。特别是当您必须运行Double.doubleParse以将值转换为double时。

是的异常不是超快,但您只需在解析错误时支付该价格。如果你不打算看到很多错误,那么我不认为你会注意到在抛出时收集堆栈跟踪的速度变慢(这就是为什么异常表现不佳)。如果你只是遇到一些例外,那么性能不会成为问题。问题是你期望一个双倍,它可能不是一些配置错误所以告诉用户并退出,或选择一个合适的默认值并继续。在这些情况下,你就能做到这一切。

答案 3 :(得分:1)

如果您使用parseDouble,您最终会得到Mark所说的内容,但会以更易读的方式,并且可能会从性能改进和错误修复中获益。

由于异常只会在抛出时成本高昂,因此只需要寻找不同的策略

  • 期望错误的格式经常发生
  • 期望它们落入一种特定的模式,你可以更快地捕捉到

最后你也会调用parseDouble,因此可以这样使用它。

请注意,您的模式拒绝7.作为Double,而Java和C / C ++没有,以及像4.2e8这样的科学记数法。

答案 4 :(得分:1)

  

是的,我想知道哪一个是好编码练习?

根据具体情况,两者都可以是良好的编码实践。

  • 如果不太可能出现不好的数字(即这是一种“异常”情况),那么基于异常的解决方案就可以了。 (实际上,如果错误数字的概率足够小,异常甚至可能平均更快。这取决于Double.parseDouble()的相对速度和典型输入字符串的编译正则表达式。这需要进行测量。 。)

  • 如果错误的数字合理(或非常)可能(即它不是“例外”情况),那么基于正则表达式的解决方案可能会更好。

  • 如果执行测试的代码路径不经常执行,那么使用哪种方法确实没有区别。

答案 5 :(得分:1)

也许你也可以尝试这种方式。但这对包含有效数字的字符串来说是通用的。

public static boolean isNumeric(String str) 
{ 
    str = "2.3452342323423424E8";
 //   str = "21414124.12412412412412";
 //   str = "123123";
    NumberFormat formatter = NumberFormat.getInstance(); 
    ParsePosition pos = new ParsePosition(0); 
    formatter.parse(str, pos); 
    return  str.length() == pos.getIndex();  
}

答案 6 :(得分:0)

以下是性能测试,以查看正则表达式VS try catch之间的性能差异,以验证字符串是否为数字。

下表显示了包含三个点(90%,70%,50%)良好数据(浮点值)和剩余不良数据(字符串)的列表(100k)的统计数据。

                      **90% - 10%   70% - 30%   50% - 50%**
**Try Catch**           87234580    122297750   143470144
**Regular Expression**  202700266   192596610   162166308

try catch的性能更好(除非坏数据超过50%),即使try / catch可能会对性能产生一些影响。 try catch的性能影响是因为try / catch阻止JVM进行一些优化。 Joshua Bloch," Effective Java,"说如下: Joshua Bloch," Effective Java,"说了以下几点:

•将代码置于try-catch块中会禁止现有JVM实现可能执行的某些优化。

public class PerformanceStats {
static final String regularExpr = "([0-9]*[.])?[0-9]+";

public static void main(String[] args) {

    PerformanceStats ps = new PerformanceStats();
    ps.statsFinder();
    //System.out.println("123".matches(regularExpr));

}


private void statsFinder() {
    int count =  200000;
    int ncount = 200000;
    ArrayList<String> ar = getList(count, ncount);

    System.out.println("count = " + count + " ncount = " + ncount);

    long t1 = System.nanoTime();
    validateWithCatch(ar);
    long t2 = System.nanoTime();
    validateWithRegularExpression(ar);
    long t3 = System.nanoTime();

    System.out.println("time taken with Exception          " + (t2 - t1) );
    System.out.println("time taken with Regular Expression " + (t3 - t2) );
}


private ArrayList<String> getList(int count, int noiseCount) {
    Random rand = new Random();

    ArrayList<String> list = new ArrayList<String>();
    for (int i = 0; i < count; i++) {
        list.add((String) ("" + Math.abs(rand.nextFloat())));
    }
    // adding noise
    for (int i = 0; i < (noiseCount); i++) {
        list.add((String) ("sdss" + rand.nextInt() ));
    }
    return list;
}



private void validateWithRegularExpression(ArrayList<String> list) {
    ArrayList<Float> ar = new ArrayList<>();
    for (String s : list) {
        if (s.matches(regularExpr)) {
            ar.add(Float.parseFloat(s));
        }
    }
    System.out.println("the size is in regular expression " + ar.size());
}

private void validateWithCatch(ArrayList<String> list) {
    ArrayList<Float> ar = new ArrayList<>();
    for (String s : list) {
        try {
            float e = Float.parseFloat(s);
            ar.add(e);
        } catch (Exception e) {
        }
    }
    System.out.println("the size is in catch block " + ar.size());
}

}