13.

java.math.BigDecimal cannot be cast to java.lang.String

編集
この記事の要点
  • BigDecimal cannot be cast to StringBigDecimal を String にキャストしようとしたエラー
  • 対処: (String) bdbd.toString() または bd.toPlainString()
  • 科学的記数法 (1.5E+3) を避けるなら toPlainString()
  • 逆方向 (String → BigDecimal): new BigDecimal(str)
  • DB で NUMERIC / DECIMAL 型を getObject() すると BigDecimal が返る

 

エラーの状況

java.lang.ClassCastException:
java.math.BigDecimal cannot be cast to java.lang.String
    at com.example.MyClass.process(MyClass.java:42)

// 典型的な発生コード
Object val = resultSet.getObject("price");  // NUMERIC → BigDecimal
String price = (String) val;  // ← エラー

原因

BigDecimal クラスは String を継承していないので、強制キャストは不可。

対処方法

① toString() / toPlainString()

BigDecimal bd = new BigDecimal("12345.678");

// 標準
String s1 = bd.toString();
// → "12345.678"

// 大きい数値だと科学的記数法
BigDecimal big = new BigDecimal("1500000000");
System.out.println(big.toString());
// → "1500000000"

// 小さい数値
BigDecimal small = new BigDecimal("0.0000001");
System.out.println(small.toString());
// → "1E-7"  ← 科学的記数法に!

// toPlainString で常に通常表記
System.out.println(small.toPlainString());
// → "0.0000001"

② String.valueOf()

String s = String.valueOf(bd);
// → bd.toString() と同じ、null セーフ (null → "null" 文字列)

// オブジェクトが null の場合の差
Object nullVal = null;
String s1 = String.valueOf(nullVal);  // → "null"
String s2 = nullVal.toString();        // → NullPointerException

③ 桁数フォーマット

BigDecimal bd = new BigDecimal("1234.5678");

// 小数 2 桁に
String formatted = bd.setScale(2, RoundingMode.HALF_UP).toPlainString();
// → "1234.57"

// 3 桁区切り
NumberFormat nf = NumberFormat.getNumberInstance(Locale.JAPAN);
nf.setMaximumFractionDigits(2);
String s = nf.format(bd);
// → "1,234.57"

// 通貨形式
NumberFormat cf = NumberFormat.getCurrencyInstance(Locale.JAPAN);
String price = cf.format(bd);
// → "¥1,235"

// DecimalFormat
DecimalFormat df = new DecimalFormat("#,##0.00");
String s = df.format(bd);
// → "1,234.57"

逆方向: String → BigDecimal

// String → BigDecimal
BigDecimal bd1 = new BigDecimal("1234.567");
BigDecimal bd2 = new BigDecimal("0.0001");
BigDecimal bd3 = new BigDecimal("-99.99");

// 日本円や $ 等を含む場合は前処理が必要
String price = "¥1,234.50";
String cleaned = price.replaceAll("[¥,$,]", "");  // "1234.50"
BigDecimal bd = new BigDecimal(cleaned);

// null セーフ
public static BigDecimal toBigDecimal(String s) {
    if (s == null || s.trim().isEmpty()) return null;
    try {
        return new BigDecimal(s.trim());
    } catch (NumberFormatException e) {
        return null;
    }
}

// double → BigDecimal (誤差注意)
BigDecimal fromDouble = BigDecimal.valueOf(1.5);  // ← 推奨
BigDecimal wrong = new BigDecimal(1.5);  // → 1.5000000000000... 誤差

JDBC でのよくあるパターン

// DB の DECIMAL / NUMERIC カラム
ResultSet rs = ps.executeQuery();
while (rs.next()) {
    // ❌ ダメ
    String price = (String) rs.getObject("price");

    // ✅ 良い
    BigDecimal priceBd = rs.getBigDecimal("price");
    String priceStr = priceBd.toPlainString();

    // または getString (DB 側で文字列に変換)
    String priceStr = rs.getString("price");
}

JPA / Hibernate でのマッピング

@Entity
public class Product {
    @Id @GeneratedValue
    private Long id;

    @Column(precision = 10, scale = 2)
    private BigDecimal price;  // DB: DECIMAL(10,2)
}

// 利用
Product p = productRepository.findById(1L).orElseThrow();
String priceText = p.getPrice().toPlainString();  // "1234.50"

// DTO
public class ProductDto {
    private Long id;
    private String price;  // 文字列で送る場合

    public static ProductDto from(Product p) {
        ProductDto dto = new ProductDto();
        dto.id = p.getId();
        dto.price = p.getPrice() != null ? p.getPrice().toPlainString() : null;
        return dto;
    }
}

JSON シリアライズ (Jackson)

// デフォルト: BigDecimal は数値として出力
ObjectMapper om = new ObjectMapper();
om.writeValueAsString(new BigDecimal("1234.5"));
// → "1234.5" (数値)

// 文字列として出力したい場合
om.configure(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);
// → "\"1234.5\""

// アノテーションで個別指定
public class Product {
    private Long id;

    @JsonSerialize(using = ToStringSerializer.class)
    private BigDecimal price;  // 文字列で出力
}

類似エラー

エラー意味
BigDecimal cannot be cast to Stringこのページ (toString() / toPlainString() を使う)
BigDecimal cannot be cast to Longbd.longValueExact() でロング化
BigDecimal cannot be cast to Integerbd.intValueExact()
BigDecimal cannot be cast to Doublebd.doubleValue()
Integer cannot be cast to BigDecimalBigDecimal.valueOf(intVal)

BigDecimal を扱う際のベストプラクティス

  • 金額計算には BigDecimal: double / float は浮動小数点誤差で金銭計算に不適
  • 等価比較は equals ではなく compareTo: new BigDecimal("1.00").equals(new BigDecimal("1.0"))false
  • 除算は MathContext or RoundingMode 必須: bd1.divide(bd2, 2, RoundingMode.HALF_UP)
  • 不変オブジェクト: 演算結果は新インスタンス(bd.add(other) は bd を変更しない)
  • 文字列化は toPlainString(): 科学的記数法を避ける

関連記事

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. java.lang.NoSuchMethodError
  2. java.lang.ClassCastException: java.util.Date cannot be cast to java.sql.Date
  3. java.lang.UnsupportedClassVersionError
  4. version less than X.X is not supported.
  5. パッケージ~は存在しません
  6. org.apache.jasper.JasperException: ...The jsp:param action must not be...
  7. java.io.FileNotFoundException: ファイル名 (許可がありません)
  8. java.sql.SQLException: Cannot convert value 'YYYY-MM-DD ...' from column n(YYYY-MM-DD ...) to TIMESTAMP.
  9. 警告: この文字は、エンコーディング[文字コード]にマップできません
  10. java.text.ParseException: Unparseable date
  11. Unsupported major.minor version 52.0
  12. エンティティ" ... "への参照は';'デリミタで終了する必要があります。
  13. java.math.BigDecimal cannot be cast to java.lang.String