この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:4
ページ更新者:T
更新日時:2026-06-11 07:07:02

タイトル: 文字列の数字チェック
SEOタイトル: Java で文字列が数字か判定する方法完全ガイド — 4 つの実装と性能比較

この記事の要点
  • 最も簡潔なのは str.matches("\d+") だが正規表現コンパイルが毎回走るため高速ではない
  • commons-lang3 の StringUtils.isNumeric() は null/空文字を false で安全に処理。char ループで高速
  • 小数や符号付きを許可するなら NumberUtils.isCreatable() または try-catch で Integer.parseInt
  • 自前実装は Character.isDigit() ループが最速だが Unicode 数字 (全角・アラビア文字数字等) も true になる点に注意
  • パフォーマンス順: char ループ > StringUtils.isNumeric > try-catch >> String.matches

結論: ケース別おすすめ実装

要件おすすめ実装
半角数字のみ判定StringUtils.isNumeric(s) (commons-lang3)
負数・小数も許可NumberUtils.isCreatable(s)
整数化して使うtry-catch で Integer.parseInt(s)
ライブラリ無しで実装Character.isDigit() ループまたは正規表現
大規模数値new BigDecimal(s) を try-catch

方法 1: String.matches() で正規表現

public static boolean isDigitOnly(String s) {
    return s != null && s.matches("\\d+");
}

// 符号付き整数
public static boolean isInteger(String s) {
    return s != null && s.matches("-?\\d+");
}

// 小数
public static boolean isDecimal(String s) {
    return s != null && s.matches("-?\\d+(\\.\\d+)?");
}

欠点: 呼ぶたびに Pattern.compile() が走る。ループ内で頻繁に呼ぶと遅い。改善するなら Pattern を static final にキャッシュ:

private static final Pattern DIGITS = Pattern.compile("\\d+");

public static boolean isDigitOnly(String s) {
    return s != null && DIGITS.matcher(s).matches();
}

方法 2: StringUtils.isNumeric (commons-lang3)

import org.apache.commons.lang3.StringUtils;

StringUtils.isNumeric(null);     // false
StringUtils.isNumeric("");       // false (Lang 3.5+ は false)
StringUtils.isNumeric("  ");     // false
StringUtils.isNumeric("123");    // true
StringUtils.isNumeric("12.3");   // false (ピリオド NG)
StringUtils.isNumeric("-123");   // false (符号 NG)
StringUtils.isNumeric("123"); // false (全角は NG、Character.isDigit() とは違う)
StringUtils.isNumeric("12 3");   // false

内部実装は Character.isDigit() を文字ごとに呼ぶだけのシンプルなループ。正規表現より高速です。

方法 3: NumberUtils.isCreatable (commons-lang3)

「Java の数値リテラルとして解釈可能か」を判定。符号・小数・16 進・指数表記・型サフィックスまで対応:

import org.apache.commons.lang3.math.NumberUtils;

NumberUtils.isCreatable("123");      // true
NumberUtils.isCreatable("-123");     // true
NumberUtils.isCreatable("1.23");     // true
NumberUtils.isCreatable("1.23e5");   // true
NumberUtils.isCreatable("0x1A");     // true (16 進)
NumberUtils.isCreatable("123L");     // true (long サフィックス)
NumberUtils.isCreatable("1.23f");    // true (float サフィックス)
NumberUtils.isCreatable("abc");      // false
NumberUtils.isCreatable("");         // false
NumberUtils.isCreatable(null);       // false

旧名 isNumber() は deprecated。新規コードは isCreatable を使う

方法 4: try-catch で Integer.parseInt

判定後に数値として使うなら、try-catch で直接パースする方がコードが綺麗:

public static Integer tryParseInt(String s) {
    if (s == null) return null;
    try {
        return Integer.parseInt(s);
    } catch (NumberFormatException e) {
        return null;
    }
}

// Java 8+ Optional 版
public static OptionalInt parseInt(String s) {
    if (s == null) return OptionalInt.empty();
    try {
        return OptionalInt.of(Integer.parseInt(s));
    } catch (NumberFormatException e) {
        return OptionalInt.empty();
    }
}

欠点: 例外コストが大きい。「数字でない確率が高い」入力では遅くなる。例外スローのスタックトレース生成が重い。

方法 5: Character.isDigit() で自前ループ

public static boolean isDigitOnly(String s) {
    if (s == null || s.isEmpty()) return false;
    for (int i = 0; i < s.length(); i++) {
        if (!Character.isDigit(s.charAt(i))) return false;
    }
    return true;
}

最速。ただし Character.isDigit('1') (全角 1) や Character.isDigit('٥') (アラビア数字 5) は true を返すため、ASCII 限定なら以下:

public static boolean isAsciiDigitOnly(String s) {
    if (s == null || s.isEmpty()) return false;
    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        if (c < '0' || c > '9') return false;
    }
    return true;
}

方法 6: BigDecimal で精度を保つ

金額計算など precision が重要な場合は BigDecimal を使う:

public static boolean isDecimalSafe(String s) {
    if (s == null || s.isEmpty()) return false;
    try {
        new BigDecimal(s);
        return true;
    } catch (NumberFormatException e) {
        return false;
    }
}

// double は浮動小数点誤差があるため業務系では避ける
// new BigDecimal("123.456") → 正確
// Double.parseDouble("123.456") → 123.45600000000000307...

性能比較

1 万回呼び出しのおおよその目安 (環境依存):

実装相対速度備考
char ループ (ASCII 比較)★★★★★ (最速)分岐 1 つだけ
Character.isDigit() ループ★★★★☆Unicode 判定の分やや遅い
StringUtils.isNumeric()★★★★☆上と同等
Pattern キャッシュ + matches★★★☆☆正規表現エンジンのオーバーヘッド
try-catch Integer.parseInt (成功時)★★★☆☆例外なしなら早い
try-catch Integer.parseInt (失敗時)★☆☆☆☆例外スローで激遅
String.matches() (キャッシュなし)★★☆☆☆毎回 compile

null / 空文字の扱い

仕様によって null や空文字 ("") を「数字 OK」にするか「NG」にするか分岐します。多くの場合 NG が安全:

// 安全側 (null/空 → false)
public static boolean isDigit(String s) {
    return s != null && !s.isEmpty() && s.chars().allMatch(Character::isDigit);
}

// Java 11+ String.isBlank() で空白文字も除外
public static boolean isDigitStrict(String s) {
    return s != null && !s.isBlank() && s.chars().allMatch(Character::isDigit);
}

負数・小数を許容する判定の細部

// 整数 (符号付き)
"-?\\d+"

// 小数 (符号付き、小数部任意)
"-?\\d+(\\.\\d+)?"

// 指数表記対応 (1.23e5 / -1.5E-3)
"-?\\d+(\\.\\d+)?([eE][+-]?\\d+)?"

// 千の区切り対応 (1,234,567)
"-?\\d{1,3}(,\\d{3})*(\\.\\d+)?"

FAQ

Q: 全角数字 (123) を許容したい
A: Character.isDigit() は全角もアラビア数字も true。完全に全角を許可するなら Normalizer.normalize(s, Form.NFKC) で半角化してから判定。

Q: scientific notation (1.5e+10) を判定したい
A: NumberUtils.isCreatable() がそのまま使える。または Double.parseDouble() を try-catch。

Q: Long の範囲を超える数字を判定したい
A: new BigInteger(s) を try-catch。あるいは StringUtils.isNumeric() + 桁数チェック。

Q: 先頭ゼロ (007) はどう扱う?
A: StringUtils.isNumeric("007") は true。Integer.parseInt("007") は 7 として成功。8 進数解釈はしない。

関連項目

  • commons-lang3 StringUtils / NumberUtils
  • Integer.parseInt / Long.parseLong / BigDecimal
  • Java Regex Pattern キャッシュ
  • Normalizer (全角半角統一)