Definition
- **Inclusive range** – `salary.compareTo(low) >= 0 && salary.compareTo(high) <= 0` keeps both endpoints.
- **BigDecimal for money** – never use `double` for boundary comparisons; floating-point loses precision.
- **Named constants** – define `LOW = new BigDecimal("40000")` and `HIGH = new BigDecimal("80000")`.
- **Reusable predicate** – `Predicate<Employee> inBand = e -> e.salary().compareTo(low) >= 0 && e.salary().compareTo(high) <= 0`.
- **Boundary precision** – inclusive means exactly 40,000 and exactly 80,000 both qualify.The HR manager at National Bank of India targets a mid-income personal-loan offer at employees earning between Rs.40,000 and Rs.80,000 inclusive. Someone earning exactly Rs.40,000 qualifies because the band includes both ends. Someone earning Rs.90,000 is out.
Understanding the Concepts
How do you filter a range with BigDecimal?
package com.bank.service;
import java.math.BigDecimal;
import java.util.List;
public class RangeFilterDemo {
record Employee(String name, String department, BigDecimal salary) {}
public static void main(String[] args) {
BigDecimal LOW = new BigDecimal("40000");
BigDecimal HIGH = new BigDecimal("80000");
List<Employee> staff = List.of(
new Employee("Rajesh", "IT", new BigDecimal("85000")),
new Employee("Priya", "Finance", new BigDecimal("72000")),
new Employee("Amit", "IT", new BigDecimal("40000")),
new Employee("Deepa", "HR", new BigDecimal("30000")),
new Employee("Vikram", "Finance", new BigDecimal("80000")),
new Employee("Neha", "Sales", new BigDecimal("55000"))
);
List<Employee> midBand = staff.stream()
.filter(e -> e.salary().compareTo(LOW) >= 0
&& e.salary().compareTo(HIGH) <= 0)
.toList();
midBand.forEach(e -> System.out.println(e.name() + ": Rs." + e.salary()));
}
}
Priya: Rs.72000
Amit: Rs.40000
Vikram: Rs.80000
Neha: Rs.55000
Amit (exactly 40,000) and Vikram (exactly 80,000) both qualify because the range is inclusive.
Why must you use BigDecimal for money ranges?
// WRONG: double loses precision at boundaries
double salary = 40000.00;
System.out.println(salary >= 40000.00); // may be unreliable for edge values
// CORRECT: BigDecimal compares exactly
BigDecimal salary = new BigDecimal("40000.00");
System.out.println(salary.compareTo(new BigDecimal("40000")) >= 0); // true, always correct
What is the difference between inclusive and exclusive ranges?
| Range type | Lower | Upper | 40,000 in? | 80,000 in? | |------------|-------|-------|------------|------------| | Inclusive `[40K, 80K]` | `>= 0` | `<= 0` | Yes | Yes | | Exclusive `(40K, 80K)` | `> 0` | `< 0` | No | No | | Half-open `[40K, 80K)` | `>= 0` | `< 0` | Yes | No | | Half-open `(40K, 80K]` | `> 0` | `<= 0` | No | Yes |
How do you extract a reusable range predicate?
import java.math.BigDecimal;
import java.util.function.Predicate;
public class SalaryPredicates {
public static Predicate<Employee> salaryBetween(BigDecimal low, BigDecimal high) {
return e -> e.salary().compareTo(low) >= 0
&& e.salary().compareTo(high) <= 0;
}
}
// Usage:
List<Employee> midBand = staff.stream()
.filter(SalaryPredicates.salaryBetween(
new BigDecimal("40000"), new BigDecimal("80000")))
.toList();
The same range logic applies to loan tiers, tax slabs, and bonus bands.
What are common mistakes?
// WRONG: using exclusive when inclusive is required
staff.stream().filter(e -> e.salary().compareTo(LOW) > 0
&& e.salary().compareTo(HIGH) < 0);
// Excludes exactly 40,000 and exactly 80,000!
// CORRECT: inclusive boundaries
staff.stream().filter(e -> e.salary().compareTo(LOW) >= 0
&& e.salary().compareTo(HIGH) <= 0);
// WRONG: using double for money
staff.stream().filter(e -> e.getSalaryDouble() >= 40000 && e.getSalaryDouble() <= 80000);
// CORRECT: using BigDecimal
staff.stream().filter(e -> e.salary().compareTo(LOW) >= 0 && e.salary().compareTo(HIGH) <= 0);
What are edge cases?
- Exactly on lower bound: Rs.40,000 qualifies with
>= 0. - Exactly on upper bound: Rs.80,000 qualifies with
<= 0. - Below lower bound: Rs.30,000 fails the first check.
- Above upper bound: Rs.85,000 fails the second check.
- Null salary: guard with
e.salary() != null &&before compareTo. - Inverted bounds: if low > high, no element can satisfy both conditions.
What about using Predicate combinators?
Predicate<Employee> atLeast40K = e -> e.salary().compareTo(new BigDecimal("40000")) >= 0;
Predicate<Employee> atMost80K = e -> e.salary().compareTo(new BigDecimal("80000")) <= 0;
List<Employee> midBand = staff.stream()
.filter(atLeast40K.and(atMost80K))
.toList();
What should a senior engineer know?
- Define bounds as named constants or configuration values to avoid magic numbers.
- The same mid-band logic reappears for loan eligibility, tax slabs, and bonus tiers. Extract it into a reusable utility.
- In production, push range conditions to database WHERE clauses for large employee tables.
- BigDecimal scale matters:
new BigDecimal("40000")andnew BigDecimal("40000.00")are equal by compareTo but not by equals. Use compareTo for range checks.
Visual Overview
Inclusive range filter [40000, 80000]: ───────────────────────────────────── Rajesh: 85000 >= 40K ✓ <= 80K ✗ → discard Priya: 72000 >= 40K ✓ <= 80K ✓ → keep Amit: 40000 >= 40K ✓ <= 80K ✓ → keep (boundary included) Deepa: 30000 >= 40K ✗ → discard (short-circuit) Vikram: 80000 >= 40K ✓ <= 80K ✓ → keep (boundary included) Neha: 55000 >= 40K ✓ <= 80K ✓ → keep Result: [Priya, Amit, Vikram, Neha]
Key Takeaway
An inclusive range check joins two comparisons with AND: the value must be at least the lower bound and at most the upper bound. Both endpoints qualify. Getting the boundary wrong is one of the most common interview mistakes and in banking could wrongly include or exclude a customer from a product tier.
Always use BigDecimal and its compareTo method for money ranges. Double and float lose precision at boundaries. Define bounds as named constants and extract the range predicate into a reusable function because the same band logic applies to loan tiers, tax slabs, and bonus bands.
BigDecimal.compareTo returns >= 0 for at-least and <= 0 for at-most. In production, push range conditions to database WHERE clauses for large datasets.
Remember one sentence: inclusive range uses compareTo >= 0 for the lower bound and <= 0 for the upper bound, and always use BigDecimal for money.
---