Definition
Comparator.comparingInt(String::length)compares by the int returned fromlength(), no boxing.reversed()gives longest-first ordering.- Tie-breaker:
thenComparing(Comparator.naturalOrder())sorts equal-length strings alphabetically. - Derived-key technique: works for any computed int property.
- Non-mutating:
sorted()produces a new stream.
The National Bank of India has a mix of reference codes: short legacy codes and long new UPI references. Priya wants them sorted from shortest to longest so the old short codes group together.
Understanding the Concepts
How do you sort strings by their length?
package com.bank.core;
import java.util.*;
import java.util.stream.Collectors;
public class SortByLength {
public static void main(String[] args) {
List<String> codes = List.of(
"TX1", "UPI123456", "AB9", "NEFT78", "RTGS12345678");
// Ascending: shortest first
List<String> ascending = codes.stream()
.sorted(Comparator.comparingInt(String::length))
.collect(Collectors.toList());
System.out.println("Ascending: " + ascending);
// Descending: longest first
List<String> descending = codes.stream()
.sorted(Comparator.comparingInt(String::length).reversed())
.collect(Collectors.toList());
System.out.println("Descending: " + descending);
}
}
Ascending: [TX1, AB9, NEFT78, UPI123456, RTGS12345678]
Descending: [RTGS12345678, UPI123456, NEFT78, TX1, AB9]
How do you make equal-length strings deterministic?
// Equal-length strings sorted alphabetically
List<String> deterministic = codes.stream()
.sorted(Comparator.comparingInt(String::length)
.thenComparing(Comparator.naturalOrder()))
.collect(Collectors.toList());
System.out.println(deterministic);
// [AB9, TX1, NEFT78, UPI123456, RTGS12345678]
// AB9 and TX1 are both length 3; alphabetical tie-break puts AB9 first
How is comparingInt different from comparing for length?
| Method | Boxing | Performance | |---|---|---| | comparingInt(String::length) | No | Better | | comparing(String::length) | Yes, int → Integer | Slower on large lists |
What are common mistakes?
Mistake: forgetting a tie-breaker, making equal-length output non-deterministic.
// Non-deterministic: TX1 and AB9 (both length 3) can appear in either order
codes.stream()
.sorted(Comparator.comparingInt(String::length))
.collect(Collectors.toList());
// Deterministic: alphabetical tie-breaker
codes.stream()
.sorted(Comparator.comparingInt(String::length)
.thenComparing(Comparator.naturalOrder()))
.collect(Collectors.toList());
What about sorting by a different derived int key?
The same technique works for any computed int property.
// Sort account numbers by digit count
List<String> accounts = List.of("SAV2001", "CUR12345678", "SAV99");
accounts.stream()
.sorted(Comparator.comparingInt(s -> s.replaceAll("\\D", "").length()))
.forEach(System.out::println);
What should a senior engineer know?
comparingIntavoids boxing and is the correct choice for int-returning key extractors.- Always add a deterministic tie-breaker for reports that must be reproducible.
- The source list is never mutated.
String::lengthis O(1) because length is a stored field, so the sort overhead is purely the comparison.
What are common interview follow-up questions?
- "How do you sort longest-first?" Append
.reversed(). - "What about equal-length strings?" Add
thenComparing(Comparator.naturalOrder()). - "Can you sort by a different derived key?" Yes, pass any int-returning lambda to
comparingInt.
Visual Overview
["TX1"(3), "UPI123456"(9), "AB9"(3), "NEFT78"(6), "RTGS12345678"(12)]
│
│ sorted(comparingInt(String::length))
▼
["TX1"(3), "AB9"(3), "NEFT78"(6), "UPI123456"(9), "RTGS12345678"(12)]
│ shortest → longest
│ .reversed()
▼
["RTGS12345678"(12), "UPI123456"(9), "NEFT78"(6), "TX1"(3), "AB9"(3)]
longest → shortest
Key Takeaway
To sort strings by their length I use comparingInt(String::length), which extracts the primitive int length with no boxing. Appending .reversed() gives longest-first, and thenComparing(Comparator.naturalOrder()) makes equal-length strings alphabetical for deterministic output.
In my banking project at the National Bank of India this ordered a reconciliation report of transaction reference codes by length, letting the operations team visually separate short legacy codes from longer modern UPI and NEFT references.
The same derived-key technique generalises to any computed int property, and sorted never mutates the source list.
Remember one sentence: comparingInt(String::length) sorts by character count without boxing, and .reversed() gives longest-first.
---