This post will discuss various methods to iterate over characters in a string in Java.
1. Naive solution
A naive solution is to use a simple for-loop to process each character of the string. This approach proves to be very effective for strings of smaller length.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Main { // Iterate over the characters of a string public static void main(String[] args) { String s = "Techie Delight"; // using simple for-loop for (int i = 0; i < s.length(); i++) { System.out.print(s.charAt(i)); } } } |
2. Using String.toCharArray()
method
We can also convert a string to char[]
using String.toCharArray()
method and then iterate over the character array using enhanced for-loop (for-each loop) as shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Main { // Iterate over the characters of a string public static void main(String[] args) { String s = "Techie Delight"; // convert string to `char[]` array char[] chars = s.toCharArray(); // iterate over `char[]` array using enhanced for-loop for (char ch: chars) { System.out.print(ch); } } } |
3. Using Iterator
We can also use the StringCharacterIterator
class that implements bidirectional iteration for a String.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import java.text.CharacterIterator; import java.text.StringCharacterIterator; class Main { // Iterate over the characters of a string public static void main(String[] args) { String s = "Techie Delight"; CharacterIterator it = new StringCharacterIterator(s); while (it.current() != CharacterIterator.DONE) { System.out.print(it.current()); it.next(); } } } |
4. Using StringTokenizer
Another solution is to use StringTokenizer, although its use is discouraged. The StringTokenizer
class breaks a string into tokens. Its prototype is:
StringTokenizer(String str, String delim, boolean returnDelims)
An instance of StringTokenizer
behaves in one of two ways, depending on whether it was created with the returnDelims
flag having the value true or false:
- If
returnDelims
is false, delimiter characters serve to separate tokens. A token is a maximal sequence of consecutive characters that are not delimiters. - If
returnDelims
is true, delimiter characters are themselves considered to be tokens. Thus, a token is either one delimiter character or a maximal sequence of consecutive characters that are not delimiters.
The following program demonstrates it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import java.util.StringTokenizer; class Main { // Iterate over the characters of a string public static void main(String[] args) { String s = "Techie Delight"; @Deprecated // if returnDelims is true, use the string itself as a delimiter StringTokenizer st = new StringTokenizer(s, s, true); while (st.hasMoreTokens()) { System.out.print(st.nextToken()); } // if returnDelims is false, use an empty string as a delimiter st = new StringTokenizer(s, "", false); while (st.hasMoreTokens()) { System.out.print(st.nextToken()); } } } |
5. Using String.Split()
method
It is recommended to use the String.split()
method over StringTokenizer
, which is a legacy class and still alive for compatibility reasons.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Main { // Iterate over the characters of a string public static void main(String[] args) { String s = "Techie Delight"; String[] arr = s.split(""); for (String ch: arr) { System.out.print(ch); } } } |
6. Using Guava Library
Guava’s Lists.charactersOf()
returns a view of the specified string as an immutable list of characters. We can process the immutable list using a for-each loop or an iterator. Please note that this method returns a view; no actual copying happens here.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import com.google.common.collect.Lists; class Main { // Iterate over the characters of a string public static void main(String[] args) { String s = "Techie Delight"; // using the for-each loop for (Character ch: Lists.charactersOf(s)) { System.out.print(ch); } // Java 8 – listIterator Lists.charactersOf(s).forEach(System.out::print); } } |
7. Using String.chars()
method
Java 8 provides a new method, String.chars()
, which returns an IntStream
(a stream of ints) representing an integer representation of characters in the String. This method does not return the desired Stream<Character>
(for performance reasons), but we can map IntStream
to an object in such a way that it will automatically box into a Stream<Character>
. There are various ways to achieve that, as shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
class Main { // Iterate over the characters of a string public static void main(String[] args) { String s = "Techie Delight"; // 1. Implicit boxing into `Stream<Character>` // 1.1. Using method reference s.chars() .mapToObj(Character::toChars) .forEach(System.out::print); // 1.2. Using lambda expressions by casting `int` to `char` s.chars() .mapToObj(i -> Character.valueOf((char) i)) .forEach(System.out::print); s.chars() .mapToObj(i -> (char) i) .forEach(System.out::print); s.chars() .mapToObj(i -> new StringBuilder().appendCodePoint(i)) .forEach(System.out::print); // 2. Without boxing into `Stream<Character>` s.chars() .forEach(i -> System.out.print(Character.toChars(i))); s.chars() .forEach(i -> System.out.print((char) i)); s.chars() .forEach(i -> System.out.print(new StringBuilder() .appendCodePoint(i))); } } |
8. Using Code Points
We can also use Java 8 String.codePoints()
instead of String.chars()
that also returns an IntStream
but having Unicode code points instead of char values.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
class Main { // Iterate over the characters of a string public static void main(String[] args) { String s = "Techie Delight"; /* 1. Implicit Boxing into `Stream<Character>` */ // 1.1. Using method reference s.codePoints() .mapToObj(Character::toChars) .forEach(System.out::print); s.codePoints() .mapToObj(i -> new StringBuilder().appendCodePoint(i)) .forEach(System.out::print); // 1.2. Using lambda expressions by casting `int` to `char` s.chars() .mapToObj(i -> Character.valueOf((char) i)) .forEach(System.out::print); s.codePoints() .mapToObj(i -> (char) i) .forEach(System.out::print); /* 2. Without Boxing into `Stream<Character>` */ s.codePoints() .forEach(i -> System.out.print(Character.toChars(i))); s.codePoints() .forEach(i -> System.out.print((char) i)); s.chars() .forEach(i -> System.out.print(new StringBuilder() .appendCodePoint(i))); } } |
9. Using Reflection
For very long strings, nothing beats reflection in terms of performance. We can inspect any string using reflection and access the backing array of the specified string. To find the name of the backing array, we can print all the fields of String
class using the following code and search one with the type char[]
.
Update: This is unsupported after Java 8.
1 2 3 4 5 6 7 8 9 |
Field[] fields = String.class.getDeclaredFields(); Arrays.asList(fields) .stream() .filter(x -> x.toString().contains("char[]")) .forEach(x -> { int index = x.toString().lastIndexOf(".") + 1; System.out.print(x.toString().substring(index)); // prints "value" }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import java.lang.reflect.Field; class Main { // Iterate over the characters of a string public static void main(String[] args) { String s = "Techie Delight"; Field field = null; try { field = String.class.getDeclaredField("value"); } catch (NoSuchFieldException e) { e.printStackTrace(); } field.setAccessible(true); char[] chars = new char[0]; try { chars = (char[]) field.get(s); } catch (IllegalAccessException e) { e.printStackTrace(); } for (char ch: chars) { System.out.print(ch); } } } |
That’s all about iterating over characters of a Java String.
Related Post: