概要
長さ、重量、温度、速度などの単位変換は、物流、製造、科学技術計算などの業務で頻繁に必要になります。変換式を個別に書くと組み合わせ爆発が起きるため、基準単位を経由する設計が有効です。温度変換のように単純な係数乗算では対応できない単位系もあり、華氏と摂氏の変換ミスは海外取引先との仕様書やり取りで実際に起こりやすい問題です。この記事では、enum で単位を定義し、基準単位への変換係数を持たせることで、任意の単位間の変換を共通ロジックで扱う方法を紹介します。
使いどころ
物流システムで重量をkg/lb/ozなど複数単位で入出力する
製造システムで寸法をmm/cm/inchで変換する
科学技術計算で温度をCelsius/Fahrenheit/Kelvinで変換する
コード例
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
public class UnitConverter {
enum LengthUnit {
METER(BigDecimal.ONE),
CENTIMETER(new BigDecimal("0.01")),
MILLIMETER(new BigDecimal("0.001")),
KILOMETER(new BigDecimal("1000")),
INCH(new BigDecimal("0.0254")),
FOOT(new BigDecimal("0.3048"));
final BigDecimal toMeter;
LengthUnit(BigDecimal toMeter) {
this.toMeter = toMeter;
}
}
private static final MathContext MC =
new MathContext(10, RoundingMode.HALF_UP);
public static BigDecimal convert(
BigDecimal value,
LengthUnit from,
LengthUnit to) {
var meters = value.multiply(from.toMeter);
return meters.divide(to.toMeter, MC);
}
public static void main(String[] args) {
var feet = new BigDecimal("6");
var cm = convert(feet,
LengthUnit.FOOT, LengthUnit.CENTIMETER);
System.out.println(feet + " ft = " +
cm.setScale(2, RoundingMode.HALF_UP) +
" cm");
}
}Version Coverage
record + switch 式で変換ロジックを簡潔に書ける。var による型推論で記述量も減る。
// Java 17: record + switch 式で変換ロジック
record Conversion(BigDecimal value, String unit) {}
var result = switch (to) {
case METER -> meters;
case CENTIMETER -> meters.divide(
CENTIMETER.toMeter, MC);
case INCH -> meters.divide(
INCH.toMeter, MC);
};
var output = new Conversion(result, to.name());Library Comparison
注意点
温度変換は単純な係数乗算ではないため、別途ロジックが必要。
BigDecimal で係数を管理しないと浮動小数点誤差が入る。
単位の追加時は enum にフィールドを追加するだけで拡張できる設計にする。
FAQ
N種類の単位があっても N×2 の変換メソッドで済み、N×N の組み合わせ爆発を防げます。
Kelvin を基準にすれば可能ですが、Celsius⇔Fahrenheit のオフセット加算は個別ロジックが必要です。
enum の代わりに Map で変換係数を管理すれば、設定ファイルや DB から読み込めます。