Java CharSequence Interface
Last modified: April 13, 2025
The java.lang.CharSequence
interface represents a readable sequence
of char values. It provides uniform, read-only access to different types of
character sequences. This interface is implemented by String, StringBuilder,
StringBuffer, and other character sequence classes.
CharSequence was introduced in Java 1.4 to create a common abstraction for character sequences. It defines basic operations for examining characters without modifying them. Many Java APIs accept CharSequence to work with different character sequence types flexibly.
CharSequence Interface Methods
The CharSequence interface defines several methods for examining characters.
These methods must be implemented by all classes that implement the interface.
The main methods include length
, charAt
,
subSequence
, and toString
.
public interface CharSequence { int length(); char charAt(int index); CharSequence subSequence(int start, int end); String toString(); }
The code above shows the methods defined by the CharSequence interface. These methods provide basic read-only access to character sequences. The interface does not include any mutation operations.
Basic CharSequence Usage
This example demonstrates basic usage of CharSequence with different implementations. We show how to use the interface methods with String, StringBuilder, and StringBuffer.
package com.zetcode; public class Main { public static void main(String[] args) { // Different CharSequence implementations CharSequence str = "Hello World"; CharSequence sb = new StringBuilder("Java Programming"); CharSequence sbf = new StringBuffer("CharSequence Demo"); // Common operations System.out.println("String length: " + str.length()); System.out.println("5th char in StringBuilder: " + sb.charAt(4)); System.out.println("Subsequence of StringBuffer: " + sbf.subSequence(0, 11)); // toString() usage String s = str.toString(); System.out.println("Converted to String: " + s); } }
This example shows how CharSequence provides a common interface for different character sequence types. We can call the same methods regardless of the underlying implementation. The toString method converts any CharSequence to a String when needed.
CharSequence with String
Strings are the most common CharSequence implementation. This example shows specific String operations through the CharSequence interface.
package com.zetcode; public class Main { public static void processSequence(CharSequence seq) { System.out.println("Processing sequence: " + seq); System.out.println("Length: " + seq.length()); System.out.println("First char: " + seq.charAt(0)); System.out.println("Last char: " + seq.charAt(seq.length() - 1)); } public static void main(String[] args) { String text = "Programming in Java"; processSequence(text); processSequence(text.subSequence(0, 11)); } }
Here we demonstrate how String works as a CharSequence. The processSequence method accepts any CharSequence, allowing it to work with both the full String and its subsequence. This shows the flexibility of programming to interfaces.
CharSequence with StringBuilder
StringBuilder is a mutable CharSequence implementation. This example shows how to use StringBuilder through the CharSequence interface while maintaining mutability.
package com.zetcode; public class Main { public static void main(String[] args) { StringBuilder sb = new StringBuilder("Initial Value"); CharSequence cs = sb; System.out.println("Original: " + cs); System.out.println("Length: " + cs.length()); System.out.println("Char at 3: " + cs.charAt(3)); // Mutate the underlying StringBuilder sb.append(" Appended"); System.out.println("After mutation: " + cs); // Create subsequence CharSequence sub = cs.subSequence(8, 13); System.out.println("Subsequence: " + sub); } }
This example demonstrates that while CharSequence itself is read-only, the underlying StringBuilder remains mutable. Changes to the StringBuilder are visible through the CharSequence reference. The subsequence operation creates a new CharSequence view of part of the original.
Comparing CharSequence Implementations
This example compares different CharSequence implementations and shows how to work with them polymorphically. We'll process various sequence types through a common interface.
package com.zetcode; public class Main { public static void printSequenceInfo(CharSequence seq) { System.out.println("Type: " + seq.getClass().getSimpleName()); System.out.println("Content: " + seq); System.out.println("Length: " + seq.length()); if (seq.length() > 0) { System.out.println("First char: " + seq.charAt(0)); System.out.println("Last char: " + seq.charAt(seq.length() - 1)); } System.out.println("-----"); } public static void main(String[] args) { CharSequence[] sequences = { "String implementation", new StringBuilder("StringBuilder implementation"), new StringBuffer("StringBuffer implementation"), new java.nio.CharBuffer() { public char get() { return 'X'; } public char get(int index) { return 'X'; } public int length() { return 10; } public CharSequence subSequence(int s, int e) { return this; } public String toString() { return "Custom Implementation"; } } }; for (CharSequence seq : sequences) { printSequenceInfo(seq); } } }
This example shows how to handle different CharSequence implementations through a single interface. We process String, StringBuilder, StringBuffer, and even a custom implementation. The printSequenceInfo method works with all types transparently, demonstrating interface polymorphism.
CharSequence in Regular Expressions
Java's regular expression API extensively uses CharSequence. This example shows pattern matching with different CharSequence implementations.
package com.zetcode; import java.util.regex.*; public class Main { public static void main(String[] args) { Pattern pattern = Pattern.compile("\\d{3}-\\d{2}-\\d{4}"); CharSequence[] inputs = { "123-45-6789", // String new StringBuilder("987-65-4321"), new StringBuffer("Invalid-12-3456"), "Another invalid 12-34-5678" }; for (CharSequence input : inputs) { Matcher matcher = pattern.matcher(input); System.out.println(input + ": " + (matcher.matches() ? "Valid" : "Invalid")); } } }
This example demonstrates how Java's regex API accepts any CharSequence. We test different implementations against a social security number pattern. The Pattern and Matcher classes work with all CharSequence types, showing the interface's utility in API design.
Custom CharSequence Implementation
This example shows how to create a custom CharSequence implementation. We'll build a simple sequence that reverses another CharSequence.
package com.zetcode; public class ReverseCharSequence implements CharSequence { private final CharSequence original; public ReverseCharSequence(CharSequence original) { this.original = original; } @Override public int length() { return original.length(); } @Override public char charAt(int index) { return original.charAt(original.length() - 1 - index); } @Override public CharSequence subSequence(int start, int end) { return new ReverseCharSequence( original.subSequence(original.length() - end, original.length() - start)); } @Override public String toString() { StringBuilder sb = new StringBuilder(length()); for (int i = 0; i < length(); i++) { sb.append(charAt(i)); } return sb.toString(); } } public class Main { public static void main(String[] args) { CharSequence original = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; CharSequence reversed = new ReverseCharSequence(original); System.out.println("Original: " + original); System.out.println("Reversed: " + reversed); System.out.println("5th char: " + reversed.charAt(4)); System.out.println("Subseq(5-10): " + reversed.subSequence(5, 10)); } }
This example demonstrates creating a custom CharSequence that reverses another sequence. The ReverseCharSequence class implements all required methods, providing a view of the original sequence in reverse order. This shows how CharSequence can be used to create specialized sequence views.
CharSequence Performance Considerations
This example compares performance characteristics of different CharSequence implementations for common operations.
package com.zetcode; public class Main { public static void measurePerformance(CharSequence seq, String type) { final int ITERATIONS = 1000000; // Measure charAt performance long start = System.nanoTime(); for (int i = 0; i < ITERATIONS; i++) { seq.charAt(i % seq.length()); } long duration = System.nanoTime() - start; System.out.printf("%s charAt: %d ns%n", type, duration/ITERATIONS); // Measure subSequence performance start = System.nanoTime(); for (int i = 0; i < ITERATIONS; i++) { seq.subSequence(0, seq.length() / 2); } duration = System.nanoTime() - start; System.out.printf("%s subSequence: %d ns%n", type, duration/ITERATIONS); } public static void main(String[] args) { CharSequence str = "PerformanceTestString"; CharSequence sb = new StringBuilder("PerformanceTestString"); CharSequence sbf = new StringBuffer("PerformanceTestString"); measurePerformance(str, "String"); measurePerformance(sb, "StringBuilder"); measurePerformance(sbf, "StringBuffer"); } }
This example measures the performance of basic CharSequence operations across different implementations. String typically offers the fastest read operations, while StringBuilder and StringBuffer may have different performance characteristics. Results may vary based on JVM implementation and version.
Source
Java CharSequence Interface Documentation
In this article, we've covered the Java CharSequence interface with practical examples. Understanding CharSequence is valuable for writing flexible APIs that can work with different character sequence types efficiently.
Author
List all Java tutorials.