[Java] Use Big Decimal properly ~ 2018 ~

In Java9, the BigDecimal # ROUND_ ~ system has finally become @ Deprecated. Nevertheless, in blogs and entries that explain BigDecimal, when explaining BigDecimal # setScale, BigDecimal # divide, etc., it is explained usingBigDecimal # ROUND_ ~system. What do you mean? It's all @Deprecated in Java 9, right? I decided to write an article because I feel uncomfortable recently.

First of all, from the basics.

Generation / Factory method

Basic

It is basically generated by the following method.

BigDecimal value = BigDecimal.valueOf(1234.567);//Generation from a numerical system
BigDecimal value = new BigDecimal("1234.567");//Generated from a string

Since 0, 1, and 10 are already defined, use them.

BigDecimal.ZERO
BigDecimal.ONE
BigDecimal.TEN

Notes on generation from strings

Generation from a string is as specified by the string for scale.

System.out.println(new BigDecimal("1234.567").scale());  // → 3
System.out.println(new BigDecimal("1234.56700").scale());// → 5

NG pattern generated from numerical values

Use BigDecimal # valueOf to generate from a number (double). It would be ridiculous to generate it with new.

BigDecimal value = new BigDecimal(1234.567);// NG!!Generation from a numerical system
System.out.println(value);// → 1234.5670000000000072759576141834259033203125

ResultSet#getBigDecimal When getting from ResultSet, there is ResultSet # getBigDecimal, so use this.

BigDecimal value = rs.getBigDecimal("COL");

The following is useless, so NG

BigDecimal value = BigDecimal.valueOf(rs.getDouble("COL"));
BigDecimal value = new BigDecimal(rs.getString("COL"));

Four arithmetic operations

Addition

BigDecimal a = BigDecimal.valueOf(123);
BigDecimal b = BigDecimal.valueOf(456);

// value = a + b
BigDecimal value = a.add(b);

System.out.println(value);// 579

Subtraction

BigDecimal a = BigDecimal.valueOf(123);
BigDecimal b = BigDecimal.valueOf(456);

// value = a - b
BigDecimal value = a.subtract(b);

System.out.println(value);// -333

Multiply

BigDecimal a = BigDecimal.valueOf(123);
BigDecimal b = BigDecimal.valueOf(456);

// value = a * b
BigDecimal value = a.multiply(b);

System.out.println(value);// 56088

10 times, 100 times, etc.

Use BigDecimal # scaleByPowerOfTen.

BigDecimal src = BigDecimal.valueOf(0.123);
BigDecimal value = src.scaleByPowerOfTen(2);//Hundredfold(10 squared)
System.out.println(value);// 12.3

It's a lot cleaner than src.multiply (BigDecimal.valueOf (100)), and you don't have to create an instance of 100.

Negative (sign inversion)

Use BigDecimal # negate.

BigDecimal src = BigDecimal.valueOf(123);
BigDecimal value = src.negate();
System.out.println(value);// -123

Please stop writing the following.

BigDecimal value = src.multiply(BigDecimal.valueOf(-1));

division

import java.math.RoundingMode;
//・ ・ ・

BigDecimal a = BigDecimal.valueOf(123);
BigDecimal b = BigDecimal.valueOf(456);

// value = a / b
BigDecimal value = a.divide(b, 3 /* ← scale */, RoundingMode.HALF_UP /*← Rounding*/);

System.out.println(value);// 0.270

Methods that can be replaced with RoundingMode are not available

The following writing style is NG

BigDecimal value = a.divide(b, 3, BigDecimal.ROUND_HALF_UP);

For more information on Rounding Mode, please see [at the bottom](#rounding mode) for details.

Specify scale

There is also a BigDecimal # divide method that does not specify a scale, When it is not divisible, ʻArithmeticException will occur, so it is better to use the scale` specified version.

1/10, 1/100, etc.

Use BigDecimal # scaleByPowerOfTen.

BigDecimal src = BigDecimal.valueOf(8);
BigDecimal value = src.scaleByPowerOfTen(-2);// 1/100(10-Squared)
System.out.println(value);// 0.08

Rounding / Rounding / Rounding up

import java.math.RoundingMode;
//・ ・ ・


BigDecimal src = BigDecimal.valueOf(123.456);

//Rounding
BigDecimal value = src.setScale(2, RoundingMode.HALF_UP);
System.out.println(value); // → 123.46

//Round up
BigDecimal value = src.setScale(2, RoundingMode.UP);

//Truncate
BigDecimal value = src.setScale(2, RoundingMode.DOWN);

Methods that can be replaced with RoundingMode are not available

The following writing style is NG

BigDecimal value = src.setScale(2, BigDecimal.ROUND_HALF_UP);

For more information on Rounding Mode, please see [at the bottom](#rounding mode) for details.

Stringification

BigDecimal#toPlainString BigDecimal # toString can be exponential notation, so I think it's better to use BigDecimal # toPlainString.

BigDecimal value = new BigDecimal("0.0000001");
System.out.println(value.toString());     // → 1E-7
System.out.println(value.toPlainString());// → 0.0000001

jackson also has an option to use toPlainString. JsonGenerator.Feature.html#WRITE_BIGDECIMAL_AS_PLAIN

Remove 0 at the end of the decimal

Both BigDecimal # toString and BigDecimal # toPlainString take scale into the string and are retained even if the decimal number is followed by 0. If you want to turn this off, use BigDecimal # stripTrailingZeros. You don't have to work hard with regular expressions.

BigDecimal value = new BigDecimal("1.000000");
		
System.out.println(value);                     // → 1.000000
System.out.println(value.stripTrailingZeros());// → 1

ʻIntlong double`

BigDecimal value = BigDecimal.valueOf(12345);
int i = value.intValue();
long l = value.longValue();
double d = value.doubleValue();

There are also float and BigInteger.

Tolerance check version

There is a version of the conversion to integers that throws an exception when there is information that is lost out of tolerance. Conversely, the normal version is ignored even if information is lost.

int i = value.intValueExact();
long l = value.longValueExact();

There are also byte, short and BigInteger versions of the -ValueExact family of methods.

Match comparison

Normal comparison

Since BigDecimal # equals returns false if scale does not match, If you are writing a system that you are not interested in, such as scale, you should judge whether the result of compareTo matches 0.

BigDecimal value1 = new BigDecimal("123.0"); // scale=1
BigDecimal value2 = new BigDecimal("123.00");// scale=2

System.out.println(value1.equals(value2));        // false

System.out.println(value1.compareTo(value2) == 0);// true

Used for the key of HashMap

BigDecimal # equals BigDecimal # hashCode also considers scale, so Writing a system that you are not interested in, such as scale, may hurt you.

BigDecimal value1 = new BigDecimal("123.0"); // scale=1
BigDecimal value2 = new BigDecimal("123.00");// scale=2

Map<BigDecimal, String> map = new HashMap<>();
map.put(value1, "data");

System.out.println(map.get(value2));// null

In this case, you may want to stabilize scale with BigDecimal # stripTrailingZeros.

BigDecimal value1 = new BigDecimal("123.0"); // scale=1
BigDecimal value2 = new BigDecimal("123.00");// scale=2

Map<BigDecimal, String> map = new HashMap<>();
map.put(value1.stripTrailingZeros(), "data");

System.out.println(map.get(value2.stripTrailingZeros()));// data

RoundingMode

RoundingMode is defined by ʻenum`, and there are various things such as" rounding up "," rounding down "," rounding to positive infinity ", and" rounding to negative infinity "in addition to" rounding ", so once javadoc is done. I think you should check it.

The following is a transcription of Rounding Mode javadoc.

CEILING This mode rounds to approach positive infinity. DOWN This mode rounds to approach 0. FLOOR It is a mode to round so as to approach negative infinity. HALF_DOWN Rounding mode to round to the "closest number" (rounded down if the numbers on both sides are equidistant). HALF_EVEN Rounding mode to round to the "closest number" (however, if the numbers on both sides are equidistant, round to the even side). HALF_UP Rounding mode to round to the "closest number" (however, if the numbers on both sides are equidistant, they are rounded up). UNNECESSARY Rounding mode that indicates that the result of the required operation is accurate and does not require rounding. UP This mode rounds away from 0.

Methods that can be replaced with RoundingMode are not available

Do not use the BigDecimal # ROUND_ ~ system and the methods that assume the use of these. (@Deprecated in Java 9) There should be a pair of methods that use RoundingMode for each, so let's use these.

The method that became @Deprecated in 9 is a legacy of the 1.4 era. However, when I usually google for "BigDecimal division", I'm desperate because all the pages that use BigDecimal.ROUND_HALF_UP come out.

Recommended Posts

[Java] Use Big Decimal properly ~ 2018 ~
Java Big Decimal
How to use Big Decimal
[Java] Use Collectors.collectingAndThen
[Ruby] Big Decimal and DECIMAL
Big Decimal in Kotlin
Use OpenCV in Java
Use PreparedStatement in Java
[java] Decimal number → n-ary number n-ary number → decimal number
Use of Abstract Class and Interface properly in Java
Use Lambda Layers with Java
[Java] How to use Map
How to use java Optional
How to use java class
[Java] How to use Optional ②
[Java] How to use removeAll ()
[Java] How to use string.format
How to use Java Map
[java] Reasons to use static
How to use Java variables
Use Redis Stream in Java
CICS-Run Java applications-(5) Use JCICSX
Use SpatiaLite with Java / JDBC
[Java] How to use Optional ①
How to use Java HttpClient (Get)
Use java with MSYS and Cygwin
Use Microsoft Graph with standard Java
How to use Java HttpClient (Post)
[Java] How to use join method
Let's use Twilio in Java! (Introduction)
Use Azure Bing SpellCheck with Java
Use JDBC with Java and Scala.
[Java] Do not use "+" in append!
Use composite keys in Java Map.
Use Java 11 with Google Cloud Functions
[Java] How to use LinkedHashMap class
java (use class type for field)
Use Chrome Headless from Selenium / Java
[JavaFX] [Java8] How to use GridPane
[Note] Handling of Java decimal point
How to use class methods [Java]
[Java] How to use List [ArrayList]
How to use classes in Java?
[Processing × Java] How to use arrays
How to use Java lambda expressions
Do you use Stream in Java?
[Java] How to use Math class
How to use Java enum type
[Java] Tips and error issues when converting from double to Big Decimal
Prevent exponential notation (E) from appearing when toString of Java Big Decimal