package sample.util; import java.math.*; import java.util.concurrent.atomic.AtomicReference; /** * 計算ユーティリティ。 * <p>単純計算の簡易化を目的とした割り切った実装なのでスレッドセーフではありません。 */ public final class Calculator { private final AtomicReference<BigDecimal> value = new AtomicReference<>(); /** 小数点以下桁数 */ private int scale = 0; /** 端数定義。標準では切り捨て */ private RoundingMode mode = RoundingMode.DOWN; /** 計算の都度端数処理をする時はtrue */ private boolean roundingAlways = false; /** scale未設定時の除算scale値 */ private int defaultScale = 18; private Calculator(Number v) { try { this.value.set(new BigDecimal(v.toString())); } catch (NumberFormatException e) { this.value.set(BigDecimal.ZERO); } } private Calculator(BigDecimal v) { this.value.set(v); } /** * 計算前処理定義。 * @param scale 小数点以下桁数  * @return 自身のインスタンス */ public Calculator scale(int scale) { return scale(scale, RoundingMode.DOWN); } /** * 計算前処理定義。 * @param scale 小数点以下桁数 * @param mode 端数定義 */ public Calculator scale(int scale, RoundingMode mode) { this.scale = scale; this.mode = mode; return this; } /** * 計算前の端数処理定義をします。 * @param roundingAlways 計算の都度端数処理をする時はtrue */ public Calculator roundingAlways(boolean roundingAlways) { this.roundingAlways = roundingAlways; return this; } /** 与えた計算値を自身が保持する値に加えます。 */ public Calculator add(Number v) { try { add(new BigDecimal(v.toString())); } catch (NumberFormatException e) { } return this; } /** 与えた計算値を自身が保持する値に加えます。*/ public Calculator add(BigDecimal v) { value.set(rounding(value.get().add(v))); return this; } private BigDecimal rounding(BigDecimal v) { return roundingAlways ? v.setScale(scale, mode) : v; } /** 自身が保持する値へ与えた計算値を引きます。*/ public Calculator subtract(Number v) { try { subtract(new BigDecimal(v.toString())); } catch (NumberFormatException e) { } return this; } /** 自身が保持する値へ与えた計算値を引きます。 */ public Calculator subtract(BigDecimal v) { value.set(rounding(value.get().subtract(v))); return this; } /** 自身が保持する値へ与えた計算値を掛けます。*/ public Calculator multiply(Number v) { try { multiply(new BigDecimal(v.toString())); } catch (NumberFormatException e) { } return this; } /** 自身が保持する値へ与えた計算値を掛けます。*/ public Calculator multiply(BigDecimal v) { value.set(rounding(value.get().multiply(v))); return this; } /** 与えた計算値で自身が保持する値を割ります。*/ public Calculator divideBy(Number v) { try { divideBy(new BigDecimal(v.toString())); } catch (NumberFormatException e) { } return this; } /** 与えた計算値で自身が保持する値を割ります。*/ public Calculator divideBy(BigDecimal v) { BigDecimal ret = roundingAlways ? value.get().divide(v, scale, mode) : value.get().divide(v, defaultScale, mode); value.set(ret); return this; } /** 計算結果をint型で返します。*/ public int intValue() { return decimal().intValue(); } /** 計算結果をlong型で返します。*/ public long longValue() { return decimal().longValue(); } /** 計算結果をBigDecimal型で返します。*/ public BigDecimal decimal() { BigDecimal v = value.get(); return v != null ? v.setScale(scale, mode) : BigDecimal.ZERO; } /** 開始値0で初期化されたCalculator */ public static Calculator init() { return new Calculator(BigDecimal.ZERO); } /** * @param v 初期値 * @return 初期化されたCalculator */ public static Calculator of(Number v) { return new Calculator(v); } /** * @param v 初期値 * @return 初期化されたCalculator */ public static Calculator of(BigDecimal v) { return new Calculator(v); } }