Definition
- map(String::valueOf) converts each integer to its decimal string.
- filter(startsWith(digit)) keeps strings beginning with the target digit.
- Negative sign: negative numbers start with '-', not a digit; decide whether to strip the sign.
- Numeric alternative: compute the leading digit with repeated division to avoid string allocations.
- Map back: use
Integer.parseIntto return numeric results after text-based filtering.
Priya at the National Bank of India filters account numbers that begin with a particular branch-prefix digit. She writes each number as text, checks whether it starts with the digit '1', and keeps the matching ones.
Understanding the Concepts
What does this question ask?
The interviewer wants you to filter integers by their leading digit using string conversion. This tests map between types, startsWith, and awareness of the sign issue.
How do you filter numbers by leading digit?
package com.bank.core;
import java.util.List;
public class LeadingDigitFilter {
public static void main(String[] args) {
List<Integer> accountNumbers = List.of(
1001, 2345, 1502, 3001, 1999, 4500, 1100);
List<String> startsWith1 = accountNumbers.stream()
.map(String::valueOf)
.filter(s -> s.startsWith("1"))
.toList();
System.out.println("Starting with 1: " + startsWith1);
}
}
Starting with 1: [1001, 1502, 1999, 1100]
How do you get numeric results back?
List<Integer> numericResults = accountNumbers.stream()
.map(String::valueOf)
.filter(s -> s.startsWith("1"))
.map(Integer::parseInt)
.toList();
Or avoid the double conversion by filtering in string form and keeping a reference:
List<Integer> efficient = accountNumbers.stream()
.filter(n -> String.valueOf(n).startsWith("1"))
.toList();
How do you handle negative numbers?
List<Integer> mixed = List.of(100, -150, 200, -175);
// Negatives start with '-', not a digit
List<String> withSign = mixed.stream()
.map(String::valueOf)
.filter(s -> s.startsWith("1"))
.toList();
System.out.println(withSign); // [100] -- -150 excluded!
// Strip sign for absolute value comparison
List<Integer> ignoreSign = mixed.stream()
.filter(n -> String.valueOf(Math.abs(n)).startsWith("1"))
.toList();
System.out.println(ignoreSign); // [100, -150, -175]
What is the numeric alternative without string conversion?
public static int leadingDigit(int n) {
n = Math.abs(n);
while (n >= 10) {
n /= 10;
}
return n;
}
List<Integer> numeric = accountNumbers.stream()
.filter(n -> leadingDigit(n) == 1)
.toList();
This avoids creating a string per element, which matters on hot paths with large lists.
How is this related to Benford's Law?
In many real-world numeric datasets, the leading digit '1' appears about 30% of the time (not the expected 11%). This is Benford's Law. Filtering by leading digit and counting the distribution can detect anomalies or fabricated data.
import java.util.stream.Collectors;
var distribution = accountNumbers.stream()
.map(n -> String.valueOf(n).charAt(0))
.collect(Collectors.groupingBy(c -> c, Collectors.counting()));
System.out.println("Leading digit distribution: " + distribution);
What are common mistakes?
Mistake: using toString() on a potentially null Integer.
// WRONG: NPE if list contains null
Integer val = null;
String s = val.toString(); // NPE!
// CORRECT: String.valueOf handles null
String safe = String.valueOf(val); // "null"
// But better: filter nulls first
Mistake: forgetting that startsWith is case-sensitive for string digits.
// For digits this is not an issue, but for hex:
// "A1".startsWith("a") is false
What about filtering by last digit?
List<Integer> endsWith5 = accountNumbers.stream()
.filter(n -> String.valueOf(n).endsWith("5"))
.toList();
// Or numerically: n % 10 == 5
What are common interview follow-up questions?
- "How do you count numbers starting with each digit?" Group by leading digit and count.
- "How do you filter by a prefix of two digits?" Use startsWith("12") for numbers starting with 12.
- "How do you validate account number format?" Combine startsWith with length checks and matches.
Visual Overview
List: [1001, 2345, 1502, 3001, 1999, 4500, 1100]
│
│ .map(String::valueOf)
▼
["1001", "2345", "1502", "3001", "1999", "4500", "1100"]
│
│ .filter(s -> s.startsWith("1"))
▼
["1001", "1502", "1999", "1100"]
Negative example: -150 → "-150" → startsWith("1") = false
Use Math.abs first if sign should be ignored
Key Takeaway
Filtering numbers by their leading digit converts each integer to a string and uses startsWith to check the prefix. This pattern moves between the numeric and textual views of data mid-pipeline: you switch to text just long enough to do a prefix test, then optionally switch back to integers with parseInt.
The sign matters: negative numbers start with '-', not a digit, so decide whether to strip the sign with Math.abs based on the requirement. For hot paths, compute the leading digit numerically with repeated division to avoid allocating a string per element.
At the National Bank of India, Rajesh used this to filter account numbers beginning with a particular branch-prefix digit.
Remember one sentence: map to String and filter with startsWith checks the leading digit, but handle negative signs and consider numeric division for hot paths.
---