Convert.ToInt32 与 TryParse

发布于 2024-07-21 19:01:45 字数 538 浏览 12 评论 0原文

我们都知道大量抛出的异常会对应用程序的性能产生影响,因此,我们应该远离使用异常来控制流之类的事情。 在这句话之后,我必须承认,在编码时我并不太关心这一点。 我主要在 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);< /代码>

谢谢。

We all know the effects that lots of thrown exceptions can have over the performance of our applications, thus, we should stay away from things like using exceptions for control flow.
After this statement I must confess that when coding I didn't care that much about this. I've been working mostly on Java platform but lately I was doing it on .NET platform and just found out this handy method: public static bool TryParse(string s,out int result)
,which allows you to transform a String into int whithout raise an exception. From that moment on, I'm keeping on using it. I just wanted to ask you about your preferences regarding the use of public static bool TryParse(string s,out int result) or public static int ToInt32(string value).

And from the point of view of Java, just pointing that it's missing such a similar method, despite we could get it through things like:

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

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

心安伴我暖 2024-07-28 19:01:45

是的,Java 缺少类似的方法,尽管没有 out 参数,它实际上很难表达(同时想要返回一个原语)。 不过,一般来说,在 C# 中,如果您希望值有时不是整数,则应使用 TryParse,否则应使用 ToInt32; 这样,“特殊”情况就被如此对待。

特别是,如果性能是您想要 TryParse 的主要原因,那么您发布的正则表达式匹配方法要差得多。 异常的性能“消耗”(实际上,非常小)与错误地使用它们会模糊控制流的简单理解相比,显得相形见绌。

Yes, Java is missing a similar method, although without out parameters it's actually pretty difficult to express (while wanting to return a primitive). Generally, though, in C# you should use TryParse if you expect the value to not be an integer sometimes, and ToInt32 otherwise; this way the "exceptional" situation is treated as such.

In particular if performance is your main reason for wanting TryParse, the regex matches method you post is considerably worse. The performance "expense" of Exceptions (which is, in reality, very minimal) is dwarfed by how much using them wrongly can fuzz easy understanding of control flow.

慕巷 2024-07-28 19:01:45

我不了解 C#,但在 Java 中,异常只有在实际抛出时才昂贵,但随后它们确实非常昂贵。 如果您预计很大一部分字符串无效,那么即使您使用正则表达式,也值得您首先验证它们。

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

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

I don't know about C#, but in Java exceptions are only expensive when they're actually thrown, but then they're very expensive indeed. If you expect a significant fraction of the strings to be invalid, it's worth your while to validate them first, even if you use a regex.

But don't use String.matches() or Pattern.matches() to apply the regex; those methods recompile the regex every time you call them. Instead, compile the regex ahead of time and save it as a Pattern object, then do your validating with that. In my tests, parsing a list of 10,000 strings of which 20% were invalid, pre-validating with a Pattern is almost twice as fast as using Integer.parseInt() alone and catching the exceptions.

However, this discussion only applies if you're doing a lot of conversions in a tight loop. If you're only doing them once in a while, like when you accept user input, letting Integer.parseInt() do the validating is fine. And if you do choose to validate with a regex, you'll need a much better regex than ^\d*$ - that regex will match the empty string as well as "numbers" larger than Integer.MAX_VALUE, and it won't match negative numbers at all.

糖粟与秋泊 2024-07-28 19:01:45

为此,在 Java 中,您可以使用众所周知的 StringUtils(在 commons-lang 上),此类有一个方法 isNumeric

也许你可以看看那些人为 该函数

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

我并不是说这是最有效的方法来做到这一点,但还有另一种不使用正则表达式的替代方案。
祝你好运!

For that purpose in Java you can use the well know StringUtils (on the commons-lang), this class have a method isNumeric

Probably you can take a look to the code that those guys have write for 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;
 }

I am not saying that this is the most efficient way to do it, but there is another alternative for you without using regex.
Good luck!

像极了他 2024-07-28 19:01:45

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

And from the point of view of Java,
just pointing that it's missing such a
similar method, despite we could get
it through things like:

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

To predict if Integer.parseInt(myString) would throw an Exception there's more work to do. The String could start with a -. Also an int cannot have more than 10 significant digits. So a more reliable expression would be ^-?0*\d{1,10}$. But even this expression wouldn't predict every Exception because it's still too imprecise.

To generate a reliable regular expression is possible. But it would be very long. It's also possible to implement a method which precisely determines if parseInt would throw an Exception. It could look like this:

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

I don't know which version is more efficient though. And it depends mostly on the context what kind of checks are reasonable.

In C# to check if a string can be converted you would use TryParse. And if it returns true then as a byproduct it got converted at the same time. This is a neat feature and I don't see a problem with just reimplementing parseInt to return null instead of throwing an exception.

But if you don't want to reimplement the parsing method it could still be nice to have a set of methods at hand that you can use depending on the situation. They could look like this:

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;
}
沫尐诺 2024-07-28 19:01:45

我只是想问一下您对使用 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,我根本不用担心这个问题。

I just wanted to ask you about your preferences regarding the use of public static bool TryParse(string s,out int result) or public static int ToInt32(string value).

Yes, I use TryParse except where I expect the value to always be valid. I find that it reads cleaner than using the exceptions. Even if I want an exception, I usually want to customize the message or throw my own custom exception; hence, I use TryParse and manually throw an exception.

In both Java and C#, I try to catch the minimum set of exceptions possible. In Java, that means I have to separately catch NullPointerException and NumberFormatException in response to Number.ValueOf(...); alternatively, I can catch "Exception" and risk catching something unintended. With TryParse in C#, I don't worry about that at all.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文