Definition
- Identity for multiplication:
1, because1 * x == xand the empty product is 1. mapToLonggives aLongStreamfor more headroom before overflow.- Silent overflow:
longmultiplication wraps around with no exception. Math.multiplyExact: throwsArithmeticExceptionon overflow instead of wrapping.BigInteger: has no fixed range and cannot overflow at all.
Imagine a risk-model weight that multiplies a factor for each team member. Priya starts holding the number 1, then multiplies it by each person's age. The key is she starts at 1, not 0, because 0 would wipe everything out.
Understanding the Concepts
How do you multiply all ages with reduce?
package com.bank.hr;
import java.util.List;
public class ProductOfAges {
public static void main(String[] args) {
List<Employee> staff = List.of(
new Employee("Rajesh", 35),
new Employee("Priya", 30),
new Employee("Amit", 28),
new Employee("Kavita", 32));
long product = staff.stream()
.mapToLong(Employee::getAge)
.reduce(1L, (a, b) -> a * b);
System.out.println("Product of ages: " + product);
}
}
Product of ages: 940800
Why is the identity 1 and not 0?
| Identity | Effect | Correct? |
|---|---|---|
| 1 | 1 * 35 * 30 * 28 * 32 = 940800 | Yes |
| 0 | 0 * 35 * 30 * 28 * 32 = 0 | No! |
The identity must satisfy identity * x == x. For multiplication that is 1. Using 0 would make every product zero.
How do you guard against overflow?
// WRONG: silent overflow wraps to a wrong number
long product = staff.stream()
.mapToLong(Employee::getAge)
.reduce(1L, (a, b) -> a * b);
// If product exceeds Long.MAX_VALUE, wraps silently!
// CORRECT: Math.multiplyExact throws on overflow
long safeProduct = staff.stream()
.mapToLong(Employee::getAge)
.reduce(1L, Math::multiplyExact);
// Throws ArithmeticException if overflow occurs
What about BigInteger for large products?
import java.math.BigInteger;
BigInteger product = staff.stream()
.reduce(
BigInteger.ONE,
(acc, e) -> acc.multiply(BigInteger.valueOf(e.getAge())),
BigInteger::multiply);
System.out.println("BigInteger product: " + product);
BigInteger product: 940800
BigInteger has no fixed range and cannot overflow.
What are common mistakes?
Mistake: using 0 as the identity for multiplication.
// WRONG: 0 collapses the entire product to 0
long wrong = staff.stream()
.mapToLong(Employee::getAge)
.reduce(0L, (a, b) -> a * b);
// Always 0!
// CORRECT: identity for multiplication is 1
long correct = staff.stream()
.mapToLong(Employee::getAge)
.reduce(1L, (a, b) -> a * b);
What about an empty stream?
With identity 1L, an empty stream returns 1L, which is the mathematical convention for the empty product.
Why does this return a plain long and not Optional?
The identity form of reduce always has a value (the identity for empty streams), so it returns a plain long, not an OptionalLong. The no-identity form would return OptionalLong.
What should a senior engineer know?
- Multiplying many values grows exponentially; even a long can overflow for a moderate number of employees.
- In financial models, use
Math.multiplyExactto turn silent overflow into a loud exception. - For truly large products, use BigInteger.
- The accumulator must be associative for parallel correctness.
What are common interview follow-up questions?
- "Why not use 0 as the identity?" It collapses the entire product to 0.
- "How do you detect overflow?" Use
Math.multiplyExactwhich throws ArithmeticException. - "What happens with an empty stream?" Returns the identity (1).
Visual Overview
reduce(1L, (a, b) -> a * b) Step 1: 1 * 35 = 35 Step 2: 35 * 30 = 1050 Step 3: 1050 * 28 = 29400 Step 4: 29400 * 32 = 940800 Result: 940800 Overflow guard: Math.multiplyExact(a, b) → ArithmeticException if overflow BigInteger.multiply() → no overflow possible
Key Takeaway
To multiply all ages with reduce I use identity 1, never 0, because 1 is the neutral element for multiplication. I map ages to a LongStream and reduce with multiplication, which returns a plain long because the identity form always has a value.
The critical concern is overflow. Multiplying many values grows fast and silently wraps a long to a wrong number. I guard with Math.multiplyExact, which throws ArithmeticException on overflow, or switch to BigInteger which cannot overflow at all.
In my banking project at the National Bank of India this pattern computed a composite risk weight. I used the guarded version so overflow raised an alert instead of producing a nonsense number.
Remember one sentence: identity 1 for multiplication (not 0!), and guard against overflow with Math.multiplyExact or BigInteger.
---