杰瑞科技汇

Java Long与BigDecimal如何选择与转换?

Of course! This is a very common and important topic in Java, especially when dealing with financial or precise numerical calculations. Let's break down the differences, use cases, and how to convert between long and BigDecimal.

Java Long与BigDecimal如何选择与转换?-图1
(图片来源网络,侵删)

The Short Answer (TL;DR)

Feature long BigDecimal
Type Primitive Object (Reference Type)
Precision Fixed 64 bits (19 decimal digits) Arbitrary precision (limited by memory)
Scale Implicit (no decimal point concept) Explicit (you control the number of decimal places)
Performance Extremely Fast. Native CPU operations. Slower. Operates in software, involves object creation.
Use Case Counting, IDs, precise whole numbers. Money, financial calculations, scientific computing.
Immutability N/A Immutable. Operations return a new BigDecimal.

In-Depth Explanation

long - The Fast, Fixed-Precision Integer

A long is a primitive data type in Java. It's a 64-bit signed two's complement integer.

  • What it is: A whole number. No decimals.
  • Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 (approximately ±9 quintillion).
  • Key Characteristics:
    • Performance: It's the fastest way to handle large whole numbers because operations are handled directly by the CPU's integer arithmetic unit.
    • Precision: It has a fixed precision. If you try to store a number larger than its maximum value, it overflows, wrapping around to a negative number. This is a silent, dangerous bug.
    • No Decimals: You cannot represent fractional values with long.

Example of long Overflow

long maxLong = Long.MAX_VALUE; // 9,223,372,036,854,775,807
System.out.println("Max long: " + maxLong);
// This will overflow and become a negative number!
long overflowed = maxLong + 1;
System.out.println("After overflow: " + overflowed); // -9,223,372,036,854,775,808

When to use long:

  • For unique identifiers (e.g., database primary keys).
  • For counting things (e.g., number of items in a warehouse).
  • Any time you need high performance with whole numbers that are guaranteed to fit within its range.

BigDecimal - The Precise, Arbitrary-Precision Decimal

BigDecimal is a class in Java, part of the java.math package. It's designed for handling decimal numbers with absolute precision.

  • What it is: An object that represents an immutable, arbitrary-precision signed decimal number.
  • How it works: Internally, it stores a number as an unscaled integer and a scale. For example, the number 456 is stored as the unscaled integer 123456 and a scale of 3.
  • Key Characteristics:
    • Precision: This is its superpower. It can handle numbers with any number of digits before and after the decimal point, limited only by the amount of memory available. It never loses precision due to its internal representation.
    • Scale: You control the number of decimal places. This is crucial for financial calculations where you always want to work with cents (or the smallest currency unit).
    • Immutability: BigDecimal objects are immutable. Any operation (like adding, multiplying) does not change the existing object. Instead, it returns a new BigDecimal object with the result.
    • Performance: It is significantly slower than long or double because all operations are performed in software and involve creating new objects.

Why double is NOT a good choice for money

Many developers try to use double for money, but this is a common mistake.

Java Long与BigDecimal如何选择与转换?-图2
(图片来源网络,侵删)
// A classic example of floating-point inaccuracy
double price1 = 1.03;
double price2 = 0.42;
double total = price1 - price2;
// You expect 0.61, but...
System.out.println(total); // Prints 0.6100000000000001

This tiny error is unacceptable in financial systems. BigDecimal solves this completely.

BigDecimal bdPrice1 = new BigDecimal("1.03");
BigDecimal bdPrice2 = new BigDecimal("0.42");
BigDecimal bdTotal = bdPrice1.subtract(bdPrice2);
// The result is exact!
System.out.println(bdTotal); // Prints 0.61

Crucial Tip: Always create a BigDecimal from a String or an int/long. Never from a double, as you'll just be importing the floating-point inaccuracy into your BigDecimal.

// WRONG - this will have the same floating-point error
BigDecimal bad = new BigDecimal(0.1); // Creates BigDecimal("0.1000000000000000055511151231257827021181583404541015625")
// CORRECT - this is precise
BigDecimal good = new BigDecimal("0.1"); // Creates BigDecimal("0.1")

When to use BigDecimal:

  • Any financial calculation: currency, interest rates, invoices, taxes.
  • Scientific calculations where precision is paramount.
  • When you need to control the number of decimal places explicitly (e.g., rounding to 2 decimal places for currency).

Conversion and Operations

long to BigDecimal

This is straightforward and safe.

Java Long与BigDecimal如何选择与转换?-图3
(图片来源网络,侵删)
long myLong = 12345;
BigDecimal fromLong = BigDecimal.valueOf(myLong);
// Or, for older Java versions: new BigDecimal(myLong)
System.out.println(fromLong); // 12345

BigDecimal to long

You must decide how to handle the fractional part. You can round or truncate.

  • longValue(): Truncates the decimal part (rounds towards zero).
  • longValueExact(): Throws an ArithmeticException if there is a fractional part.
BigDecimal bigDecimal = new BigDecimal("123.98");
// Truncates the decimal part
long truncated = bigDecimal.longValue();
System.out.println("Truncated: " + truncated); // 123
// Throws an ArithmeticException because of the .98
try {
    long exact = bigDecimal.longValueExact();
} catch (ArithmeticException e) {
    System.out.println("Cannot convert to exact long: " + e.getMessage());
}

Common BigDecimal Operations

Remember, all operations return a new BigDecimal.

BigDecimal a = new BigDecimal("10.5");
BigDecimal b = new BigDecimal("2.0");
// Addition
BigDecimal sum = a.add(b);       // 12.5
// Subtraction
BigDecimal difference = a.subtract(b); // 8.5
// Multiplication
BigDecimal product = a.multiply(b); // 21.00
// Division (Requires a MathContext for precision)
// You MUST specify the scale (number of decimal places) and rounding mode.
BigDecimal quotient = a.divide(b, 2, RoundingMode.HALF_UP); // 5.25
// Rounding
BigDecimal toRound = new BigDecimal("10.567");
BigDecimal rounded = toRound.setScale(2, RoundingMode.HALF_UP); // 10.57

Summary: Which One Should I Use?

  • Use long if:

    • You are working with whole numbers only.
    • You need the absolute best performance.
    • You are certain the numbers will never exceed Long.MAX_VALUE.
    • Examples: AtomicLong counters, database IDs, array sizes.
  • Use BigDecimal if:

    • You are working with money or currency.
    • You need perfect precision and cannot afford any rounding errors.
    • You need to control the number of decimal places explicitly.
    • You are performing complex calculations where precision is more important than speed.
    • Examples: Calculating interest, invoice totals, tax amounts, scientific measurements.
分享:
扫描分享到社交APP
上一篇
下一篇