AIによる要約
NumberFormatExceptionは、文字列が対象の数値型として解釈できない場合に発生します。空文字、空白、3桁カンマ、全角数字、小数点、単位付き、int範囲外など原因は複数です。例外をcatchして0へ変換すると未入力や不正値を隠します。入力仕様を決め、文字列段階の形式チェック、必要な正規化、適切な数値型への変換、利用者向けエラーの返却を境界で行います。


画面入力、CSV、環境変数、外部APIは、数値に見えるデータも最初は文字列です。Integer.parseIntへ渡すだけで変換できますが、入力形式が1文字でも違えばNumberFormatExceptionになります。
よくある修正はtry-catchして0を返すことですが、未入力、形式不正、値0を同じにしてしまいます。どの文字列を許可し、どのエラーとして返すかを入力境界で決めます。
この記事のポイント
- 空文字や空白はparseIntできない
- カンマ・全角数字・単位付きはそのまま変換できない
- int範囲外でもNumberFormatExceptionになる
- 不正値を0へ置き換えて隠さない
- 画面・CSV・APIごとに入力契約とエラーを決める
NumberFormatExceptionが起きる基本例
Integer.parseIntは、符号付き10進整数として正しい文字列を受け取ります。空文字、空白だけ、小数、英字を含む値は変換できません。
Integer.parseInt(""); // 例外
Integer.parseInt(" "); // 例外
Integer.parseInt("12.5"); // 例外
Integer.parseInt("12個"); // 例外
Integer.parseInt("123"); // 123例外メッセージに入力値が表示されることがあります。本番ログへ個人情報や秘密値を出さないよう、記録方法にも注意します。
空文字と空白を先に扱う
任意入力なら、未入力をnullとして扱うのか既定値にするのかを決めてから変換します。必須入力なら、数値変換より前に必須エラーとして返す方が利用者へ伝わります。
Integer parseOptionalInt(String value) {
if (value == null || value.isBlank()) {
return null;
}
return Integer.valueOf(value.strip());
}戻り値nullをServiceへ広げると別のNPEを生むことがあります。Formでは文字列、変換後DTOではIntegerなど、境界と内部型を分ける設計も検討します。
カンマ付き数値をどう扱うか
1,234はInteger.parseIntでは変換できません。カンマ入力を許可する仕様なら、単純にreplaceする前に形式が正しいか確認します。12,34まで1234として通すのは望ましくありません。
NumberFormat format = NumberFormat.getIntegerInstance(Locale.JAPAN);
format.setParseIntegerOnly(true);
Number number = format.parse("1,234");
System.out.println(number.intValue()); // 1234NumberFormatは途中まで解析して残りを無視する場合があるため、ParsePositionで文字列全体を消費したか確認するなど厳密な検証が必要です。金額入力用の共通部品があればそれを使います。
全角数字とUnicode正規化
日本語入力では123が来ることがあります。全角を半角へ変換して受け付けるか、形式エラーにするかは画面仕様です。無条件にすべてNFKC正規化すると、記号や単位まで変わる可能性があります。
String normalized = Normalizer.normalize(
input, Normalizer.Form.NFKC);
int value = Integer.parseInt(normalized);正規化対象を数値入力欄に限定し、元の入力と変換後を混同しません。監査要件がある場合は原文を保持する必要もあります。
桁あふれでもNumberFormatException
文字がすべて数字でも、intの範囲を超えると変換できません。IDや金額が将来大きくなる場合、型選択を確認します。
Integer.parseInt("2147483647"); // 最大値
Integer.parseInt("2147483648"); // NumberFormatException
long id = Long.parseLong("2147483648");longでも足りない整数、または桁数を失いたくないコード値ならBigIntegerやStringを検討します。電話番号、郵便番号、商品コードは計算しないため、数字だけでも数値型が適切とは限りません。
小数と金額は適切な型へ変換する
小数をIntegerへ変換するのではなく、用途に合う型を使います。金額や率ではBigDecimalを文字列から作ると、double経由の誤差を避けられます。
BigDecimal amount = new BigDecimal("1234.50");
// 避けたい例
BigDecimal inaccurate = new BigDecimal(0.1);BigDecimalでもカンマや通貨記号はそのまま受け付けません。入力フォーマットの解析と、内部の数値表現を分けます。
例外を業務エラーへ変換する
低レベルのNumberFormatExceptionをそのまま500エラーにせず、入力境界で項目エラーへ変換します。すべてのExceptionをcatchせず、対象を限定します。
try {
return Integer.valueOf(value);
} catch (NumberFormatException e) {
throw new InvalidInputException(
"quantity", "数量は整数で入力してください", e);
}画面FormならBean Validationの@Patternや型変換エラー、REST APIなら400レスポンスのフィールドエラーへ統一します。スタックトレースを利用者へ返さないでください。
JUnitで不正パターンを並べる
正常値だけでなく、null、空、前後空白、カンマ、全角、小数、負数、最大値超過をパラメータ化します。許可する形式だけを明示します。
@ParameterizedTest
@ValueSource(strings = {"", " ", "1,000", "123", "1.5", "2147483648"})
void 不正な整数を拒否する(String input) {
assertThrows(InvalidInputException.class,
() -> parser.parseQuantity(input));
}現場レビューでよくある指摘
数値変換のレビューではcatchの有無ではなく、入力形式、正規化、型の範囲、不正時の利用者向けエラーが一貫しているかを見ます。
// レビューコメント例
NumberFormatExceptionをcatchして0にすると、不正入力と数量0を区別できません。
項目エラーとして返してください。
// レビューコメント例
カンマをreplaceするだけでは12,34も通ります。
許可する形式を定義し、文字列全体を検証してください。
// レビューコメント例
この値は商品コードで計算しません。先頭0も必要なので、
IntegerではなくStringのまま扱う方が契約に合います。表示上数字に見えるかではなく、実際の文字列、許可形式、内部型を確認します。不正値を既定値へ落とす場合は、仕様として明記されていることが必要です。
提出前のセルフチェック
レビュー前に確認すること
- null・空文字・空白の扱いを決めたか
- カンマや全角数字を許可するか
- 正規化が他の文字を変えないか
- 小数を整数型へ入れようとしていないか
- intやlongの範囲を超えないか
- コード値を数値型にする必要があるか
- 不正値を0で隠していないか
- 項目エラーとして利用者へ返せるか
Javaの型と例外を基本から確認する参考書
文字列、数値型、例外処理を一緒に整理すると、変換失敗をcatchで隠さず、入力境界で正しく扱えるようになります。
スッキリわかるJava入門 第5版
Java文法とオブジェクト指向を、最初から整理する一冊。
豊富な図とサンプルで、変数、条件分岐、クラス、例外処理まで順番に学べます。Javaの最初の教科書を探している人向けです。
- Javaを基礎から体系的に学びたい
- Java 25 LTS対応の入門書を選びたい
当サイトはAmazonアソシエイト・プログラムの参加者です。価格・在庫・配送条件はAmazonでご確認ください。
この記事とあわせて読みたい
まとめ
NumberFormatExceptionは、空文字、空白、カンマ、全角、小数、単位付き、型の範囲外など、対象の数値型として解釈できない文字列で発生します。
例外をcatchして0へ置き換えず、許可形式、正規化、内部型、不正時のエラーを入力境界で決めます。正常値と不正パターンをテストし、コード値と計算値も区別してください。
