Back to Stream: Sorting & Comparator
Q22Question 22 of 23

Sort a list of strings by their length using Comparator.comparingInt(String::length)

Key Concepts
  • comparingInt(String::length) orders strings shortest-to-longest by character count without boxing
  • reversed() on the comparator gives longest-first ordering
  • thenComparing(Comparator.naturalOrder()) makes equal-length strings alphabetical
  • String::length is a method reference extracting the primitive int length from each string
  • The same derived-key technique works for any computed int property, like digit count
  • sorted() never mutates the source list

Definition

`comparingInt(String::length)` orders strings shortest-to-longest by character count.
  • Comparator.comparingInt(String::length) compares by the int returned from length(), 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?

JAVA
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);
    }
}
TEXT
Ascending: [TX1, AB9, NEFT78, UPI123456, RTGS12345678]
Descending: [RTGS12345678, UPI123456, NEFT78, TX1, AB9]

How do you make equal-length strings deterministic?

JAVA
// 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?

DIAGRAM
| 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.

JAVA
// 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.

JAVA
// 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?

  • comparingInt avoids 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::length is 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

DIAGRAM
  ["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.

---

Share
Use ← → arrow keys to navigate