Java 如何检查字符串是否表示数字以及表示数字的类型?

Java 如何检查字符串是否表示数字以及表示数字的类型?,java,optimization,casting,numbers,Java,Optimization,Casting,Numbers,如何检查字符串是表示长字符串、双精度字符串还是仅表示常规字符串?我需要这样做,因为这个值需要根据其类型在数据库中建立索引。目前,我正在尝试解析字符串并检查异常,但由于代码调用非常频繁,我想知道是否有更有效的方法来执行此操作。我的代码当前如下所示: String value = ...; // For example, could be "213678", "654.1236781", or "qwerty12345" try { Long longValue = Long.parseL

如何检查字符串是表示长字符串、双精度字符串还是仅表示常规字符串?我需要这样做,因为这个值需要根据其类型在数据库中建立索引。目前,我正在尝试解析字符串并检查异常,但由于代码调用非常频繁,我想知道是否有更有效的方法来执行此操作。我的代码当前如下所示:

String value = ...;
// For example, could be "213678", "654.1236781", or "qwerty12345"

try {
    Long longValue = Long.parseLong(value);
    // Index 'longValue' in the database
} catch (NumberFormatException parseLongException) {
    try {
        Double doubleValue = Double.parseDouble(value);
        // Index 'doubleValue' in the database
    } catch (NumberFormatException parseDoubleException) {
        // Index 'value' in the database
    }
}
编辑:

我只是按照@user949300的建议做了一个快速的基准测试,使用regex模式,它的性能比上面的异常处理代码略好。以下是代码,以防其他人发现它有用:

Pattern longPattern = Pattern.compile("^[-+]?[0-9]+$");
Pattern doublePattern = Pattern.compile("^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$");

// Check for long regex pattern before the double regex pattern
// since the former is a strict subset of the latter
if (longPattern.matcher(value).matches()) {
    // Perform indexing for long in the database
} else if (doublePattern.matcher(value).matches()) {
    // Perform indexing for double in the database
} else {
    // Perform indexing for string in the database
}
以下是检查50000个条目的基准测试结果,其中类型的大致细分为50%长、10%双、40%字符串(代表我的应用程序处理的工作负载):


就我所知,除了这个,没有其他优雅的方式。我建议您按照从最常见到最不常见的顺序解析它们,以便尽可能快地完成这项工作


如果你有超过3种可能的类型,你将会有一个深而难看的
try-catch
nest,但从技术上讲,它会比你将每次解析尝试分解成自己的方法更快;这里的权衡是您想要代码清晰还是执行速度更快——听起来您可能想要后者

通过检查非数字以检测长字符,您可能会得到一些改进(特别是如果您可以排除科学符号,例如
1e12

Long.parseLong()
委托给一个通用的方法,该方法可以在任何基数下工作,因此只有十进制的方法可能会快一点

不要忘记负号,如果这些在你的数据中是可能的

双精度更难,因为
654.1236871
有效,但
654.12.36.87…1
无效,尽管它们包含相同的字符集。因此,可能需要进行完整的解析。

您的代码看起来不错

做一些分析,如果基于它你发现你的代码太慢,那么你可以考虑潜在的优化(比如简单的循环看看是否所有字符都是数字)


在评测之前不要尝试优化代码。特别是在java等语言中。

您考虑过正则表达式吗

如果字符串包含除-(开头)和0-9或之外的任何内容,则它是一个字符串。(注意——这忽略了国际化和科学符号——它们是问题吗?)

否则,它包含一个。它是一个双精度。(好吧,你应该只测试一次,但这只是一个开始)

否则,这是一个漫长的过程

出于偏执,我仍然可能检查异常,但这可能是一种更快的方法


注意:我猜想测试正则表达式比从各种解析例程中抛出异常要快,但这可能不是真的。您应该做一些测试。

一种可能是java.io.StreamTokenizer:

Reader r = new StringReader(value);
StreamTokenizer st = new StreamTokenizer(r);
int tokenType = st.nextToken();
double number;
String word;
switch (tokenType) {
    case StreamTokenizer.TT_NUMBER: // it's a number
         number = st.nval; break;
    case StreamTokenizer.TT_WORD: // it's a string
         word = st.sval; break;
}

但是使用起来可能有点棘手。

如果您不需要担心
long
是负数,您可以使用Apache Commons Lang库中的
NumberUtils.isDigits()和
NumberUtils.isNumber()

if(NumberUtils.isDidgets(string)){
    //Index long
} else if(NumberUtils.isNumber(string)){
    //Index double
} else {
    //Index string
}

如果您使用的是
java7
,那么请看一下@RanRag,我看不出多catch块在这种情况下有多大帮助。第二个catch在第一个catch块的内部,而不是之后。你是对的,我没有看到这一点。@Dawood如果大多数字符串都是以字母开头的,那么首先对第一个字符做一个快速而肮脏的测试,你可能会获得更快的速度,例如string.charAt(0)>='a'。假设ASCII。如果我理解正确,那么按照出现频率的顺序进行解析将不起作用,因为字符串表示将是Double的严格超集,而Double又将是Long的严格超集。如果一个值应该是长的,它仍然会成功地解析为double,而不会引发异常。@Dawood:你说得对。我的观点是,应该考虑解析的顺序,以便(希望)避免一些工作。我的印象是,正则表达式会比较慢,但只是做了一个快速的基准测试,使用正则表达式模式匹配多倍和双倍,结果稍微快一点。我已将此代码与基准测试结果一起添加到我的问题中。
if(NumberUtils.isDidgets(string)){
    //Index long
} else if(NumberUtils.isNumber(string)){
    //Index double
} else {
    //Index string
}