String iteration
Java performance
character processing
coding best practices
loop optimization

Fastest way to iterate over all the chars in a String

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Java, the fastest way to iterate through a String depends on what you mean by character. If you only need UTF-16 code units, an indexed charAt loop is usually the best baseline. If you need full Unicode correctness, you must iterate by code point even though the loop becomes slightly more complex.

Decide Whether You Need char or Unicode Code Points

A Java char is a single UTF-16 code unit, not always a full logical character. Supplementary Unicode symbols are represented as surrogate pairs, which means one visible symbol can occupy two char values.

That distinction matters:

  1. parsing ASCII-like text often works fine with char
  2. user-facing text processing often requires code points

Optimizing the wrong iteration model is a correctness bug, not a performance win.

charAt Is a Strong Default for Code-Unit Iteration

When you only need UTF-16 code units, indexed iteration with charAt is usually fast and allocation-free.

java
1public class Main {
2    static int countDigits(String s) {
3        int count = 0;
4        int n = s.length();
5
6        for (int i = 0; i < n; i++) {
7            char c = s.charAt(i);
8            if (c >= '0' && c <= '9') {
9                count++;
10            }
11        }
12
13        return count;
14    }
15
16    public static void main(String[] args) {
17        System.out.println(countDigits("A1B2C3"));
18    }
19}

This style avoids extra allocations and keeps the loop body simple. In real programs, that simplicity is usually more important than tiny syntax-level differences between loop forms.

toCharArray Adds an Allocation

Another common pattern is converting the string once and iterating the array. This can be readable, but it creates a new array, which matters in hot paths or allocation-sensitive services.

java
1public class Main {
2    static int countDigitsArray(String s) {
3        int count = 0;
4        char[] chars = s.toCharArray();
5
6        for (char c : chars) {
7            if (c >= '0' && c <= '9') {
8                count++;
9            }
10        }
11
12        return count;
13    }
14}

Sometimes the array-based loop benchmarks well for a specific workload, but you should treat it as a measured optimization, not a default.

Use Code Points When Correctness Requires It

If the logic cares about logical characters rather than UTF-16 code units, iterate with codePointAt and advance by Character.charCount.

java
1public class Main {
2    static int countCodePoints(String s) {
3        int count = 0;
4
5        for (int i = 0; i < s.length();) {
6            int cp = s.codePointAt(i);
7            count++;
8            i += Character.charCount(cp);
9        }
10
11        return count;
12    }
13
14    public static void main(String[] args) {
15        String text = "A𝄞B";
16        System.out.println(countCodePoints(text));
17    }
18}

This is the correct approach for many internationalized applications, even if a charAt loop would appear faster in a narrow benchmark.

Keep the Loop Body Cheap

In most real code, iteration style is not the dominant cost. The expensive part is what happens inside the loop. Avoid per-character allocations, substring creation, regex work, or repeated method calls that could be moved outside the loop.

Good habits include:

  1. cache length() before the loop
  2. keep branches simple
  3. accumulate using primitives

Those changes often matter more than switching between for loop variants.

Benchmark With JMH, Not a Stopwatch

Microbenchmarking string iteration with System.nanoTime() usually produces misleading results because of JIT compilation, dead-code elimination, and warm-up effects. If performance truly matters, use JMH.

java
1// Sketch only
2// @Benchmark
3// public int benchmarkCharAt() { ... }
4//
5// @Benchmark
6// public int benchmarkCodePoint() { ... }

Benchmark using realistic string sizes and character distributions. A loop that looks fast on short ASCII strings may behave very differently on long multilingual text.

Common Pitfalls

The biggest mistake is assuming a char loop is always Unicode-correct. Another is converting every string with toCharArray() without accounting for the extra allocation. Developers also waste time optimizing loop syntax when the real cost comes from heavy work inside the loop body rather than the iteration mechanism itself.

Summary

  • The fastest Java string iteration method depends on whether you need code units or code points.
  • Indexed charAt loops are a strong default for UTF-16 code-unit processing.
  • 'toCharArray() may be readable, but it adds an allocation.'
  • Use code-point iteration for Unicode-correct character handling.
  • Measure real performance with JMH before treating a loop variant as an optimization.

Course illustration
Course illustration

All Rights Reserved.