「数字に見えるのにエラーって、どういうことなんですか!?」
Javaで Integer.parseInt(” 12 “) を実行したとき、私は見事にクラッシュしました。
「えっ、12って入ってますけど?」と思っていたあの頃…。
“123”(←全角)や “1,000”(←カンマ入り)、””(←空文字)など、一見数字っぽい文字列が怒られるたび、Javaくんの“数字の定義の厳しさ”に驚かされました。
でも今思えば、それはJavaからの「ちゃんと確認してね」という優しさだったのかもしれません。
本記事では、そんな NumberFormatException と出会った経験をもとに、
なぜこのエラーが起きるのか、よくある落とし穴はどこなのか、 どうやって防げばいいのか、といった内容を、わかりやすく解説していきます。
数字とうまく付き合いたい方、ぜひご一読ください!
NumberFormatExceptionとは? ― 変換できない“数字”たち
「NumberFormatException」は、“数字じゃないよ”の優しい拒絶
Javaで文字列を数値に変換するには、Integer.parseInt() や Double.parseDouble()、Long.valueOf() などのメソッドを使います。
とても便利なメソッドですが、「文字列がちゃんと数値の形になっていないと落ちます」という注意点があります。
たとえば、こんなコード
String input = "42a";
int number = Integer.parseInt(input); // ❌ 実行時にエラー発生
これはコンパイルは通るものの、実行時に java.lang.NumberFormatException を吐いてプログラムが止まってしまいます。
なぜ発生するの?
NumberFormatException は、「その文字列、どう見ても数値じゃないよ」とJavaに言われている状態です。
正式には、数値に変換できない形式の文字列を数値型に変換しようとしたときに起こる実行時例外です。
つまり、こんなときに起きます:
入力文字列 | 結果 |
---|---|
“123” | ⭕️OK (整数として変換可能) |
“12a” | ❌ NumberFormatException 発生 |
“”(空文字) | ❌ 同上 |
” 42 “ | ❌(空白付き)※trimしないとNG |
“1,000” | ❌(カンマ入り) |
“123” | ❌(全角数字) |
どんなメソッドで起きやすいの?
以下のような「文字列→数値」に変換するメソッドでよく見られます:
- Integer.parseInt(String s)
- Double.parseDouble(String s)
- Long.valueOf(String s)
- Float.parseFloat(String s)
- new BigDecimal(String s)(特に小数点・通貨表記)
どの型でも、対象の形式以外の文字が混じっているとエラーになります。
このエラー、事前に防げないの?
いいえ、防げます! でも Java は「数字に見える」ではなく、「正しい形式の文字列か」を厳密に見ています。
そのため、空白、記号、全角、改行、null などの“目に見えづらいノイズ”が混じっていると、素直にエラーになります。
たとえば、こんな一手間
String input = " 123 ";
int num = Integer.parseInt(input.trim()); // 👍 OK!
この章のまとめ
- NumberFormatException は、「数値じゃないよ!」とJavaが教えてくれる実行時例外
- 文字列を数値に変換する際、「形式が正しくない」と落ちる
- 空白や記号、全角文字など“見落としがちな原因”が多い
- 「見た目が数字っぽい」≠「Javaにとっての数字」
よくある発生パターン ― 空文字、記号、全角数字の罠
「数字のはずなのに、なぜエラー?」
NumberFormatException は、Javaが 「これは数字じゃない」と判断した文字列 に対して発生します。
でも、私たちが“数字っぽい”と思っていても、Javaは容赦なく落とします。
この章では、ついやってしまいがちな入力例と、それぞれの背景をコード付きで解説します。
ケース①:空文字(””)は数字じゃない!
String input = "";
int number = Integer.parseInt(input); // ❌ エラー
原因: 何も入っていない=数値情報ゼロ。Javaも「どうしろと…?」となります。
対策: 空文字チェックは変換前に必須!
if (input != null && !input.isEmpty()) {
int number = Integer.parseInt(input);
}
ケース②:文字が混じっている
String input = "42a";
int number = Integer.parseInt(input); // ❌ エラー
原因: 数字の後ろにアルファベットなどが混ざっていると、完全にアウト。
対策: ^[0-9]+$ などの正規表現で“純粋な数字だけ”か確認しましょう。
if (input.matches("^[0-9]+$")) {
int num = Integer.parseInt(input);
}
ケース③:全角数字(”123”)は別物
String input = "123"; // 全角
int number = Integer.parseInt(input); // ❌ エラー
原因: 全角の“123”は、Javaにとって「数字じゃない別キャラ」です。
対策: ユーザー入力の場合、全角→半角変換してあげる処理も検討しましょう(例:正規化)。
ケース④:カンマ付きの数値(”1,000″)
String input = "1,000";
int number = Integer.parseInt(input); // ❌ エラー
原因: Javaはカンマ(,)の入った値を数値として扱いません。
対策: replaceAll() でカンマを除去してから変換!
String cleaned = input.replaceAll(",", "");
int number = Integer.parseInt(cleaned); // ⭕️ OK
ケース⑤:空白(スペース)に気づかない!
String input = " 42 ";
int number = Integer.parseInt(input); // ❌ エラー(trimしてない)
原因: 前後のスペースが残っていると、Javaは“それ数字じゃないよ”と判断します。
対策: .trim() で空白を取り除きましょう。
int number = Integer.parseInt(input.trim()); // ⭕️ OK
まとめ:見た目が数字っぽくても油断禁物!
入力 | 落ちる理由 | 対策 |
---|---|---|
“” | 空文字 | isEmpty() チェック |
“42a” | 文字混入 | 正規表現 or try-catch |
“123” | 全角数字 | 半角変換(必要に応じて) |
“1,000” | カンマ | replaceAll() |
” 42 “ | 空白付き | .trim() |
Javaは見た目よりも“正確さ”を重視します。
「これは数字っぽいからOKでしょ」ではなく、「これは明確に数字です」と言える状態で渡すことが大切なんですね。
エラーメッセージを読み解く ― Javaからの正直な伝言
エラー文、ちゃんと読んでますか?
avaのエラーメッセージ、最初はちょっと intimidating(ビビる)かもしれませんが、 実はとても まっすぐで正直な“ヒントのかたまり”なんです。
例えば、こんなエラーを見たことはありませんか?
Exception in thread "main" java.lang.NumberFormatException: For input string: "12a"
at Sample.main(Sample.java:5)
「なんか怒られてるっぽいけど…」とスルーせず、ひとつひとつ読み解いてみましょう。
メッセージを分解してみよう
部分 | 意味 |
---|---|
NumberFormatException | 発生した例外の種類(数値変換に失敗) |
For input string: “12a” | 原因となった文字列(”12a”が数字じゃない) |
at Sample.main(Sample.java:5) | エラーが発生した場所(Sampleクラスの5行目) |
つまりこのメッセージはこう言っています:
「Sample.javaの5行目で、’12a’ を数字に変換しようとして失敗しましたよ」
Java、わりとめちゃくちゃ素直じゃないですか?
実際のコードと照らしてみよう
public class Sample {
public static void main(String[] args) {
String input = "12a";
int num = Integer.parseInt(input); // ← ここでエラー
}
}
実行すると:
Exception in thread "main" java.lang.NumberFormatException: For input string: "12a"
at Sample.main(Sample.java:5)
5行目で、”12a” という「数字+文字列」の混合を int に変換しようとして失敗しています。
スタックトレースを活用するコツ
- 例外の種類を見る → NumberFormatException = 数値への変換に失敗した可能性が高い
- 対象の文字列を見る → “abc” や “1,000” など、エラー原因のヒントがここに!
- エラー発生箇所を見る → Sample.java:5 のような表記で、該当の行がすぐ分かる
- getMessage() を使ってログに出す
try {
int value = Integer.parseInt(input);
} catch (NumberFormatException e) {
System.err.println("変換失敗:" + e.getMessage());
}
この章のまとめ
- NumberFormatException: For input string: “xxx” は 「それ、数値じゃないよ」のサイン
- エラー文は「どこで」「何が」ダメだったかを正確に伝えてくれる
- 怖がらずに、エラーを読む → 見に行く → 改善する の習慣がとても大切です
解決策まとめ ― 数字変換の安全地帯をつくる
原則:「ちゃんとした数字ですよ」とJavaに伝える準備がすべて!
NumberFormatException を防ぐには、「この文字列、本当に数字になれるのか?」を変換前に確かめることが第一歩です。
ここでは、実務や学習の場でもよく使われる安全対策を5つご紹介します。
対策①:try-catch で例外を受け止める
try {
int num = Integer.parseInt(input);
System.out.println("変換成功:" + num);
} catch (NumberFormatException e) {
System.out.println("変換失敗:" + e.getMessage());
}
ユーザー入力や外部から受け取るデータには、必ず防御コードを。
対策②:isEmpty() や isBlank() で空チェック
if (input != null && !input.isBlank()) {
int num = Integer.parseInt(input.trim());
}
空文字や空白だけの入力は、「数字変換以前の問題」。 trim() も忘れずに!
対策③:正規表現で「数字だけ」か確認する
if (input.matches("^[0-9]+$")) {
int num = Integer.parseInt(input);
}
“12a” や “1,000”、”123” を事前にフィルタリング。
^[0-9]+$ なら「半角数字のみ」のチェックが可能です。
対策④:不要な文字(カンマなど)を削除する
String cleaned = input.replaceAll(",", "");
int num = Integer.parseInt(cleaned);
カンマや通貨記号(¥や$)を含む場合は、変換前に加工処理を加えると安心です。
対策⑤:入力→変換→使用を分離する設計にする
Optional<Integer> safeParse(String s) {
try {
return Optional.of(Integer.parseInt(s));
} catch (NumberFormatException e) {
return Optional.empty();
}
}
こうしておくと、「変換できたときだけ処理を進める」柔軟なロジックが書けます。
特に 大量のデータを扱う処理や、部分的にスキップしても良い場面で便利 です!
この章のまとめ
- 数字変換前に「それ、本当に数字?」をチェックする習慣が大切
- try-catch は最後の砦、でも できるだけ事前に弾くのが理想
- 正規表現や空文字チェック、カンマ除去などで“安全な文字列”に整えてから変換
- 設計上「例外を起こさず済む書き方」も視野に入れよう
設計と習慣 ― 「入力を信じすぎない」心構え
なぜエラーが起きるのか?の根っこにある考え方
エラーの多くは「こう動くはず」という思い込みから生まれます。
NumberFormatException もまさにその代表例。
たとえば、ユーザーが数字を入力してくれると信じて Integer.parseInt(input) を書いたけれど、実際は “abc” だった。
あるいは、APIのレスポンスに数字が来るはずが、 “null” や ” ” が混じっていた。
つまりこのエラー、「入力を信じすぎたコード」に対するJavaからのツッコミなのです。
習慣①:外部から来るデータは“信用しない”のが基本
フォーム入力・CSV・API・ファイル読込など、“外から来るものは型保証されていない”ことを前提にしましょう。
// ❌ いきなり変換すると危険
int value = Integer.parseInt(param);
// ✅ まずはnull・空・形式をチェック!
if (param != null && param.matches("^[0-9]+$")) {
int value = Integer.parseInt(param);
}
想定外を受け入れる器のあるコードが、トラブルに強くなります。
習慣②:入力・変換・利用を“分ける”
// ❌ 入力と変換と処理が一気に行われている
int age = Integer.parseInt(request.getParameter("age"));
これだと何が悪かったのか分かりづらく、テストもしにくいです。
// ⭕️ 入力 → 検証 → 処理 に分離
String ageInput = request.getParameter("age");
if (ageInput != null && ageInput.matches("^[0-9]+$")) {
int age = Integer.parseInt(ageInput);
user.setAge(age);
} else {
log.warn("不正な年齢入力:" + ageInput);
}
それぞれの責任を分けることで、エラーを見つけやすくなります。
習慣③:「変換できなかったらどうする?」を事前に決めておく
変換に失敗したとき、アプリ全体が止まってしまってもよいのか? ログに残してスキップする?それともデフォルト値で代用する?
int value = 0;
try {
value = Integer.parseInt(input);
} catch (NumberFormatException e) {
log.warn("数値変換できませんでした。0に設定します:" + input);
}
あらかじめ「例外時のふるまい」を考慮しておくことも、“落ちない設計”の大切な一部です。
習慣④:「すべてが整数とは限らない」前提で考える
// ❌ ユーザーが「1.5」と入力 → parseIntで落ちる
int quantity = Integer.parseInt("1.5"); // → NumberFormatException
// ⭕️ parseDouble や try-catch など、用途に合った選択を
double quantity = Double.parseDouble("1.5");
想定通りのフォーマットになっている保証は、実はどこにもありません。
だからこそ「いろんな入力が来るかもしれない」という前提で設計をすると、コードの安定感が変わってきます。
習慣チェックリスト(セルフレビュー用)
項目 | 意味 |
---|---|
入力値を無条件で変換していないか? | 信頼前にチェックを |
データ検証と利用の処理が混ざっていないか? | 責任を分離しよう |
想定外の入力にどう対応するか決まっているか? | デフォルトやログ処理も含めて考える |
受け取るのは本当に整数でよいか? | 場合によっては浮動小数なども検討 |
この章のまとめ
- 「この入力、信じて大丈夫?」という目線を持つことが、落ちないコードの第一歩
- 入力 → 検証 → 変換 → 利用 の流れを明確に分けよう
- 例外が起きるのは“予期していなかったとき”。だからこそ、“予期する習慣”を身につけよう
まとめ ― 数字とも、Javaとも仲良くなれた日
“怒られた理由”を知ると、やさしくなれる
NumberFormatException は、「数字に変換できない文字列を渡されたときに起きるエラー」です。
ただしそれは、Javaが意地悪をしているわけではありません。
むしろ「それ、ちゃんと見直してね」と、プログラムの安全のために止めてくれているサインでもあるんです。
最初は戸惑ったこの例外も、理由を知っていくことでだんだん怖くなくなってきました。
エラーとの対話で深まる“型”への理解
今回学んだのは、単に“正しい文字列を渡せばOK”というテクニック以上に、
- どんな入力も正しいとは限らない
- 数字っぽく見えても、数字じゃないことがある
- コードの安全性は「前提を疑える力」で決まる
という、プログラミングにおける「向き合い方」だったのかもしれません。
「これ数字です!」と自信を持って渡せるコードに
今後、数字を扱うコードを書くときには、きっと
- 空文字、大丈夫かな?
- 全角・カンマ・空白、混ざってないかな?
- 想定外の文字列が来たらどうする?
といった“ひと呼吸おいた思考”が自然と生まれてくるはずです。
それはエラーを通じて得られた、コードとの信頼関係のはじまりでもあります。
最後に:エラーは「やらかし」ではなく「成長記録」
今回の記事が、「あ、これ自分もやったことある…!」と少しでも共感の助けになっていたら嬉しいです。
エラーは怖くありません。むしろ「気づきをくれるメンター」のような存在です。
焦らず、一つずつ。 エラーと向き合った経験は、確実にあなたのエンジニアとしての糧になります。

NumberFormatExceptionは、私自身たくさんつまずいた経験があるからこそ、この記事を書きました。もしどこかで「あるある…!」と共感していただけたなら、とても嬉しいです。
エラーとの出会いが、少しでも前向きな学びに変わりますように。これからも一緒に成長していきましょう!
コメント