Java Tips | 基本ユーティリティ:数値パース

Java Java
スポンサーリンク

数値パースは「文字列をちゃんとした数字にする」作業

業務システムでは、画面入力や CSV、外部 API から「文字列として届いた数字」を、本物の intlongBigDecimal に変換する場面が山ほど出てきます。
この「文字列 → 数値」への変換を、一般に「数値パース(number parsing)」と呼びます。

Java では、Integer.parseIntDouble.parseDouble などのメソッドで数値パースを行いますが、形式が不正な文字列を渡すと NumberFormatException という例外が発生します。
業務コードではこの例外が頻出で、「ちゃんとパースできるか」「失敗したときどう扱うか」を設計しておくことがとても重要になります


基本の parseInt / parseLong / parseDouble を押さえる

代表的なパースメソッドとその挙動

Java 標準の代表的な数値パースメソッドは次の通りです。

  • Integer.parseInt(String s): 文字列を int に変換する。
  • Long.parseLong(String s): 文字列を long に変換する。
  • Double.parseDouble(String s) / Float.parseFloat(String s): 文字列を浮動小数点数に変換する。

使い方はとてもシンプルです。

int i = Integer.parseInt("123");
long l = Long.parseLong("456");
double d = Double.parseDouble("3.14");

System.out.println(i); // 123
System.out.println(l); // 456
System.out.println(d); // 3.14
Java

ここで重要なのは、「完全に数字として正しい形式の文字列しか受け付けない」という点です。
数字以外の文字が混ざっていたり、空文字だったり、範囲外の値だったりすると、NumberFormatException がスローされます。

NumberFormatException が出る典型パターンを体感する

いくつか「わざと失敗させる」例を見てみましょう。

Integer.parseInt("abc");     // 文字が混じっている → 例外
Integer.parseInt("");        // 空文字 → 例外
Integer.parseInt("12a3");    // 一部だけ数字 → 例外
Integer.parseInt("123");    // 全角数字を含む → 例外
Integer.parseInt("1,000");   // カンマ付き → 例外
Integer.parseInt(" 123 ");   // 前後に空白 → 例外
Integer.parseInt("999999999999"); // int の範囲外 → 例外
Java

これらはすべて NumberFormatException の原因としてよく挙げられるパターンです。
見た目は「数字っぽい」のに Java からすると「これは数字じゃない」と判断される、というギャップがバグの元になります。


例外を前提にした「素のパース」と try-catch

例外をそのまま上に投げるスタイル

もっとも素朴な書き方は、例外を特に捕まえず、そのまま上位に投げるスタイルです。

public int parseAge(String input) {
    return Integer.parseInt(input);  // 不正なら NumberFormatException がそのまま飛ぶ
}
Java

この場合、呼び出し側は「ここで例外が飛ぶかもしれない」と意識しておく必要があります。
業務ロジックの中で「ここは絶対に数字が来るはず」という前提が固いなら、このスタイルでも構いません。

try-catch でパース失敗を受け止める

ユーザー入力や外部データのように「不正な値が普通に来る」場面では、try-catchNumberFormatException を受け止めるのが基本です。

public Integer parseAgeOrNull(String input) {
    try {
        return Integer.parseInt(input);
    } catch (NumberFormatException e) {
        return null;  // パースできなければ null を返す
    }
}
Java

呼び出し側はこうなります。

String input = getAgeInput();  // 画面からの入力

Integer age = parseAgeOrNull(input);

if (age == null) {
    System.out.println("年齢は数字で入力してください");
} else {
    System.out.println("年齢は " + age + " 歳です");
}
Java

ここでのポイントは、「例外を業務ロジックに直接ばらまかず、ユーティリティで吸収する」という設計です。
これにより、画面やバッチのコードが「パース失敗時の扱い」を意識しやすくなります。


実務でよく使う「安全な数値パースユーティリティ」

null や空文字、空白をまとめて扱う

現場では、「null や空文字、空白だけの文字列は『値なし』として扱いたい」という要件が多いです。
そのたびに if (s == null || s.isBlank()) と書くのは面倒なので、ユーティリティにまとめてしまいます。

public final class Numbers {

    private Numbers() {}

    // null / 空文字 / 空白だけ → null、それ以外は int にパース
    public static Integer parseIntOrNull(String s) {
        if (s == null || s.isBlank()) {
            return null;
        }
        try {
            return Integer.parseInt(s.trim());
        } catch (NumberFormatException e) {
            return null;
        }
    }

    // パースできなければデフォルト値を返す版
    public static int parseIntOrDefault(String s, int defaultValue) {
        Integer value = parseIntOrNull(s);
        return value != null ? value : defaultValue;
    }
}
Java

使い方はこうです。

String input = getAgeInput();  // " 20 " や "" や "abc" かもしれない

int age = Numbers.parseIntOrDefault(input, 0);

if (age <= 0) {
    System.out.println("年齢を正しく入力してください");
} else {
    System.out.println("年齢は " + age + " 歳です");
}
Java

ここで重要なのは、次のような「現実世界の汚れた入力」を一箇所で吸収していることです。

  • 前後に空白が付いている " 20 "
  • 空文字や空白だけ "", " "
  • 数字以外が混ざっている "20歳"

こうした「よくある汚れ」をユーティリティで処理しておくと、業務ロジック側は「きれいな int が来る」と信じて書けるようになります。

範囲チェックを組み込んだパース

年齢や数量など、「あり得る範囲」が決まっている数値は、パースと同時に範囲チェックもしてしまうと安全です。

public static Integer parseAge(String s) {
    Integer value = parseIntOrNull(s);
    if (value == null) {
        return null;
    }
    if (value < 0 || value > 150) {
        return null;  // 業務的にあり得ない値は無効扱い
    }
    return value;
}
Java

こうしておくと、「-1 歳」や「9999 歳」といった値が DB に紛れ込むのを防げます。
パースとバリデーションをセットで考えるのが、実務的な設計のコツです。


カンマ付き・全角数字・小数などの「現場あるある」への対応

カンマ付き数値 “1,000” を扱う

業務では、画面や Excel から「1,000」のようなカンマ付き数値が来ることがよくあります。
Integer.parseInt("1,000") はそのままだと NumberFormatException になります。

シンプルな対処としては、「カンマを事前に取り除く」方法があります。

public static Integer parseIntWithComma(String s) {
    if (s == null || s.isBlank()) {
        return null;
    }
    String normalized = s.replace(",", "").trim();
    try {
        return Integer.parseInt(normalized);
    } catch (NumberFormatException e) {
        return null;
    }
}
Java

これで "1,000"" 2,500 ""1000" も同じように扱えます。
ただし、「小数点やマイナス記号も許可するか」「桁区切りの位置が正しいか」など、要件に応じてルールを決める必要があります。

全角数字や全角マイナスの扱い

日本語環境では、「123」のような全角数字が紛れ込むこともあります。
Java から見ると全角数字は別の文字なので、そのままではパースできません。

簡易的な対処としては、「全角数字を半角に変換してからパースする」方法があります。
これは自前でマッピングしてもいいですし、外部ライブラリを使うこともあります。

public static String toHalfWidthDigits(String s) {
    if (s == null) return null;
    StringBuilder sb = new StringBuilder(s.length());
    for (char c : s.toCharArray()) {
        if (c >= '0' && c <= '9') {
            sb.append((char) (c - '0' + '0'));
        } else {
            sb.append(c);
        }
    }
    return sb.toString();
}
Java

これをパース前に挟めば、"123""123" として扱えるようになります。
ただし、「全角を許可するかどうか」は業務要件次第なので、チームで方針を決めておくことが大事です。

小数・金額・精度の話

Double.parseDouble で小数をパースすることもできますが、金額や精度が重要な値には BigDecimal を使うのが一般的です。
BigDecimal には new BigDecimal(String) コンストラクタがあり、これも不正な形式の文字列を渡すと NumberFormatException をスローします。

BigDecimal price = new BigDecimal("1234.56");  // OK
BigDecimal bad   = new BigDecimal("1,234.56"); // 例外
Java

金額を扱うときは、「カンマをどうするか」「小数点以下の桁数をどう制限するか」などを含めて、専用のパースユーティリティを用意しておくと安全です。


まとめ:初心者が身につけるべき数値パースの感覚

数値パースでまず押さえるべきこと

  • 「文字列 → 数値」は常に失敗し得る
    見た目が数字でも、空白・カンマ・全角・範囲外などで簡単に NumberFormatException が出ることを体感しておく。
  • 例外をそのまま放置しない
    ユーティリティで try-catch し、null やデフォルト値、エラーコードなどに変換して、業務ロジックが扱いやすい形にする。
  • 「パース」と「バリデーション」をセットで考える
    年齢なら範囲チェック、金額なら桁数や符号のチェックなど、「業務的にあり得る値か」を同時に確認する。

ここまでの感覚が身につけば、数値パースで振り回されることはかなり減ります。

タイトルとURLをコピーしました