TL;DRInteger.parseInt()(またはそれに類するメソッド)を、有効な数値でない文字列に対して呼び出しています。空文字列、単語、"1,000"のような値、余分なスペースも含め、すべてこのエラーを引き起こします。try-catchで囲むか、事前にバリデーションを行いましょう。
// 簡単な修正 — try-catchで囲む
try {
int value = Integer.parseInt(input);
} catch (NumberFormatException e) {
System.err.println("Invalid number: " + input);
// デフォルト値の処理、エラーの返却など
}
このエラーが発生する原因スタックトレースの全体は次のようになります:
Exception in thread "main" java.lang.NumberFormatException: For input string: "abc"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:668)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at com.example.Main.main(Main.java:8)
Javaのパースメソッドは厳格です。数字のみを受け付け、先頭に-または+を任意で付けられます。それだけです。それ以外はすべてNumberFormatExceptionをスローします。最もよくある原因:
- バリデーションされていないユーザー入力(
"abc"、""、null)- 桁区切り文字付きの数値:"1,000"- 単位が付いた数値:"42px"、"5MB"-parseIntに渡された浮動小数点数文字列:"3.14"- 先頭または末尾に空白がある文字列:" 7 "- CSVやJSON、またはデータベースのカラムから読み取った値がnullまたは不正な形式だった場合## 修正方法### 1. try-catch(最も一般的)これが基本的な解決策です。不正な値と値なしを区別する必要がある場合や、問題を起こした文字列をログに記録したい場合に使用します。
public static Integer safeParseInt(String s) {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
return null; // またはデフォルト値(0など)
}
}
// 使用例
Integer age = safeParseInt(request.getParameter("age"));
if (age == null) {
throw new IllegalArgumentException("age must be a number");
}
2. パース前に空白を除去する余分なスペースはこのエラーの最も気づきにくい原因の一つです。特にファイルやフォームフィールドから読み取った値に多く見られます。.trim()を一度呼び出すだけで解決することが多いです。
int value = Integer.parseInt(input.trim());
3. 事前に正規表現でバリデーションする不正な入力を最初の段階で拒否します。このアプローチにより、スタックトレースに埋もれた不可解な例外ではなく、明確で早期のエラーメッセージが得られます。
if (!input.matches("-?\\d+")) {
throw new IllegalArgumentException("Expected an integer, got: " + input);
}
int value = Integer.parseInt(input);
4. ロケール形式の数値を処理する(1,000 / 1.000)parseIntはロケールの概念を持っていません。"1,234,567"は常に失敗します。特定の地域向けにフォーマットされた数値を読み取る際はNumberFormatに切り替えましょう。
import java.text.NumberFormat;
import java.util.Locale;
String formatted = "1,234,567";
NumberFormat nf = NumberFormat.getInstance(Locale.US);
long value = nf.parse(formatted).longValue(); // 1234567
5. 整数に見せかけた小数をパースする"3.14"を受け取ったが普通のintが必要な場合は、まずdoubleとしてパースしてからキャストします。結果は3になります。小数部分は切り捨てられ、四捨五入はされません。
String s = "3.14";
int value = (int) Double.parseDouble(s); // 3
6. Apache Commons Lang(オプションのユーティリティ)Commons Langをすでに使用していますか?NumberUtilsはnull、空文字列、不正な入力をスローせずに処理します。try-catchの定型コードは不要です。
import org.apache.commons.lang3.math.NumberUtils;
int value = NumberUtils.toInt("abc", 0); // 0を返す(デフォルト値)
boolean valid = NumberUtils.isCreatable("123"); // true
7. Java 8+ Optionalパターン関数型パイプラインが好みですか?スローしたりnullを返したりする代わりにOptionalIntを返しましょう。値が存在しないことが明示的になり、コードに潜むサイレントなデフォルト値がなくなります。
import java.util.OptionalInt;
public static OptionalInt tryParseInt(String s) {
if (s == null || s.isBlank()) return OptionalInt.empty();
try {
return OptionalInt.of(Integer.parseInt(s.trim()));
} catch (NumberFormatException e) {
return OptionalInt.empty();
}
}
// 使用例
tryParseInt(input).ifPresentOrElse(
val -> System.out.println("Parsed: " + val),
() -> System.out.println("Not a valid integer")
);
注意すべきエッジケース- null入力 — Integer.parseInt(null)はNPEではなくNumberFormatExceptionをスローします。意外ですが、これが事実です。パースを呼び出す前に必ずnullチェックを行いましょう。- 整数オーバーフロー — "99999999999"はInteger.MAX_VALUE(2,147,483,647)を超えるためスローされます。大きな値にはLong.parseLong()またはnew BigInteger(s)を使用してください。- 16進数文字列 — "0xFF"は普通のparseIntでは失敗します。Integer.parseInt(s.substring(2), 16)またはよりシンプルなInteger.decode("0xFF")を使用してください。- 指数表記 — "1e5"は有効な整数文字列ではありません。まずDoubleとしてパースしてからキャストしてください。## 修正の確認パースユーティリティに対してこれらのアサーションを実行してください。厄介なエッジケースがすべてカバーされています。すべての行が通れば、リリース可能です。
// 基本的な有効入力
assert safeParseInt("42") != null;
assert safeParseInt("-7") != null;
assert safeParseInt(" 10 ") != null; // trimの後
// null / デフォルト値を返すべき — スローしてはいけない
assert safeParseInt("") == null;
assert safeParseInt("abc") == null;
assert safeParseInt(null) == null;
assert safeParseInt("3.14") == null;
assert safeParseInt("1,000") == null; // カンマを先に除去しない限り
System.out.println("All checks passed");
例外が発生せず、出力にAll checks passedと表示されますか?修正は完了です。

