こんにちはJavaプログラマなうの村上です。
今回は数値変換時の型チェックに関する記事です。
以前数値 ⇔ 文字列変換で文字列を数値変換する時は
1 2 3 |
Integer.parseInt(s); new Integer(s).intValue(); Integer.valueOf(s).intValue(); |
とかで数値変換するようなコードを書いてましたが、だいたい数値変換する時は数値変換可能かのバリデーションをするのがお行儀が良いです。
なので、今回は数値変換時のバリデーションについて
型チェックの方法は色々あるとおもいますが、次の3つで検証してみました。
- Integer#parseInt()時の例外チェック
12345678public boolean isNumber(String val) {try {Integer.parseInt(val);return true;} catch (NumberFormatException nfex) {return false;}} - 正規表現チェック
123456public boolean isNumber(String val) {String regex = "\\A[-]?[0-9]+\\z";Pattern p = Pattern.compile(regex);Matcher m1 = p.matcher(val);return m1.find();} - commons-langのNumberUtils#isNumber()
123public boolean isNumber(String val) {return NumberUtils.isNumber(val);}
(注意)
- 今回は整数時のチェックのみということにしています。
- 正規表現のチェックの実際のコードはPatternオブジェクトをインスタンス変数にしてオブジェクト生成のコストを下げています。
100万回のループですべてtrueを返すもの場合(文字列の1とか)とすべてfalseを返す場合(文字列のaとか)で調査しました。
以下結果です。単位はミリ秒です。
Java5 | Java6 | Java7 | ||
---|---|---|---|---|
Integer#parseInt() | すべてtrue | 292 | 218 | 183 |
すべてfalse | 1739 | 1329 | 1051 | |
正規表現チェック | すべてtrue | 532 | 455 | 291 |
すべてfalse | 515 | 455 | 273 | |
NumberUtils#isNumber() | すべてtrue | 212 | 180 | 159 |
すべてfalse | 212 | 187 | 128 |
Integer#parseInt()はtrueを返す場合とfalseを返す場合でずいぶんと差がでますね。
エラー時は例外クラスを生成してスローするので遅くなりそうな感じがしますね。
正規表現チェックとNumberUtils#isNumber()はどちらも安定していますね。
ただ今回は整数に限ってなのでご注意を!!
ちなみに次の文字列でそれぞれが返す値は以下の通りです。
ケース | Integer#parseInt() | 正規表現チェック | NumberUtils#isNumber() |
---|---|---|---|
1 | true | true | true |
123 | true | true | true |
a | false | false | false |
0 | true | true | true |
-100 | true | true | true |
10-10 | false | false | false |
+100 | true | false | false |
10+10 | false | false | false |
+ | false | false | false |
- | false | false | false |
1.0 | false | false | true |
1.1 | false | false | true |
1,000 | false | false | false |
12345678901234567890 | false | true | true |
0x123 | false | false | true |
123L | false | false | true |
123D | false | false | true |
12e3 | false | false | true |
※ 網掛け部分を追記(2014年5月22日)
今回は整数のみということなので、16進数、long型、小数点などの表記方法では結果が異なります。
開発時には注意を!!!
Comments
3の例は1と2とは同じ結果を返しません
System.out.println(NumberUtils.isNumber("0x123"));
System.out.println(NumberUtils.isNumber("123L"));
System.out.println(NumberUtils.isNumber("123D"));
System.out.println(NumberUtils.isNumber("12e3"));
ご指摘ありがとうございます。
今回のエントリーは整数に限定させております。
良いご指摘でしたので、一覧に追加させて頂きました!!
isNumberに"08000"を渡したらfalseになりました。なぜなのでしょう?
ご質問ありがとうございます。
「0」から始まる場合は8進数として解釈され、8進数として正しくないのでfalseが返ります。