文档章节

Check If a String Is Numeric in Java

Ciet
 Ciet
发布于 01/29 22:45
字数 1617
阅读 202
收藏 0

1. Introduction

Oftentimes while operating upon Strings, we need to figure out whether a String is a valid number or not.

In this tutorial, we’ll explore multiple ways to detect if the given String is numeric, first using plain Java, then regular expressions and finally by using external libraries.

Once we're done discussing various implementations, we'll use benchmarks to get an idea of which methods are optimal.

2. Prerequisites

Let's start with some prerequisites before we head on to the main content.

In the latter part of this article, we'll be using Apache Commons external library for which we'll add its dependency in our pom.xml:

1
2
3
4
5
< dependency >
     < groupId >org.apache.commons</ groupId >
     < artifactId >commons-lang3</ artifactId >
     < version >3.9</ version >
</ dependency >

The latest version of this library can be found on Maven Central.

3. Using Plain Java

Perhaps the easiest and the most reliable way to check whether a String is numeric or not is by parsing it using Java's built-in methods:

  1. Integer.parseInt(String)
  2. Float.parseFloat(String)
  3. Double.parseDouble(String)
  4. Long.parseLong(String)
  5. new BigInteger(String)

If these methods don't throw any NumberFormatException, then it means that the parsing was successful and the String is numeric:

1
2
3
4
5
6
7
8
9
10
11
public static boolean isNumeric(String strNum) {
     if (strNum == null ) {
         return false ;
     }
     try {
         double d = Double.parseDouble(strNum);
     } catch (NumberFormatException nfe) {
         return false ;
     }
     return true ;
}

Let's see this method in action:

1
2
3
4
5
6
7
8
9
assertThat(isNumeric( "22" )).isTrue();
assertThat(isNumeric( "5.05" )).isTrue();
assertThat(isNumeric( "-200" )).isTrue();
assertThat(isNumeric( "10.0d" )).isTrue();
assertThat(isNumeric( "   22   " )).isTrue();
  
assertThat(isNumeric( null )).isFalse();
assertThat(isNumeric( "" )).isFalse();
assertThat(isNumeric( "abc" )).isFalse();

In our isNumeric() method, we're just checking for values that are of type Double, but this method can also be modified to check for Integer, Float, Long and large numbers by using any of the parse methods that we have enlisted earlier.

These methods are also discussed in the Java String Conversions article.

4. Using Regular Expressions

Now let's use regex -?\d+(\.\d+)? to match numeric Strings consisting of the positive or negative integer and floats.

But this goes without saying, that we can definitely modify this regex to identify and handle a wide range of rules. Here, we'll keep it simple.

Let’s break down this regex and see how it works:

  • -? – this part identifies if the given number is negative, the dash “” searches for dash literally and the question mark “?” marks its presence as an optional one
  • \d+ – this searches for one or more digits
  • (\.\d+)? – this part of regex is to identify float numbers. Here we're searching for one or more digits followed by a period. The question mark, in the end, signifies that this complete group is optional

Regular expressions are a very broad topic. To get a brief overview, check our tutorial on the Java regular expressions API.

For now, let's create a method using the above regular expression:

1
2
3
4
5
6
7
8
private Pattern pattern = Pattern.compile( "-?\\d+(\\.\\d+)?" );
 
public boolean isNumeric(String strNum) {
     if (strNum == null ) {
         return false ;
     }
     return pattern.matcher(strNum).matches();
}

Let's now look at some assertions for the above method:

1
2
3
4
5
6
assertThat(isNumeric( "22" )).isTrue();
assertThat(isNumeric( "5.05" )).isTrue();
assertThat(isNumeric( "-200" )).isTrue();
 
assertThat(isNumeric( null )).isFalse();
assertThat(isNumeric( "abc" )).isFalse();

 5. Using Apache Commons

In this section, we'll discuss various methods available in the Apache Commons library.

5.1. NumberUtils.isCreatable(String)

NumberUtils from Apache Commons provides a static method NumberUtils.isCreatable(String) which checks whether a String is a valid Java number or not.

This method accepts:

  1. Hexadecimal numbers starting with 0x or 0X
  2. Octal numbers starting with a leading 0
  3. Scientific notation (for example 1.05e-10)
  4. Numbers marked with a type qualifier (for example 1L or 2.2d)

If the supplied string is null or empty/blank, then it's not considered a number and the method will return false.

Let's run some tests using this method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
assertThat(NumberUtils.isCreatable( "22" )).isTrue();
assertThat(NumberUtils.isCreatable( "5.05" )).isTrue();
assertThat(NumberUtils.isCreatable( "-200" )).isTrue();
assertThat(NumberUtils.isCreatable( "10.0d" )).isTrue();
assertThat(NumberUtils.isCreatable( "1000L" )).isTrue();
assertThat(NumberUtils.isCreatable( "0xFF" )).isTrue();
assertThat(NumberUtils.isCreatable( "07" )).isTrue();
assertThat(NumberUtils.isCreatable( "2.99e+8" )).isTrue();
  
assertThat(NumberUtils.isCreatable( null )).isFalse();
assertThat(NumberUtils.isCreatable( "" )).isFalse();
assertThat(NumberUtils.isCreatable( "abc" )).isFalse();
assertThat(NumberUtils.isCreatable( " 22 " )).isFalse();
assertThat(NumberUtils.isCreatable( "09" )).isFalse();

Note how we're getting true assertions for hexadecimal numbers, octal numbers and scientific notations in lines 6, 7 and 8 respectively.

Also, on line 14, the string “09” returns false because the preceding “0” indicates that this is an octal number and “09” is not a valid octal number.

For every input that returns true with this method, we can use NumberUtils.createNumber(String) which will give us the valid number.

5.2. NumberUtils.isParsable(String)

The NumberUtils.isParsable(String) method checks whether the given String is parsable or not.

Parsable numbers are those that are parsed successfully by any parse method like Integer.parseInt(String), Long.parseLong(String), Float.parseFloat(String) or Double.parseDouble(String).

Unlike NumberUtils.isCreatable(), this method won't accept hexadecimal numbers, scientific notations or strings ending with any type qualifier, that is, ‘f', ‘F', ‘d' ,'D' ,'l'or‘L'.

Let's look at some affirmations:

1
2
3
4
5
6
7
8
9
10
11
12
assertThat(NumberUtils.isParsable( "22" )).isTrue();
assertThat(NumberUtils.isParsable( "-23" )).isTrue();
assertThat(NumberUtils.isParsable( "2.2" )).isTrue();
assertThat(NumberUtils.isParsable( "09" )).isTrue();
 
assertThat(NumberUtils.isParsable( null )).isFalse();
assertThat(NumberUtils.isParsable( "" )).isFalse();
assertThat(NumberUtils.isParsable( "6.2f" )).isFalse();
assertThat(NumberUtils.isParsable( "9.8d" )).isFalse();
assertThat(NumberUtils.isParsable( "22L" )).isFalse();
assertThat(NumberUtils.isParsable( "0xFF" )).isFalse();
assertThat(NumberUtils.isParsable( "2.99e+8" )).isFalse();

On line 4, unlike NumberUtils.isCreatable(), the number starting with string “0” isn't considered as an octal number, but a normal decimal number and hence it returns true.

We can use this method as a replacement for what we did in section 3, where we’re trying to parse a number and checking for an error.

5.3. StringUtils.isNumeric(CharSequence)

The method StringUtils.isNumeric(CharSequence) checks strictly for Unicode digits. This means:

  1. Any digits from any language that is a Unicode digit is acceptable
  2. Since a decimal point is not considered as a Unicode digit, it's not valid
  3. Leading signs (either positive or negative) are also not acceptable

Let's now see this method in action:

1
2
3
4
5
6
7
8
9
10
11
assertThat(StringUtils.isNumeric( "123" )).isTrue();
assertThat(StringUtils.isNumeric( "١٢٣" )).isTrue();
assertThat(StringUtils.isNumeric( "१२३" )).isTrue();
  
assertThat(StringUtils.isNumeric( null )).isFalse();
assertThat(StringUtils.isNumeric( "" )).isFalse();
assertThat(StringUtils.isNumeric( "  " )).isFalse();
assertThat(StringUtils.isNumeric( "12 3" )).isFalse();
assertThat(StringUtils.isNumeric( "ab2c" )).isFalse();
assertThat(StringUtils.isNumeric( "12.3" )).isFalse();
assertThat(StringUtils.isNumeric( "-123" )).isFalse();

Note that the input parameters in lines 2 and 3 are representing numbers 123 in Arabic and Devanagari respectively. Since they're valid Unicode digits, this method returns true on them.

5.4. StringUtils.isNumericSpace(CharSequence)

The StringUtils.isNumericSpace(CharSequence) checks strictly for Unicode digits and/or space. This is same as StringUtils.isNumeric() with the only difference being that it accepts spaces as well, not only leading and trailing spaces but also if they're in between numbers:

1
2
3
4
5
6
7
8
9
10
assertThat(StringUtils.isNumericSpace( "123" )).isTrue();
assertThat(StringUtils.isNumericSpace( "١٢٣" )).isTrue();
assertThat(StringUtils.isNumericSpace( "" )).isTrue();
assertThat(StringUtils.isNumericSpace( "  " )).isTrue();
assertThat(StringUtils.isNumericSpace( "12 3" )).isTrue();
  
assertThat(StringUtils.isNumericSpace( null )).isFalse();
assertThat(StringUtils.isNumericSpace( "ab2c" )).isFalse();
assertThat(StringUtils.isNumericSpace( "12.3" )).isFalse();
assertThat(StringUtils.isNumericSpace( "-123" )).isFalse();

6. Benchmarks

Before we conclude this article, let's go through some benchmark results to help us to analyze which of the above-mentioned methods are best for our use-case.

6.1. Simple Benchmark

First, we take a simple approach. We pick one string value – for our test we use Integer.MAX_VALUE. Then, that value will be tested against all our implementations:

Benchmark                                     Mode  Cnt    Score   Error  Units
Benchmarking.usingCoreJava                    avgt   20   57.241 ± 0.792  ns /op
Benchmarking.usingNumberUtils_isCreatable     avgt   20   26.711 ± 1.110  ns /op
Benchmarking.usingNumberUtils_isParsable      avgt   20   46.577 ± 1.973  ns /op
Benchmarking.usingRegularExpressions          avgt   20  101.580 ± 4.244  ns /op
Benchmarking.usingStringUtils_isNumeric       avgt   20   35.885 ± 1.691  ns /op
Benchmarking.usingStringUtils_isNumericSpace  avgt   20   31.979 ± 1.393  ns /op

As we see, the most costly operations are regular expressions. After that is our core Java-based solution.

Moreover, note that the operations using the Apache Commons library are by-and-large the same.

6.2. Enhanced Benchmark

Let's use a more diverse set of tests, for a more representative benchmark:

  • 95 values are numeric (0-94 and Integer.MAX_VALUE)
  • 3 contain numbers but are still malformatted — ‘x0‘, ‘0..005′, and ‘–11
  • 1 contains only text
  • 1 is a null

Upon executing the same tests, we'll see the results:

Benchmark                                     Mode  Cnt      Score     Error  Units
Benchmarking.usingCoreJava                    avgt   20  10162.872 ± 798.387  ns /op
Benchmarking.usingNumberUtils_isCreatable     avgt   20   1703.243 ± 108.244  ns /op
Benchmarking.usingNumberUtils_isParsable      avgt   20   1589.915 ± 203.052  ns /op
Benchmarking.usingRegularExpressions          avgt   20   7168.761 ± 344.597  ns /op
Benchmarking.usingStringUtils_isNumeric       avgt   20   1071.753 ±   8.657  ns /op
Benchmarking.usingStringUtils_isNumericSpace  avgt   20   1157.722 ±  24.139  ns /op

The most important difference is that two of our tests – the regular expressions solution and the core Java-based solution – have traded places.

From this result, we learn that throwing and handling of the NumberFormatException, which occurs in only 5% of the cases, has a relatively big impact on the overall performance. So, we conclude, that the optimal solution depends on our expected input.

Also, we can safely conclude that we should use the methods from the Commons library or a method implemented similarly for optimal performance.

7. Conclusion

In this article, we explored different ways to find if a String is numeric or not. We looked at both solutions – built-in methods and also external libraries.

As always, the implementation of all examples and code snippets given above including the code used to perform benchmarks can be found over on GitHub.

本文转载自:https://www.baeldung.com/java-check-string-number

Ciet
粉丝 0
博文 68
码字总数 70
作品 0
南京
其他
私信 提问
加载中

评论(0)

commons-lang开源API 收藏

跟java.lang这个包的作用类似,Commons Lang这一组API也是提供一些基础的、通用的操作和处理,如自动生成toString()的结果、自动实现hashCode()和equals()方法、数组操作、枚举、日期和时间的...

李长春
2011/10/17
237
0
jdbc对SqlServer以及java数据类型映射表(很有用的)

数据类型映射 下表列出了基本 SQL Server、JDBC 和 Java 编程语言数据类型之间的默认映射: SQL Server 类型 JDBC 类型 (java.sql.Types) Java 语言类型 bigint BIGINT long timestamp binar...

林家的人
2014/05/19
4K
1
Spring mvc中@RequestMapping 6个基本用法小结

小结下spring mvc中的@RequestMapping的用法。 1)最基本的,方法级别上应用,例如: @RequestMapping(value="/departments") public String simplePattern(){ System.out.println("simpleP......

迷途树袋熊
2013/02/21
356
0
Spring mvc中@RequestMapping 6个基本用法小结

小结下spring mvc中的@RequestMapping的用法。 1)最基本的,方法级别上应用,例如: @RequestMapping(value="/departments") public String simplePattern(){ System.out.println("simpleP......

jackyrong
2013/02/17
3W
2
Spring mvc中@RequestMapping 6个基本用法小结

小结下spring mvc中的@RequestMapping的用法。 1)最基本的,方法级别上应用,例如: Java代码 @RequestMapping(value="/departments") public String simplePattern(){ System.out.println(......

again-Y
2013/06/24
77
0

没有更多内容

加载失败,请刷新页面

加载更多

为容器设置启动时要执行的命令及其入参

本页将展示如何为 Pod 中的容器设置启动时要执行的命令及其入参。 准备开始 创建 Pod 时设置命令及入参 使用环境变量来设置入参 通过 shell 来执行命令 注意 接下来 准备开始 你必须拥有一个...

xiaomin0322
26分钟前
24
0
自动化部署工具syncd

一.部署安装 (一)常用安装方式 1. curl https://syncd.cc/install.sh | bash 2. dockerfile安装方式正在测试中 (二)安装参考文档 1.https://syncd.cc/docs/#/install 2.https://github....

浮世清欢-千帆
32分钟前
30
0
如何学习嵌入式?(网上汇总)

如何学习嵌入式?汇总了网上的一些帖子,最后部分给出了一些资源的下载链接 嵌入式菜鸟学习路线,2019, https://zhuanlan.zhihu.com/p/68227075 嵌入式小白到大神学习全攻略(学习路线+课程...

sentuate
32分钟前
23
0
工欲善其事,必先利其器——DevOps中如何管理工具包

一、背景 作为DevOps交付流水线的开发者,为支持CI/CD中各项任务的自动化,都需要依赖多种包管理工具来下载各种相关的工具,比如针对产生最终交付件的构建过程,就需要在构建流程的第一步,自...

JFrog杰蛙
33分钟前
22
0
深度探索JFR - JFR详细介绍与生产问题定位落地 - 2. 通过一个线上调优例子了解JMC 与 Event 结构与详细配置

查看 JFR 事件的工具 - JMC (Java Mission Control) 官网地址:https://adoptopenjdk.net/jmc.html 国内下载起来比较慢,建议在aws上面建一个欧洲法兰克福的实例,在这个实例上先下载好,然...

zhxhash
34分钟前
26
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部