Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a custom BigDecimal type

In my application, all BigDecimal numbers are scaled to have two decimal places.. In other words, everytime I create a new BigDecimal in my code, I need to use the method scale too:

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

So, to minimize the work, I wanted to create my custom BigDecimal type, something like:

public class CustomBigDecimal extends BigDecimal {

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

}

I know this.setScale(2, RoundingMode.HALF_UP); doesn't do the job, but I can't find the way to do it, is it possible?

like image 382
yat0 Avatar asked Mar 10 '15 16:03

yat0


People also ask

What is BigDecimal data type?

A BigDecimal consists of an arbitrary precision integer unscaled value and a 32-bit integer scale. If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale.

How do I assign a value to BigDecimal?

In order to add a BigDecimal to another BigDecimal, use add(BigDecimal augend) API method, that returns a BigDecimal whose value is (this + augend), and whose scale is max(this. scale(), augend.

What can I use instead of BigDecimal?

If you need to use division in your arithmetic, you need to use double instead of BigDecimal.

Why use BigDecimal instead of double in Java?

The BigDecimal(String) constructor should always be preferred over BigDecimal(Double) because using BigDecimal(double) is unpredictable due to the inability of the double to represent 0.1 as exact 0.1.


2 Answers

You could simply create a method for yourself that creates a BigDecimal with zero. Something like:

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

Put it in a helper class, like BigDecimalHelper, BigDecimalFactory or whatever. :)

EDIT: Changed it slightly to return the results of setScale, since BigDecimal is immutable. And to further answer the original question: no what you've written is not possible since the state of the object is not changed with setScale().

like image 117
Marcus Widegren Avatar answered Sep 22 '22 05:09

Marcus Widegren


You could create a CustomBigDecimal that extends from BigDecimal. However, as BigDecimal is immutable, you would never inherit state (such as the scale and rounding mode) from the parent class.

I'd go for the utility class suggested in another answer, or maybe a wrapper that delegates every operation to an actual BigDecimal instance. The downside of this approach is that your brand new CustomBigDecimal wouldn't be a BigDecimal, so they wouldn't be interchangeable.

EDIT: a downside of this approach is that you have to delegate about 50 methods. Not the end of the world with a good IDE, but definitely not very appealing...

If, after all, you still want to make CustomBigDecimal inherit from BigDecimal, you'd need to use a decorator approach:

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

}
like image 21
fps Avatar answered Sep 22 '22 05:09

fps