Создание настраиваемого типа BigDecimal

В моем приложении все значения BigDecimal масштабируются, чтобы иметь два десятичных знака.. Другими словами, каждый раз, когда я создаю новый BigDecimal в своем коде, мне также нужно использовать масштаб метода:

BigDecimal x = BigDecimal.ZERO;
x.setScale(2, RoundingMode.HALF_UP);

Итак, чтобы свести к минимуму работу, я хотел создать свой собственный тип BigDecimal, например:

public class CustomBigDecimal extends BigDecimal {

    public CustomBigDecimal(String val) {
        super(val);
        this.setScale(2, RoundingMode.HALF_UP);
    }

}

Я знаю, что this.setScale(2, RoundingMode.HALF_UP); не выполняет эту работу, но я не могу найти способ сделать это, возможно ли это?

Ответы

Ответ 1

Вы можете создать CustomBigDecimal, который простирается от BigDecimal. Однако, поскольку BigDecimal неизменен, вы никогда не наследуете состояние (например, масштаб и режим округления) от родительского класса.

Я бы пошел на класс утилиты, предложенный в другом ответе, или, может быть, в оболочку, которая делегирует каждую операцию фактическому экземпляру BigDecimal. Недостатком этого подхода является то, что ваш новый CustomBigDecimal не будет BigDecimal, поэтому они не будут взаимозаменяемыми.

EDIT: недостатком этого подхода является то, что вы должны делегировать около 50 методов. Не конец света с хорошей IDE, но определенно не очень привлекательный...

Если вы все равно хотите сделать наследование CustomBigDecimal с BigDecimal, вам нужно будет использовать подход декоратора:

public class CustomBigDecimal extends BigDecimal {

    private final BigDecimal value;

    private CustomBigDecimal(BigDecimal value) {
        super(value.toPlainString()); // needed to compile, 
                                      // useless except for implicit null-check
        this.value = value;
    }

    public CustomBigDecimal(String val) {
        this(new BigDecimal(val).setScale(2, RoundingMode.HALF_UP));
    }

    @Override
    public CustomBigDecimal abs() {
        return new CustomBigDecimal(this.value.abs());
    }

    // TODO all other methods

}

Ответ 2

Вы можете просто создать для себя метод, который создает BigDecimal с нулем. Что-то вроде:

public static BigDecimal scaled(String val) {
    BigDecimal x = new BigDecimal(val);
    return x.setScale(2, RoundingMode.HALF_UP);
}

Поместите его в класс-помощник, например BigDecimalHelper, BigDecimalFactory или что-то еще.:)

EDIT: немного изменил его, чтобы вернуть результаты setScale, так как BigDecimal является неизменным. И для дальнейшего ответа на исходный вопрос: никакое то, что вы написали, невозможно, так как состояние объекта не изменяется с помощью setScale().

Ответ 3

Вы можете хранить экземпляр singleton MathContext, например, и использовать их в качестве аргумента для BigDecimal Constructor.

Обычно вы можете делать:

MathContext context = new MathContext(2, RoundingMode.HALF_UP);
BigDecimal number = new BigDecimal(val, context);

Итак, если у вас есть MathContext как singleton, вы можете сделать:

BigDecimal number = new BigDecimal(val, MathInstanceHolder.getMathContext());

Где MathInstanceHolder содержит экземпляр MathContext.

Ответ 4

Просто чтобы быть другим и использовать Java 8 - вы также можете пойти лямбда на проблему:

public static Function<String, BigDecimal> SCALED_BIG_DECIMAL = (val) -> new BigDecimal(val).setScale(2, RoundingMode.HALF_UP);
...

// and this is how you would use it
SCALED_BIG_DECIMAL.apply("20.2343425")