检查字符串是否可以解析为Long而不使用try-catch?

Ser*_*erg 60 java string parsing try-catch

Long.parseLong("string")如果字符串无法解析为long,则抛出错误.有没有办法比使用更快地验证字符串try-catch?谢谢

Rom*_*man 48

您可以创建相当复杂的正则表达式,但这不值得.在这里使用例外是绝对正常的.

这是很自然的特殊情况:你假设字符串中有一个整数,但确实还有其他东西.应抛出异常并妥善处理.

如果您查看parseLong代码内部,您将看到有许多不同的验证和操作.如果你想在解析它之前做所有这些事情会降低性能(如果我们谈论解析数百万个数字,因为否则无关紧要).因此,如果您真的需要通过避免异常来提高性能,那么您唯一能做的就是:将parseLong实现复制到您自己的函数并返回NaN,而不是在所有相应的情况下抛出异常.

  • @罗马:还有很多通常毫无意义和不必要的事情,例如使用除10以外的基数,并解析非ASCII的数字。这就是为什么您可以重写比默认Long.parseLong更快的parseBase10AsciiDigitsLong(...)的原因。但是我敢肯定,Java之神的每一个脑力劳动都无法讨论... (2认同)

lex*_*ore 28

来自commons-lang StringUtils:

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 伙计们/加尔斯 - 如果有的话?!!!! 来吧 .为什么在`for`循环中调用`if`条件的另一个方法比`try {Long.parseLong(string)} catch(异常e){}更快"" - 我认为这个问题以及这个答案值得投票.不要*过度工程* (13认同)
  • 哦伙计们,一切都怎么样?该方法给出了一个基本线索,还是不够? (9认同)
  • 那些负面因素和Long的限制之外的价值观呢? (8认同)
  • @ring bearer:Long.parseLong()也支持非十进制基数.因此,我最终将会更简单,更快捷.但是我同意在这里完全可以捕获异常.只是试图回答原始问题而不是改变它 - 只是为了好玩.PS.当然没有冒犯.我很抱歉,如果我的话似乎可以假设那样. (3认同)
  • @lexicore:别担心,你不是唯一一个......只是因为在SO上真的有很多奇怪的"程序员"都参与了某种"集体思考":freethought在这里不受欢迎.除了默认库之外,不要暗示其他东西,因为这些程序员一直使用这些默认库.他们不能写*他们,所以他们为他们辩护.你可以在很多问题上看到这种模式,所以它甚至都不好笑.从现在开始,我将这些"程序员"称为*"default-API-kneejerkers"*;) (2认同)

rin*_*rer 10

你可以做点什么

if(s.matches("\\d*")){
}
Run Code Online (Sandbox Code Playgroud)

使用正则表达式 - 检查String s是否已满数字.但是你有什么收获的呢?另一个条件?

  • 负数又如何呢?或非常大的数字无法容纳很长的内容 (2认同)

Woo*_*ody 6

这是一个有效的问题,因为有时您需要推断字符串中表示的数据类型.例如,您可能需要将大型CSV导入数据库并准确表示数据类型.在这种情况下,调用Long.parseLong并捕获异常可能会太慢.

以下代码仅处理ASCII十进制:

public class LongParser {
    // Since tryParseLong represents the value as negative during processing, we
    // counter-intuitively want to keep the sign if the result is negative and
    // negate it if it is positive.
    private static final int MULTIPLIER_FOR_NEGATIVE_RESULT = 1;
    private static final int MULTIPLIER_FOR_POSITIVE_RESULT = -1;

    private static final int FIRST_CHARACTER_POSITION = 0;
    private static final int SECOND_CHARACTER_POSITION = 1;
    private static final char NEGATIVE_SIGN_CHARACTER = '-';
    private static final char POSITIVE_SIGN_CHARACTER = '+';
    private static final int DIGIT_MAX_VALUE = 9;
    private static final int DIGIT_MIN_VALUE = 0;
    private static final char ZERO_CHARACTER = '0';
    private static final int RADIX = 10;

    /**
     * Parses a string representation of a long significantly faster than
     * <code>Long.ParseLong</code>, and avoids the noteworthy overhead of
     * throwing an exception on failure. Based on the parseInt code from
     * http://nadeausoftware.com/articles/2009/08/java_tip_how_parse_integers_quickly
     *
     * @param stringToParse
     *            The string to try to parse as a <code>long</code>.
     *
     * @return the boxed <code>long</code> value if the string was a valid
     *         representation of a long; otherwise <code>null</code>.
     */
    public static Long tryParseLong(final String stringToParse) {
        if (stringToParse == null || stringToParse.isEmpty()) {
            return null;
        }

        final int inputStringLength = stringToParse.length();
        long value = 0;

        /*
         * The absolute value of Long.MIN_VALUE is greater than the absolute
         * value of Long.MAX_VALUE, so during processing we'll use a negative
         * value, then we'll multiply it by signMultiplier before returning it.
         * This allows us to avoid a conditional add/subtract inside the loop.
         */

        int signMultiplier = MULTIPLIER_FOR_POSITIVE_RESULT;

        // Get the first character.
        char firstCharacter = stringToParse.charAt(FIRST_CHARACTER_POSITION);

        if (firstCharacter == NEGATIVE_SIGN_CHARACTER) {
            // The first character is a negative sign.
            if (inputStringLength == 1) {
                // There are no digits.
                // The string is not a valid representation of a long value.
                return null;
            }

            signMultiplier = MULTIPLIER_FOR_NEGATIVE_RESULT;
        } else if (firstCharacter == POSITIVE_SIGN_CHARACTER) {
            // The first character is a positive sign.
            if (inputStringLength == 1) {
                // There are no digits.
                // The string is not a valid representation of a long value.
                return null;
            }
        } else {
            // Store the (negative) digit (although we aren't sure yet if it's
            // actually a digit).
            value = -(firstCharacter - ZERO_CHARACTER);
            if (value > DIGIT_MIN_VALUE || value < -DIGIT_MAX_VALUE) {
                // The first character is not a digit (or a negative sign).
                // The string is not a valid representation of a long value.
                return null;
            }
        }

        // Establish the "maximum" value (actually minimum since we're working
        // with negatives).
        final long rangeLimit = (signMultiplier == MULTIPLIER_FOR_POSITIVE_RESULT)
            ? -Long.MAX_VALUE
            : Long.MIN_VALUE;

        // Capture the maximum value that we can multiply by the radix without
        // overflowing.
        final long maxLongNegatedPriorToMultiplyingByRadix = rangeLimit / RADIX;

        for (int currentCharacterPosition = SECOND_CHARACTER_POSITION;
            currentCharacterPosition < inputStringLength;
            currentCharacterPosition++) {
            // Get the current digit (although we aren't sure yet if it's
            // actually a digit).
            long digit = stringToParse.charAt(currentCharacterPosition)
                    - ZERO_CHARACTER;

            if (digit < DIGIT_MIN_VALUE || digit > DIGIT_MAX_VALUE) {
                // The current character is not a digit.
                // The string is not a valid representation of a long value.
                return null;
            }

            if (value < maxLongNegatedPriorToMultiplyingByRadix) {
                // The value will be out of range if we multiply by the radix.
                // The string is not a valid representation of a long value.
                return null;
            }

            // Multiply by the radix to slide all the previously parsed digits.
            value *= RADIX;

            if (value < (rangeLimit + digit)) {
                // The value would be out of range if we "added" the current
                // digit.
                return null;
            }

            // "Add" the digit to the value.
            value -= digit;
        }

        // Return the value (adjusting the sign if needed).
        return value * signMultiplier;
    }
}
Run Code Online (Sandbox Code Playgroud)


pol*_*nts 5

您可以使用 java.util.Scanner

Scanner sc = new Scanner(s);
if (sc.hasNextLong()) {
   long num = sc.nextLong();
}
Run Code Online (Sandbox Code Playgroud)

这也做范围检查等.当然会说"99 bottles of beer" hasNextLong(),所以如果你想确保它只有一个long你必须做额外的检查.


And*_*man 5

org.apache.commons.lang3.math.NumberUtils.isParsable(yourString)将确定该字符串是否可以由以下之一解析:Integer.parseInt(String),Long.parseLong(String),Float.parseFloat(String)或Double .parseDouble(String)

由于您对Longs感兴趣,因此您可能需要检查isParsable且不包含小数的条件

if (NumberUtils.isParsable(yourString) && !StringUtils.contains(yourString,".")){ ...
Run Code Online (Sandbox Code Playgroud)