Convert.ToInt32与TryParse

时间:2009-05-27 10:37:18

标签: c# java performance exception tryparse

我们都知道许多抛出的异常可能对我们的应用程序的性能产生的影响,因此,我们应该远离诸如使用控制流的异常之类的东西。 在这个声明之后我必须承认,在编码时我并不在乎这个问题。我一直在Java平台上工作,但最近我在.NET平台上做了这个,并且发现了这个方便的方法:public static bool TryParse(string s,out int result) ,它允许您将String转换为int而不引发异常。从那一刻起,我就继续使用它。我只是想问你关于使用public static bool TryParse(string s,out int result)public static int ToInt32(string value)的偏好。

从Java的角度来看,只是指出它缺少这样一种类似的方法,尽管我们可以通过以下方式得到它:

boolean isInteger = Pattern.matches("^\d*$", myString);

感谢。

5 个答案:

答案 0 :(得分:7)

是的,Java缺少类似的方法,虽然没有out参数,但实际上很难表达(虽然想要返回原语)。但是,一般情况下,在C#中,如果期望值有时不是整数,则应使用TryParse,否则为ToInt32;这样,“特殊”情况就这样对待了。

特别是如果性能是你想要TryParse的主要原因,你发布的正则表达式匹配方法要差得多。 Exceptions的性能“花费”(实际上是非常小的)与使用它们错误地使用多少可以模糊控制流的简单理解相形见绌。

答案 1 :(得分:3)

我不知道C#,但是在Java中,异常只是在它们被实际抛出时才很昂贵,但实际上它们非常昂贵。如果您希望相当一部分字符串无效,那么即使您使用正则表达式,也值得您首先验证它们。

但请勿使用String.matches()Pattern.matches()来应用正则表达式;这些方法每次调用时都会重新编译正则表达式。相反,提前编译正则表达式并将其保存为Pattern对象,然后使用它进行验证。在我的测试中,解析10,000个字符串的列表,其中20%是无效的,使用模式进行预验证几乎是单独使用Integer.parseInt()并捕获异常的两倍。

但是,此讨论仅适用于您在紧密循环中进行大量转换的情况。如果你只是偶尔做一次,比如当你接受用户输入时,让Integer.parseInt()进行验证就可以了。如果您选择使用正则表达式进行验证,则需要比^\d*$更好的正则表达式 - 正则表达式将匹配空字符串以及大于Integer.MAX_VALUE的“数字”,并且它赢了根本不匹配负数。

答案 2 :(得分:1)

为了达到Java目的,你可以使用众所周知的StringUtils(在commons-lang上),这个类有一个方法isNumeric

您可以查看这些人为that function撰写的代码:

public static boolean isNumeric(String str) {
  if (str == null) {
    return false;
  }
  int sz = str.length();
  for (int i = 0; i < sz; i++) {
    if (Character.isDigit(str.charAt(i)) == false) {
      return false;
    }
  }
  return true;
 }

我并不是说这是最有效的方法,但是如果不使用正则表达式,还有另一种选择。 祝你好运!

答案 3 :(得分:1)

  

从Java的角度来看,   只是指出它缺少这样的   类似的方法,尽管我们可以得到   通过以下方式:

boolean isInteger = Pattern.matches("^\d*$", myString);

要预测Integer.parseInt(myString)是否会引发异常,还有更多工作要做。字符串可以以-开头。 int也不能超过10位有效数字。所以更可靠的表达式是^-?0*\d{1,10}$。但即使这个表达也不能预测每一个例外,因为它仍然太不精确。

可以生成可靠的正则表达式。但它会很长。也可以实现一个精确确定parseInt是否会抛出异常的方法。 可以看起来像这样:

static boolean wouldParseIntThrowException(String s) {
    if (s == null || s.length() == 0) {
        return true;
    }

    char[] max = Integer.toString(Integer.MAX_VALUE).toCharArray();
    int i = 0, j = 0, len = s.length();
    boolean maybeOutOfBounds = true;

    if (s.charAt(0) == '-') {
        if (len == 1) {
            return true; // s == "-"
        }
        i = 1;
        max[max.length - 1]++; // 2147483647 -> 2147483648
    }
    while (i < len && s.charAt(i) == '0') {
        i++;
    }
    if (max.length < len - i) {
        return true; // too long / out of bounds
    } else if (len - i < max.length) {
        maybeOutOfBounds = false;
    }
    while (i < len) {
        char digit = s.charAt(i++);
        if (digit < '0' || '9' < digit) {
            return true;
        } else if (maybeOutOfBounds) {
            char maxdigit = max[j++];
            if (maxdigit < digit) {
                return true; // out of bounds
            } else if (digit < maxdigit) {
                maybeOutOfBounds = false;
            }
        }
    }
    return false;
}

我不知道哪个版本效率更高。这主要取决于上下文哪种检查是合理的。

在C#中检查如果可以转换字符串,则使用TryParse。如果它返回true,那么作为副产品,得到同时转换。这是一个很好的功能,我没有看到重新实现parseInt返回null而不是抛出异常的问题。

但是如果你不想重新实现解析方法,那么根据具体情况可以使用一套可以使用的方法仍然很好。他们可以看起来像这样:

private static Pattern QUITE_ACCURATE_INT_PATTERN = Pattern.compile("^-?0*\\d{1,10}$");

static Integer tryParseIntegerWhichProbablyResultsInOverflow(String s) {
    Integer result = null;
    if (!wouldParseIntThrowException(s)) {
        try {
            result = Integer.parseInt(s);
        } catch (NumberFormatException ignored) {
            // never happens
        }
    }
    return result;
}

static Integer tryParseIntegerWhichIsMostLikelyNotEvenNumeric(String s) {
    Integer result = null;
    if (s != null && s.length() > 0 && QUITE_ACCURATE_INT_PATTERN.matcher(s).find()) {
        try {
            result = Integer.parseInt(s);
        } catch (NumberFormatException ignored) {
        // only happens if the number is too big
        }
    }
    return result;
}

static Integer tryParseInteger(String s) {
    Integer result = null;
    if (s != null && s.length() > 0) {
        try {
            result = Integer.parseInt(s);
        } catch (NumberFormatException ignored) {
        }
    }
    return result;
}

static Integer tryParseIntegerWithoutAnyChecks(String s) {
    try {
        return Integer.parseInt(s);
    } catch (NumberFormatException ignored) {
    }
    return null;
}

答案 4 :(得分:0)

  

我只是想问你关于使用public static bool TryParse(string s,out int result)或public static int ToInt32(string value)的偏好。

是的,我使用TryParse,除非我希望始终的值有效。我发现它比使用异常更干净。即使我想要一个例外,我通常也想自定义消息或抛出我自己的自定义异常;因此,我使用TryParse并手动抛出异常。

在Java和C#中,我尝试捕获可能的最小异常集。在Java中,这意味着我必须单独捕获NullPointerException和NumberFormatException以响应Number.ValueOf(...);或者,我可以捕捉到“异常”并冒着无意识捕捉的风险。使用C#中的TryParse,我根本不担心。