この記事でわかること
Integer.parseIntのNumberFormatExceptionは、未入力、整数として読めない文字、intの範囲外を分けて調べます。全角数字「123」はJava 17ではそのまま123に変換できます。この記事では、3桁カンマを許可する数量欄を例に、形式を確認してから変換し、必須・形式・範囲のエラーを分けて返すコードを示します。


画面やCSVから受け取った数量をInteger.parseIntへ渡して失敗したときは、「受け取った文字列」「変換する型」「許可する入力形式」を分けて確認します。数字以外の文字が原因の場合と、数字だけでもintに収まらない場合では、直す箇所が違います。
よくある修正はtry-catchして0を返すことですが、未入力、形式不正、値0を同じにしてしまいます。どの文字列を許可し、どのエラーとして返すかを入力境界で決めます。
この記事のポイント
- 空文字や空白はparseIntできない
- カンマ・単位付きはparseIntできないが、全角数字は変換できる
- int範囲外でもNumberFormatExceptionになる
- 不正値を0へ置き換えて隠さない
- 画面・CSV・APIごとに入力契約とエラーを決める
数量欄の正常値と3種類の入力エラーを試す
記事に載せた QuantityParser.java と QuantityParserTest.java、実行設定の pom.xml を収録しています。JDK 17とMaven 3.9系を用意し、ZIPを展開したフォルダで mvn test を実行します。
まず入力値と変換先の型を確認する
次はJava 17のInteger.parseInt(String)の結果です。各行は独立した例です。途中で例外になる行があるため、そのまま上から続けて実行すると最初の例外で止まります。
Integer.parseInt(""); // NumberFormatException: 空文字
Integer.parseInt(" 123 "); // NumberFormatException: 前後の空白
Integer.parseInt("1,234"); // NumberFormatException: カンマ
Integer.parseInt("12.5"); // NumberFormatException: 小数点
Integer.parseInt("2147483648"); // NumberFormatException: intの上限超過
Integer.parseInt("123"); // 123: 全角数字は変換できるまず例外が発生した自分のコードの行を開き、変換直前の値を確認します。値がnullまたは空なら、フォーム名・CSV列・環境変数など取得元を調べます。値があるなら空白・カンマ・単位・小数点を確認し、数字だけなら変換先の上限と照合します。Integer.parseInt((String) null)もNumberFormatExceptionになります。
例えばCSVの数量欄が"1,234"だった場合、必要なのは「数字かどうか」という曖昧なチェックではなく、「カンマ付き数量を受け付ける仕様か」の確認です。仕様で禁止しているなら入力エラーにし、許可しているなら3桁区切りを検証してから変換します。
例外メッセージに入力値が含まれることがあります。本番データをそのままログへ追加するのではなく、再現用の値で空白や記号の違いを確認します。
空文字と空白を先に扱う
任意入力なら、未入力をnullとして扱うのか既定値にするのかを決めてから変換します。次の例は、未入力はnull、前後の空白はstrip()で取り除く仕様です。必須入力や、空白を認めないCSVの仕様へそのまま流用しないでください。
Integer parseOptionalInt(String value) {
if (value == null || value.isBlank()) {
return null;
}
return Integer.valueOf(value.strip());
}戻り値nullをServiceへ広げると別のNPEを生むことがあります。Formでは文字列、変換後DTOではIntegerなど、境界と内部型を分ける設計も検討します。
カンマは3桁区切りを検証してから取り除く
1,234はInteger.parseIntでは変換できません。ただし、無条件のreplace(",", "")では12,34まで1234になります。先に文字列全体の形式を検証します。
NumberFormatに置き換えるだけでも不十分です。Java 17の日本ロケールでは、次のように不正な区切り12,34を最後まで読んで1234にします。
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.util.Locale;
NumberFormat format = NumberFormat.getIntegerInstance(Locale.JAPAN);
ParsePosition position = new ParsePosition(0);
Number number = format.parse("12,34", position);
System.out.println(number); // 1234
System.out.println(position.getIndex()); // 5: 最後まで読んでも区切りは不正ParsePositionは「1,234円の円を読まずに終わった」といった途中終了の検出には使えます。しかし、全体を読んだことと3桁区切りが正しいことは別です。setParseIntegerOnly(true)も桁区切りの検証を追加する設定ではありません。
次は、数量欄で「半角数字、カンマなし、または3桁区切りのカンマ」を許可する例です。0〜2,147,483,647を受け付け、前後空白・符号・小数・単位・全角数字は入力エラーにします。先頭の0は許可しています。
public final class QuantityParser {
private QuantityParser() {}
public static int parse(String input) {
if (input == null || input.isBlank()) {
throw new IllegalArgumentException("数量を入力してください");
}
// ASCII数字のみ。カンマを使うなら先頭1〜3桁、以降は3桁ずつ。
if (!input.matches("(?:[0-9]+|[0-9]{1,3}(?:,[0-9]{3})+)")) {
throw new IllegalArgumentException("数量は半角数字と3桁区切りのカンマで入力してください");
}
try {
return Integer.parseInt(input.replace(",", ""));
} catch (NumberFormatException e) {
throw new IllegalArgumentException("数量は0〜2,147,483,647で入力してください", e);
}
}
}matchesは文字列全体を照合します。[0-9]+はカンマなし、後半は先頭1〜3桁と「カンマ+3桁」の繰り返しです。1,234と1234は通り、12,34や1,23,456は変換前に止まります。形式が正しくてもintに収まらなければ、最後のcatchで範囲エラーにします。
この正規表現は上記の数量欄の仕様に限定したものです。小数や負数を扱う金額欄、桁区切りが異なるロケールへ共通化しないでください。既存の入力部品がある場合も、12,34を拒否するか、その部品のテストで確かめます。
全角数字はparseIntできる。半角限定なら別に検証する
Integer.parseInt("123")はJava 17で123になります。parseIntはASCIIの0〜9だけを受け付けるメソッドではなく、各桁をCharacter.digitの規則で判定します。「全角数字だからNumberFormatExceptionになる」という切り分けは誤りです。
Integer.parseInt("123"); // 123
Integer.parseInt("-123"); // -123: 符号はASCIIのマイナス
Integer.parseInt("-123"); // NumberFormatException: 全角のマイナス
Integer.parseInt(" 123"); // NumberFormatException: 先頭の全角空白画面で似て見えても、数字と符号・空白は別です。全角入力で失敗したときは、数字以外に全角のマイナスや空白が付いていないかも確認します。
前節のQuantityParserが123を拒否するのは、parseIntの制約ではなく「半角数字のみ」という入力仕様を[0-9]で検証しているためです。APIで変換できる値と、業務で許可する値を混同しないでください。
全角数字を受け付けるだけなら、parseIntのためにNFKC正規化を足す必要はありません。Normalizer.normalize("①", Normalizer.Form.NFKC)は"1"にも変わります。全角数字だけを許可したつもりで、丸数字など別の文字まで受け付けないよう、正規化の前後と許可範囲を別々に決めます。
桁あふれでもNumberFormatException
文字がすべて数字でも、intの範囲を超えると変換できません。IDや金額が将来大きくなる場合、型選択を確認します。
Integer.parseInt("2147483647"); // 最大値
Integer.parseInt("2147483648"); // NumberFormatException
long id = Long.parseLong("2147483648");longでも足りない整数、または桁数を失いたくないコード値ならBigIntegerやStringを検討します。電話番号、郵便番号、商品コードは計算しないため、数字だけでも数値型が適切とは限りません。
Integer.parseInt("2147483648")は変換の時点で例外になります。50,000を数値へ変換してからint同士で掛け算した結果がマイナスになる場合は、変換は成功しているので掛け算を行う式の型を確認します。
小数と金額は適切な型へ変換する
小数をIntegerへ変換するのではなく、用途に合う型を使います。金額や率ではBigDecimalを文字列から作ると、double経由の誤差を避けられます。
BigDecimal amount = new BigDecimal("1234.50");
// 避けたい例
BigDecimal inaccurate = new BigDecimal(0.1);BigDecimalでもカンマや通貨記号はそのまま受け付けません。入力フォーマットの解析と、内部の数値表現を分けます。
必須・形式・範囲のエラーを分けて返す
前節のQuantityParserは、未入力なら「数量を入力してください」、12,34なら形式エラー、2,147,483,648なら範囲エラーを返します。利用者は空欄を埋める、カンマを直す、上限以下にする、のどれが必要か判断できます。すべてを「整数で入力してください」にすると、数字だけの上限超過でも原因が伝わりません。
例では入力不正を標準のIllegalArgumentExceptionで表しています。画面やCSVへ組み込む際は、QuantityParserを呼ぶ境界でこの入力エラーを該当する数量欄・CSV行のエラーへ対応付けます。このクラスを置くだけで、HTTPの400や画面の項目エラーへ自動変換されるわけではありません。
「注文数は1〜999まで」の業務ルールが別にあるなら、数値へ変換した後にその範囲も確認します。intに収まることは、注文できる数量であることを保証しません。エラーをcatchして0を返すと、未入力や書式不正が数量0として処理されるため避けます。
JUnitで「通す値」と「拒否する値」を両方確認する
カンマの節に載せたQuantityParser.parseを呼び、変換値とエラーの種類を確かめます。123は半角限定の規則、12,34は3桁区切りの規則で拒否します。2,147,483,648は形式を通るので、上限超過のメッセージと、原因として残したNumberFormatExceptionを確認します。以下はZIPに収録したQuantityParserTest.javaの全文です。
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.junit.jupiter.params.provider.ValueSource;
class QuantityParserTest {
@ParameterizedTest
@CsvSource(value = {"0|0", "1234|1234", "1,234|1234", "0001|1", "000,001|1",
"2147483647|2147483647", "2,147,483,647|2147483647"}, delimiter = '|')
void 許可した形式を数値に変換する(String input, int expected) {
assertEquals(expected, QuantityParser.parse(input));
}
@ParameterizedTest
@NullAndEmptySource
@ValueSource(strings = {" ", " "})
void 未入力には必須のエラーを返す(String input) {
var error = assertThrowsExactly(IllegalArgumentException.class,
() -> QuantityParser.parse(input));
assertEquals("数量を入力してください", error.getMessage());
assertNull(error.getCause());
}
@ParameterizedTest
@ValueSource(strings = {" 123 ", "12,34", "1,23,456", "1234,567", "1,,234",
"123", "1.5", "-1", "+1"})
void 許可しない書式には形式のエラーを返す(String input) {
var error = assertThrowsExactly(IllegalArgumentException.class,
() -> QuantityParser.parse(input));
assertEquals("数量は半角数字と3桁区切りのカンマで入力してください", error.getMessage());
assertNull(error.getCause());
}
@ParameterizedTest
@ValueSource(strings = {"2147483648", "2,147,483,648", "999999999999999999999"})
void int上限超過には範囲のエラーと原因を返す(String input) {
var error = assertThrowsExactly(IllegalArgumentException.class,
() -> QuantityParser.parse(input));
assertEquals("数量は0〜2,147,483,647で入力してください", error.getMessage());
assertInstanceOf(NumberFormatException.class, error.getCause());
}
}上限ちょうどの2,147,483,647を通し、1大きい2,147,483,648を拒否する組で確認します。カンマも正常な1,234と不正な12,34を対にすると、単なるカンマ除去へ戻した変更を検出できます。
NumberFormatExceptionはIllegalArgumentExceptionのサブクラスです。assertThrows(IllegalArgumentException.class, ...)だけでは、範囲エラーを作るcatchを外しても検出できません。展開したZIPでmvn testを実行すると23件が通ります。catchを外すと、assertThrowsExactlyでアプリ側の例外型を指定した範囲超過の3件だけが失敗します。JUnitのassertThrowsExactlyの仕様
レビューでは許可形式とテスト結果を確認する
数値変換のレビューではcatchの有無ではなく、入力形式、正規化、型の範囲、不正時の利用者向けエラーが一貫しているかを見ます。
// レビューコメント例
NumberFormatExceptionをcatchして0にすると、不正入力と数量0を区別できません。
数量欄のエラーとして返してください。
// レビューコメント例
カンマをreplaceするだけでも、NumberFormatで最後まで読んだだけでも12,34を通します。
3桁区切りを先に検証し、1,234が成功、12,34が失敗するテストを追加してください。
// レビューコメント例
この値は商品コードで計算しません。先頭0も必要なので、
IntegerではなくStringのまま扱う方が契約に合います。レビューへの返信では、「正規表現を足しました」だけで終えず、許可した入力と拒否する入力を答えます。例えば「1,234は1234へ変換し、12,34と上限超過は別のエラーにしました。境界値もテスト済みです」と説明できれば、実装が仕様に沿っているか判断できます。
提出前のセルフチェック
レビュー前に確認すること
- null・空文字・空白の扱いを決めたか
- 1,234を許可し、12,34を拒否できるか
- 全角数字を受け付けるか、半角限定で検証するか決めたか
- 正規化が他の文字を変えないか
- 小数を整数型へ入れようとしていないか
- intやlongの範囲を超えないか
- コード値を数値型にする必要があるか
- 不正値を0で隠していないか
- 項目エラーとして利用者へ返せるか
Javaの型と例外を基本から確認する参考書
文字列、数値型、例外処理を一緒に整理すると、変換失敗をcatchで隠さず、入力境界で正しく扱えるようになります。
スッキリわかるJava入門 第5版
変数・条件分岐から、クラスの基本まで学ぶ一冊。
豊富な図とサンプルで、変数、条件分岐、クラス、例外処理まで順番に学べます。Javaの最初の教科書を探している人向けです。
- Javaを基礎から体系的に学びたい
- Java 25 LTS対応の入門書を選びたい
当サイトはAmazonアソシエイト・プログラムの参加者です。価格・在庫・配送条件はAmazonでご確認ください。
この記事とあわせて読みたい
まとめ
Integer.parseIntのNumberFormatExceptionは、未入力、整数として読めない文字、intの範囲外を分けて調べます。全角数字そのものは変換できるため、全角の符号や空白、半角限定の独自チェックと混同しないでください。
カンマを許可する場合は3桁区切りを検証してから取り除きます。NumberFormatの全消費チェックだけでは不正な区切りを見逃します。必須・形式・範囲のエラーを分け、正常な1,234、不正な12,34、intの上限と上限超過をセットで確認してください。




