目次
はじめに
Javaでの数値の扱いは一見単純に見えて、実務では様々な落とし穴があります。本記事では、システム開発の現場で知っておくべきJavaの数値型の基本と実践的な選択基準をまとめました。
1. 数値型の基礎知識
整数型
型 |
用途 |
値の範囲 |
実務での使い所 |
int |
一般的な整数値 |
約±21億 |
ループカウンタ、配列インデックス |
long |
大きな整数値 |
約±900京 |
ID、タイムスタンプ、大きな集計値 |
浮動小数点型
型 |
用途 |
精度 |
実務での使い所 |
float |
メモリ効率重視の小数 |
約7桁 |
精度があまり重要でない計算 |
double |
標準的な小数計算 |
約15桁 |
科学計算、一般的な小数計算 |
高精度型
型 |
用途 |
特徴 |
実務での使い所 |
BigDecimal |
正確な小数計算 |
任意精度、遅い |
金額計算、会計処理 |
BigInteger |
超大きな整数 |
桁数制限なし、遅い |
暗号処理、巨大数の計算 |
2. プリミティブ型とラッパークラスの使い分け
基本的な選択基準
-
プリミティブ型(int, long, double): パフォーマンス重視、大量計算時
-
ラッパークラス(Integer, Long, Double): NULL許容、コレクション利用時
longとLongの実務的な違い
// プリミティブ型の例
long id = 123456789L; // Lサフィックス必須
long result = id + 1; // 演算が高速
// ラッパークラスの例
Long entityId = null; // null可能
Optional<Long> optId = Optional.ofNullable(entityId); // モダンな書き方
実務での使い分けの原則
- データベースと連携する値:ラッパークラスを使う(null対応のため)
- 内部計算処理:プリミティブ型を使う(パフォーマンスのため)
- フレームワーク連携(JPA等):ラッパークラスを使う(規約のため)
3. 実務での数値計算の注意点
浮動小数点数の罠
// 浮動小数点数の計算は正確ではない
System.out.println(0.1 + 0.2); // 0.30000000000000004と表示される
// 金額計算には必ずBigDecimalを使用
BigDecimal price = new BigDecimal("10.25");
BigDecimal quantity = new BigDecimal("3");
BigDecimal total = price.multiply(quantity); // 正確に 30.75
BigDecimalの正しい使い方
- 文字列からの初期化を使う(double経由は避ける)
- スケールと丸めモードを明示的に指定する
- equals()の代わりにcompareTo()を使う
// 良い例
BigDecimal tax = new BigDecimal("1234.56").setScale(2, RoundingMode.HALF_UP);
// 悪い例
BigDecimal wrongTax = new BigDecimal(1234.56); // 精度損失の可能性あり
4. オーバーフロー対策と精度管理
オーバーフロー検出
// Java 8以降の安全な計算方法
try {
int result = Math.addExact(Integer.MAX_VALUE, 1);
} catch (ArithmeticException e) {
// オーバーフロー発生時の処理
long safeResult = (long)Integer.MAX_VALUE + 1;
}
精度管理のチェックポイント
- IDや大きなカウンター値にはlongを使用
- 2038年問題を避けるため、時間値にはlongを使用
- 小数点以下の精度が重要な場合はBigDecimalを使用
- BigDecimalの比較は必ず**compareTo()**メソッドを使用
5. 国際化対応の数値処理
ロケール対応のフォーマット
// 数値の国際化対応表示
NumberFormat formatter = NumberFormat.getNumberInstance(Locale.JAPAN);
String formattedNumber = formatter.format(1234567.89); // "1,234,567.89"
// 通貨の国際化対応表示
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(Locale.JAPAN);
String formattedCurrency = currencyFormatter.format(1234567.89); // "¥1,234,568"
国際化アプリケーションでの注意点
- ユーザー入力の数値解析時はロケールを考慮
- 内部処理では常にロケール非依存の形式で保持
- 表示時にのみロケール依存のフォーマットを適用
実務者のための数値型選択チェックリスト
-
データベースのID:
Long
(null許容のため)
-
内部カウンター:
long
(パフォーマンスのため)
-
配列インデックス:
int
(標準的な使い方)
-
金額計算:
BigDecimal
(精度のため)
-
日時処理:
long
またはInstant
(2038年問題回避)
-
UI表示用数値: ラッパークラス + フォーマッタ(null対応とフォーマット機能)
-
大量計算が必要な処理: プリミティブ型(パフォーマンスのため)
-
不明確な要件や拡張性が必要な場合: 大きめの型を選択
適切な数値型の選択は、バグの防止、パフォーマンスの向上、コードの可読性向上に直結します。プロジェクトの早い段階で数値型の設計方針を決めておくことをお勧めします。