Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
279: BigInteger and BigDecimal for Precise Arithmetic
Why can't I just use double or float for money?
This is the first question everyone asks, and it's a fair one. Why bother with clunky classes when you have double? The problem is that floating-point numbers are stored in binary, and some decimal fractions—like 0.1—cannot be represented exactly in binary. It's similar to how 1/3 becomes 0.333... in decimal; it never quite ends.
If you're building a banking app and you add 0.1 to a balance ten thousand times using a double, you'll eventually see a weird result like 1000.00000000015. In a professional setting, that's a bug that gets you a stern talking-to from the auditing team. I've seen it happen in production systems where "ghost pennies" appeared out of nowhere because someone used double for currency. That's where BigDecimal comes in; it stores numbers as an arbitrary-precision integer and a scale, meaning it treats the number exactly as you wrote it.
// The "Double Trap"
double price = 0.1;
double total = price + price + price;
System.out.println(total); // Might print 0.30000000000000004
// The Precise Way
BigDecimal precisePrice = new BigDecimal("0.1");
BigDecimal preciseTotal = precisePrice.add(precisePrice).add(precisePrice);
System.out.println(preciseTotal); // Prints exactly 0.3
How do I actually do math if I can't use + or *?
It's a bit of a shock the first time you try to use + with a BigDecimal and the compiler screams at you. Because these are objects and not primitives, you have to use method calls. It feels verbose at first, but it's the price we pay for precision.
One thing you absolutely cannot forget: BigDecimal and BigInteger are immutable. I've seen plenty of juniors write balance.add(deposit) and then wonder why the balance didn't change. The add() method doesn't modify the existing object; it returns a brand new one. You have to assign that result back to a variable.
BigDecimal balance = new BigDecimal("100.00");
BigDecimal deposit = new BigDecimal("50.50");
// WRONG: This does nothing to the balance variable
balance.add(deposit);
// RIGHT: Assign the result to the variable
balance = balance.add(deposit);
BigDecimal multiplier = new BigDecimal("1.05"); // 5% interest
balance = balance.multiply(multiplier);
What is this ArithmeticException during division?
If you try to divide 1 by 3 using BigDecimal without specifying how to handle the remainder, Java will throw an ArithmeticException. Why? Because 1/3 is a non-terminating decimal. Java refuses to guess how many decimal places you want; it would rather crash than give you an imprecise answer.
To fix this, you have to provide a RoundingMode. I usually recommend HALF_UP for financial applications—that's the standard "round .5 up" logic we all learned in school. You can also use FLOOR or CEILING depending on whether you're calculating something like a tax bracket where you must always round in a specific direction.
BigDecimal one = new BigDecimal("1");
BigDecimal three = new BigDecimal("3");
// This would throw: ArithmeticException: Non-terminating decimal expansion
// BigDecimal result = one.divide(three);
// This is the professional way: 2 decimal places, rounding half up
BigDecimal result = one.divide(three, 2, RoundingMode.HALF_UP);
System.out.println(result); // 0.33
When should I use BigInteger instead of BigDecimal?
Simple: use BigInteger when you don't have a decimal point but your numbers are larger than what a long can handle (roughly 9 quintillion). You'll rarely need this in a standard business CRUD app, but it's essential for cryptography, hashing algorithms, or scientific simulations.
For example, if you're implementing an RSA encryption algorithm, you're dealing with prime numbers that are hundreds of digits long. A long would overflow instantly. BigInteger will keep growing as long as your computer has RAM to support it.
// A number way too big for a long
BigInteger massiveNumber = new BigInteger("9223372036854775808123456789");
BigInteger anotherHugeOne = new BigInteger("12345678901234567890");
BigInteger product = massiveNumber.multiply(anotherHugeOne);
System.out.println("The result is far too large for any primitive: " + product);
📋 Practical Task
Exercise: Building a Precise Invoice Calculator
You are tasked with creating a small utility that calculates the final total for a customer invoice. You must ensure that no precision is lost during the calculation of discounts and taxes.
Requirements:
- Start with a subtotal of
1250.75. - Apply a discount of
15%(multiply by 0.85). - Apply a sales tax of
8.25%to the discounted amount. - The final result must be rounded to exactly 2 decimal places using
RoundingMode.HALF_UP. - Use
BigDecimalfor all calculations. Do not usedoubleorfloatat any point in the logic.
Expected Output: Your program should print the final total formatted to two decimal places.
There are no comments for now.