Comprehensive Guide to Java BigDecimal: Constructors, Methods, Formatting, and Common Pitfalls
This article explains Java's BigDecimal class, covering its purpose for high‑precision arithmetic, the most frequently used constructors, essential instance methods, comparison techniques, formatting with NumberFormat, handling of division exceptions, and a utility class that wraps common operations, all illustrated with concrete code examples.
Java provides the java.math.BigDecimal class for precise arithmetic beyond the 16‑digit limit of primitive double . It is essential when exact decimal results are required, such as financial calculations, because Double.valueOf(String) and Float.valueOf(String) lose precision.
BigDecimal objects cannot be manipulated with the usual arithmetic operators; instead, you must call the corresponding methods, and all method arguments must also be BigDecimal instances.
Common Constructors
The most frequently used constructors are:
BigDecimal(int) – creates an instance from an integer value.
BigDecimal(double) – creates an instance from a double value (may introduce hidden precision errors).
BigDecimal(long) – creates an instance from a long value.
BigDecimal(String) – creates an instance from a string representation; this is the most predictable way to obtain the exact decimal you expect.
Usage Example and Precision Issue
BigDecimal a = new BigDecimal(0.1);
System.out.println("a values is:" + a);
System.out.println("=====================");
BigDecimal b = new BigDecimal("0.1");
System.out.println("b values is:" + b);Output:
a values is:0.1000000000000000055511151231257827021181583404541015625
=====================
b values is:0.1Explanation:
Using the double constructor produces a value that reflects the binary representation of 0.1, which cannot be represented exactly.
The String constructor yields the exact decimal 0.1, so it is generally recommended.
If a double must be the source, use BigDecimal.valueOf(double) for a more predictable conversion.
Common Instance Methods
Typical arithmetic methods include:
add(BigDecimal) – addition.
subtract(BigDecimal) – subtraction.
multiply(BigDecimal) – multiplication.
divide(BigDecimal) – division (may throw ArithmeticException if the result is non‑terminating).
toString() – converts the value to a string.
doubleValue() , floatValue() , longValue() , intValue() – converts to primitive types.
Comparing BigDecimal Values
Use compareTo to compare two instances:
int result = bigDecimal1.compareTo(bigDecimal2);The result is -1 if the first is smaller, 0 if equal, and 1 if larger. Example:
new BigDecimal(a).compareTo(new BigDecimal(b)) >= 0Formatting with NumberFormat
Because NumberFormat.format() accepts a BigDecimal , you can format monetary or percentage values that exceed 16 significant digits.
NumberFormat currency = NumberFormat.getCurrencyInstance();
NumberFormat percent = NumberFormat.getPercentInstance();
percent.setMaximumFractionDigits(3);
BigDecimal loanAmount = new BigDecimal("15000.48");
BigDecimal interestRate = new BigDecimal("0.008");
BigDecimal interest = loanAmount.multiply(interestRate);
System.out.println("贷款金额:\t" + currency.format(loanAmount));
System.out.println("利率:\t" + percent.format(interestRate));
System.out.println("利息:\t" + currency.format(interest));Result (example):
贷款金额: ¥15,000.48 利率: 0.8% 利息: ¥120.00Formatting Helper Method
public static String formatToNumber(BigDecimal obj) {
DecimalFormat df = new DecimalFormat("#.00");
if (obj.compareTo(BigDecimal.ZERO) == 0) {
return "0.00";
} else if (obj.compareTo(BigDecimal.ZERO) > 0 && obj.compareTo(new BigDecimal(1)) < 0) {
return "0" + df.format(obj).toString();
} else {
return df.format(obj).toString();
}
}Calling this method with various BigDecimal values yields:
3.44
0.00
0.00
0.00
0.01
0.21Division Exceptions
When dividing with divide() and the result is a non‑terminating decimal, Java throws java.lang.ArithmeticException: Non‑terminating decimal expansion; no exact representable decimal result . Provide a scale to avoid the exception, e.g., divide(divisor, 2) .
Utility Class for Common Operations
package com.vivo.ars.util;
import java.math.BigDecimal;
public class ArithmeticUtils {
private static final int DEF_DIV_SCALE = 10;
public static double add(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}
public static BigDecimal add(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.add(b2);
}
public static String add(String v1, String v2, int scale) {
if (scale < 0) throw new IllegalArgumentException("The scale must be a positive integer or zero");
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.add(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
}
// ... (similar methods for sub, mul, div, round, remainder, compare) ...
}The class provides static methods for addition, subtraction, multiplication, division, rounding, remainder calculation, and comparison, handling both double and String inputs and allowing a configurable scale.
Summary
Use BigDecimal only when exact decimal arithmetic is required; it is slower than double / float .
Prefer the String constructor to avoid hidden precision errors.
Remember that BigDecimal is immutable; each arithmetic operation returns a new instance that must be stored.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.