Java Programs›Java 8 Streams›Count Character Occurrences Using Streams

Count Character Occurrences Using Streams in Java

intermediate·  Java 8 Streams  ·  Streams

Problem

String.chars() turns a string into a stream of character codes, so the usual grouping collectors can count them.

Given a word, count how many times each character appears and print the counts in alphabetical order.

Input
"mississippi"
Output
{i=4, m=1, p=2, s=4}

Java Program

Java
import java.util.Map; import java.util.TreeMap; import java.util.function.Function; import java.util.stream.Collectors; public class CountCharactersUsingStreams { public static void main(String[] args) { String text = "mississippi"; Map<Character, Long> counts = text.chars() // an IntStream of character codes .mapToObj(c -> (char) c) // box each code as a Character .collect(Collectors.groupingBy(Function.identity(), TreeMap::new, Collectors.counting())); System.out.println(counts); } }

Output

{i=4, m=1, p=2, s=4}

Core Logic

Turning the string into a stream of characters lets groupingBy with counting() build the whole frequency table in one expression.

How It Works
  1. 1text.chars() returns an IntStream of character codes.
  2. 2mapToObj(c -> (char) c) converts each code into a Character object.
  3. 3groupingBy(Function.identity(), TreeMap::new, counting()) groups equal characters and counts them.
  4. 4Printing the TreeMap lists characters in alphabetical order.
In mississippi, i and s each appear 4 times, p twice and m once.
💡

Key Point: Forgetting mapToObj leaves you with numbers: grouping the raw IntStream isn't possible without boxing.

Complexity
Time Complexity: O(n log k)Space Complexity: O(k)

Why: Each of the n characters is inserted into a TreeMap with k distinct keys.

Key Concepts

String.chars()mapToObj()Collectors.groupingBy()Collectors.counting()

Approach 2: Most Frequent Character

Java
import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; public class CountCharactersMostFrequent { public static void main(String[] args) { String text = "mississippi"; Map.Entry<Character, Long> top = text.chars() .mapToObj(c -> (char) c) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) .entrySet().stream() .max((a, b) -> a.getValue().equals(b.getValue()) ? Character.compare(b.getKey(), a.getKey()) // tie: the earlier letter counts as "bigger" : Long.compare(a.getValue(), b.getValue())) // otherwise the higher count wins .get(); System.out.println("Most frequent: '" + top.getKey() + "' (" + top.getValue() + " times)"); } }

Output

Most frequent: 'i' (4 times)

Core Logic

After counting, streaming the map's entries and taking the maximum by count finds the most frequent character.

How It Works
  1. 1The counts are built with a plain groupingBy and counting().
  2. 2The entry stream is reduced with max and a comparator.
  3. 3The comparator compares counts first and, on a tie, prefers the earlier letter.
i and s both appear 4 times; the tie-break picks i.
💡

Key Point: Always define a tie-break — otherwise which of several equally frequent characters you get depends on the map's iteration order.

Complexity
Time Complexity: O(n)Space Complexity: O(k)

Why: One pass counts the characters and another scans the k distinct entries.

Key Concepts

entrySet().stream()max() with a comparatortie-breaking

Interview Questions

How would you ignore case and spaces?

Lower-case the string and filter before grouping: text.toLowerCase().chars().filter(c -> c != ' ').

How do you find characters that appear only once?

Filter the counted map's entries for a value of 1. Use a LinkedHashMap factory to keep them in the order they first appeared.

Learn the Concept

Related Programs