Back to Operators & Expressions
Q9Question 9 of 9

How do you detect and avoid integer overflow?

Key Concepts
  • Java integer arithmetic wraps silently on overflow – Integer.MAX_VALUE + 1 = Integer.MIN_VALUE
  • No exception is thrown by default – overflow is a silent, hard-to-detect bug
  • Math.addExact(), Math.multiplyExact(), Math.subtractExact() throw ArithmeticException on overflow
  • Use long instead of int when values can exceed 2 billion
  • Use BigInteger for arbitrarily large integers, BigDecimal for exact money arithmetic
  • In banking, silent overflow can produce wrong balances, duplicate sequence IDs, and negative counters

Definition

Java integer overflow wraps silently with no exception. Use Math.addExact() to throw on overflow, long for large values, and BigDecimal for money.

The problem and the solutions:

  • The problem. When an int operation exceeds Integer.MAX_VALUE (2,147,483,647), the result wraps to Integer.MIN_VALUE (-2,147,483,648) with no warning.
  • Detection. Math.addExact(), Math.subtractExact(), Math.multiplyExact() throw ArithmeticException on overflow.
  • Prevention. Use long (range up to 9.2 quintillion), BigInteger (unlimited), or BigDecimal (exact decimals).

An odometer that goes from 999,999 back to 000,000 without a warning light. If a bank counter wraps like this, sequence numbers repeat, balances go negative, and nobody knows until the audit. Math.addExact() is the warning light that stops the engine instead of letting it wrap.

Understanding the Concepts

What happens on integer overflow?

JAVA
int max = Integer.MAX_VALUE;   // 2,147,483,647
int overflowed = max + 1;      // -2,147,483,648 (wraps to MIN_VALUE!)

System.out.println(max);        // 2147483647
System.out.println(overflowed); // -2147483648 (no exception, no warning)
System.out.println(max + max);  // -2 (silently wrong)

Java does not throw an exception. The result is silently wrong. This is one of the most dangerous behaviors in banking code.

Why is this dangerous in banking?

JAVA
// Scenario: transaction counter wraps from MAX_VALUE to MIN_VALUE
int txnCounter = Integer.MAX_VALUE;
txnCounter++;  // -2147483648 → next sequence ID is negative!

// Scenario: adding two large balances overflows
int balanceA = 1_500_000_000;  // 1.5 billion
int balanceB = 1_000_000_000;  // 1.0 billion
int total = balanceA + balanceB; // -794967296 (WRONG!)

Silent overflow can produce:

  • Negative balances that pass validation ("balance > 0" is false)
  • Duplicate sequence IDs when a counter wraps
  • Incorrect totals in batch reports

How do you detect overflow with Math.addExact?

JAVA
try {
    int safe = Math.addExact(Integer.MAX_VALUE, 1);
} catch (ArithmeticException e) {
    System.out.println("Caught: " + e.getMessage());  // integer overflow
}

try {
    long safe = Math.multiplyExact(Long.MAX_VALUE, 2);
} catch (ArithmeticException e) {
    System.out.println("Caught: " + e.getMessage());  // long overflow
}

// Available methods:
// Math.addExact(int, int) / Math.addExact(long, long)
// Math.subtractExact(int, int) / Math.subtractExact(long, long)
// Math.multiplyExact(int, int) / Math.multiplyExact(long, long)
// Math.incrementExact(int) / Math.incrementExact(long)
// Math.decrementExact(int) / Math.decrementExact(long)
// Math.negateExact(int) / Math.negateExact(long)
// Math.toIntExact(long) – throws if long does not fit in int

How do you prevent overflow by using larger types?

JAVA
// Use long instead of int for large values
long balanceA = 1_500_000_000L;
long balanceB = 1_000_000_000L;
long total = balanceA + balanceB;  // 2,500,000,000 (correct)

// Use BigInteger for arbitrarily large values
import java.math.BigInteger;
BigInteger huge = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE);
System.out.println(huge);  // 9223372036854775808 (no overflow, ever)

// Use BigDecimal for money
import java.math.BigDecimal;
BigDecimal total2 = new BigDecimal("1500000000")
    .add(new BigDecimal("1000000000"));
System.out.println(total2);  // 2500000000 (exact)

How do you check before the operation?

JAVA
// Manual check: will a + b overflow?
public static int safeAdd(int a, int b) {
    if (b > 0 && a > Integer.MAX_VALUE - b) {
        throw new ArithmeticException("Overflow: " + a + " + " + b);
    }
    if (b < 0 && a < Integer.MIN_VALUE - b) {
        throw new ArithmeticException("Underflow: " + a + " + " + b);
    }
    return a + b;
}

// But Math.addExact does this for you – just use it

What about long overflow?

long can also overflow, just at a much larger range.

JAVA
long maxLong = Long.MAX_VALUE;  // 9,223,372,036,854,775,807
long overflowed = maxLong + 1;  // -9,223,372,036,854,775,808

try {
    long safe = Math.addExact(Long.MAX_VALUE, 1);
} catch (ArithmeticException e) {
    System.out.println("Long overflow caught");
}

If your values can exceed even long range (very rare in banking), use BigInteger.

What about multiplication overflow?

Multiplication is especially dangerous because small-looking numbers can overflow:

JAVA
int a = 100_000;
int b = 100_000;
int product = a * b;  // 1410065408 (WRONG! should be 10,000,000,000)

long correct = (long) a * b;  // 10000000000 (correct: one operand cast to long)

try {
    int safe = Math.multiplyExact(a, b);  // throws ArithmeticException
} catch (ArithmeticException e) {
    System.out.println("Multiplication overflow");
}

What are common mistakes?

  • Assuming int is big enough for money. Indian bank accounts can hold crores. 100 crore = 1 billion, which fits in int, but 300 crore = 3 billion, which overflows. Always use long or BigDecimal for money.
  • Counter wrapping. An int counter that increments once per transaction wraps after ~2 billion transactions. Use long.
  • Ignoring Math.addExact in non-critical code. Overflow bugs are silent and can hide for months until the right values trigger them.
  • Casting long to int without checking. (int) longValue silently truncates. Use Math.toIntExact(longValue) which throws on overflow.

What should a senior engineer know?

  • Compilers and static analyzers do not catch overflow. javac happily compiles Integer.MAX_VALUE + 1. It is not a compile error.
  • FindBugs/SpotBugs has rules like INT_OVERFLOW that detect potential overflow. Enable in CI.
  • In Kotlin, Int.plus() also wraps. But Kotlin's Long type is the same 64-bit as Java's.
  • In databases, use BIGINT for counters. PostgreSQL INT maxes at ~2 billion. BIGINT handles ~9.2 quintillion.
  • Java 8+ added all the Exact methods. Before Java 8, you had to write manual overflow checks.

Visual Overview

DIAGRAM
  Integer overflow:
    MAX_VALUE + 1  →  MIN_VALUE  (wraps, no exception)
    100000 * 100000 →  1410065408  (wrong, no exception)

  Detection:
    Math.addExact(MAX, 1)       → ArithmeticException
    Math.multiplyExact(a, b)    → ArithmeticException
    Math.toIntExact(longValue)  → ArithmeticException if too large

  Prevention:
    Use long:       max ~9.2 quintillion (enough for most banking)
    Use BigInteger: unlimited (rare need)
    Use BigDecimal: exact decimals (money)

  Decision tree:
    Value < 2 billion?   → int is safe
    Value < 9.2E18?      → long is safe
    Value can be larger?  → BigInteger
    Money?               → BigDecimal (always)

Key Takeaway

Java integer arithmetic wraps silently on overflow. Integer.MAX_VALUE plus one does not throw an exception – it quietly becomes Integer.MIN_VALUE. This is one of the most dangerous behaviors in banking code because it can produce wrong balances, duplicate sequence IDs, and negative counters with no visible error.

The detection tool is Math.addExact(), Math.multiplyExact(), and their siblings, all added in Java 8. They throw ArithmeticException when the result would overflow, giving you a loud failure instead of a silent wrong answer. Use them in any calculation where overflow could produce a wrong monetary value.

The prevention strategy is to use the right type. Use long (up to 9.2 quintillion) for counters and large values. Use BigDecimal for all money arithmetic. Use BigInteger for the rare cases where even long is not enough. And when casting a long to an int, use Math.toIntExact() instead of a raw cast to catch overflow.

One sentence to remember: Java integer overflow wraps silently with no exception – use Math.addExact() to detect it, long for large values, and BigDecimal for money.

---

Share
Use ← → arrow keys to navigate