Interview question
Implement an immutable USD money value object in Java
Builds a small immutable money type with explicit scale, rounding, arithmetic, ordering, and value equality.
TL;DR
Builds a small immutable money type with explicit scale, rounding, arithmetic, ordering, and value equality.
Java records, BigDecimal scale, construction invariants, value equality, immutability, and domain-focused tests.
Practice the problem like a real interview: restate, reason, implement, and test.
Implement UsdMoney as an immutable Java value object. It must store exactly two decimal places, reject values that require implicit rounding, support addition and comparison, and compare by monetary value. Do not use double, expose mutable state, or silently choose a business rounding rule.
Next in Java & Spring Practical Labs: Single-flight loads by key
new UsdMoney(new BigDecimal("12.30")) -> $12.30
$12.30 + $0.70 -> $13.00
new BigDecimal("1.005") -> rejected
UsdMoney.of("2.0").equals(UsdMoney.of("2.00")) -> true
BigDecimal, never double or float.null, negative amounts, and values that need rounding.setScale(2, RoundingMode.UNNECESSARY); this accepts 2.0 but rejects 1.005.UsdMoney, so the same invariant is reused.BigDecimal.compareTo for ordering and test equality separately.import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Objects;
public record UsdMoney(BigDecimal amount)
implements Comparable<UsdMoney> {
public UsdMoney {
Objects.requireNonNull(amount, "amount");
amount = amount.setScale(2, RoundingMode.UNNECESSARY);
if (amount.signum() < 0) {
throw new IllegalArgumentException("amount must be non-negative");
}
}
public static UsdMoney of(String amount) {
return new UsdMoney(new BigDecimal(amount));
}
public UsdMoney add(UsdMoney other) {
Objects.requireNonNull(other, "other");
return new UsdMoney(amount.add(other.amount));
}
@Override
public int compareTo(UsdMoney other) {
Objects.requireNonNull(other, "other");
return amount.compareTo(other.amount);
}
}
Construction and addition are O(n) in the number of decimal digits handled by BigDecimal; comparison is also proportional to numeric representation size. The object itself stores one immutable reference.
2, 2.0, and 2.00 normalize to the same record value.1.005 is rejected instead of being rounded without a stated rule.equals and hashCode agree.add leaves both operands unchanged.BigDecimal.equals before normalization makes 2.0 and 2.00 unequal.HALF_UP silently invents a rounding policy the problem did not authorize.double introduces binary floating-point error before BigDecimal receives the value.Spot a weak answer, missing edge case, or clearer explanation? Send it in.
Say thanks with a standalone, one-time $5 contribution. No account required.