String Utility Methods: join(), repeat(), chars(), strip()
Java's String class ships with a rich set of utility methods for everyday text manipulation. Java 11 expanded the API significantly: strip() provides Unicode-aware whitespace removal, isBlank() tests for empty-or-whitespace strings, and repeat() makes string repetition a one-liner. The chars() and codePoints() methods expose a string as an IntStream, enabling stream pipelines over individual characters. This article covers the most useful String utility methods with practical examples.
Contents
String.join() with delimiter and Iterable
String.join(delimiter, elements)Iterable<? extends CharSequence>"null"String.join(",", list)Collectors.joining(delimiter, prefix, suffix)StringJoinersetEmptyValue()
// String.join(delimiter, elements...) β joins strings with a separator
String csv = String.join(", ", "Alice", "Bob", "Charlie");
System.out.println(csv); // Alice, Bob, Charlie
// Join from a List (or any Iterable<CharSequence>)
List<String> names = List.of("red", "green", "blue");
String joined = String.join(" | ", names);
System.out.println(joined); // red | green | blue
// Empty delimiter β concatenates without separator
String concat = String.join("", "foo", "bar", "baz");
System.out.println(concat); // foobarbaz
// Join with multi-character delimiter
String path = String.join("/", "home", "user", "docs", "report.txt");
System.out.println(path); // home/user/docs/report.txt
// Join a Set (iteration order is Set-defined)
Set<String> tags = new LinkedHashSet<>(List.of("java", "strings", "api"));
System.out.println(String.join(", ", tags)); // java, strings, api
// StringJoiner β more control: prefix, suffix, empty value
import java.util.StringJoiner;
StringJoiner sj = new StringJoiner(", ", "[", "]");
sj.add("one");
sj.add("two");
sj.add("three");
System.out.println(sj.toString()); // [one, two, three]
// setEmptyValue β returned when no elements are added
StringJoiner empty = new StringJoiner(", ", "[", "]");
empty.setEmptyValue("(none)");
System.out.println(empty.toString()); // (none)
// Collectors.joining() β joining in a stream pipeline
String result = Stream.of("a", "b", "c")
.map(String::toUpperCase)
.collect(Collectors.joining(", ", "{", "}"));
System.out.println(result); // {A, B, C}
String.join()Collectors.joining()StringJoinerString.repeat(): Java 11+
repeat(n)n0IllegalArgumentExceptionnew String(new char[n]).replace('\0', c)
// String.repeat(int count) β returns the string repeated count times
String dashes = "-".repeat(20);
System.out.println(dashes); // --------------------
// Useful for padding or building separators
String title = "Results";
String line = "=".repeat(title.length());
System.out.println(title);
System.out.println(line); // =======
// Repeat multi-character strings
String block = "ab".repeat(4);
System.out.println(block); // abababab
// Zero count returns empty string
System.out.println("x".repeat(0)); // ""
// Negative count throws IllegalArgumentException
// "x".repeat(-1); // throws IllegalArgumentException
// Practical use: indent levels
String indent = " "; // 2 spaces
for (int level = 0; level <= 3; level++) {
System.out.println(indent.repeat(level) + "level " + level);
}
// level 0
// level 1
// level 2
// level 3
// Building a simple ASCII table border
int cols = 5;
String border = ("+" + "-".repeat(10)).repeat(cols) + "+";
System.out.println(border);
// +----------+----------+----------+----------+----------+
// Pre-Java 11 equivalent
// String old = new String(new char[n]).replace('\0', 'x');
// Or: IntStream.range(0, n).mapToObj(i -> "x").collect(Collectors.joining())
Note: Before Java 11, there was no built-in repeat()new String(new char[n]).replace('\0', c)repeat()
strip() vs trim(): Unicode-aware whitespace
trim()<= '\u0020'strip()Character.isWhitespace()\u00A0stripLeading()stripTrailing()strip()trim()
// trim() β removes ASCII control characters and spaces (\u0000β\u0020)
// strip() β removes all Unicode whitespace (Java 11+, uses Character.isWhitespace())
String plain = " hello world ";
System.out.println(plain.trim()); // "hello world"
System.out.println(plain.strip()); // "hello world"
// The difference: Unicode whitespace characters
// \u2003 is an em-space β Unicode whitespace but NOT ASCII \u0020
String unicode = "\u2003hello\u2003";
System.out.println("[" + unicode.trim() + "]"); // [\u2003hello\u2003] β NOT removed
System.out.println("[" + unicode.strip() + "]"); // [hello] β removed
// stripLeading() β only leading whitespace
String leading = " hello ";
System.out.println("[" + leading.stripLeading() + "]"); // [hello ]
// stripTrailing() β only trailing whitespace
System.out.println("[" + leading.stripTrailing() + "]"); // [ hello]
// Practical use: normalising user input
String userInput = " \t Alice \n ";
String cleaned = userInput.strip();
System.out.println("[" + cleaned + "]"); // [Alice]
// When to use trim() vs strip()
// - New code: always prefer strip() β Unicode-aware and clearly named
// - Existing codebases: trim() is fine for pure ASCII input
// - CSV/TSV parsing with tab-separated values β use strip() to handle tabs
// Checking if stripped result is empty: combine with isBlank()
String ws = " \t \n ";
System.out.println(ws.strip().isEmpty()); // true
System.out.println(ws.isBlank()); // true (Java 11+ shorthand)
trim()strip()chars() and codePoints() streams
chars()IntStreamintcharcodePoints()IntStreamcharcodePoints()
// chars() β returns an IntStream of char values (UTF-16 code units)
String s = "Hello";
s.chars().forEach(c -> System.out.print((char) c + " ")); // H e l l o
// Count vowels using a stream
long vowels = "Programming".chars()
.filter(c -> "aeiouAEIOU".indexOf(c) >= 0)
.count();
System.out.println("Vowels: " + vowels); // Vowels: 3
// Convert chars stream back to String
String upper = "hello".chars()
.map(Character::toUpperCase)
.collect(StringBuilder::new, (sb, c) -> sb.append((char) c), StringBuilder::append)
.toString();
System.out.println(upper); // HELLO
// Check if all characters are digits
boolean allDigits = "12345".chars().allMatch(Character::isDigit); // true
boolean hasLetter = "abc12".chars().anyMatch(Character::isLetter); // true
// codePoints() β returns an IntStream of Unicode code points
// Handles supplementary characters (outside BMP, code points > 0xFFFF)
// A single supplementary char is 2 chars (a surrogate pair) in UTF-16
String emoji = "Hello \uD83D\uDE00"; // \uD83D\uDE00 = π (U+1F600)
System.out.println("chars length: " + emoji.chars().count()); // 8 (6 + 2 surrogates)
System.out.println("codePoints length: " + emoji.codePoints().count()); // 7 (6 + 1 emoji)
// Count actual characters (code points), not UTF-16 code units
long cpCount = emoji.codePoints().count();
// Collect code points back to string safely
String rebuilt = emoji.codePoints()
.collect(StringBuilder::new,
StringBuilder::appendCodePoint,
StringBuilder::append)
.toString();
System.out.println(rebuilt.equals(emoji)); // true
// Get distinct characters sorted
"banana".chars()
.distinct()
.sorted()
.mapToObj(c -> String.valueOf((char) c))
.forEach(System.out::print); // aban (sorted unique chars)
System.out.println();
chars()codePoints()charchars()contains(), startsWith(), endsWith()
These three methods return a plain boolean and are all case-sensitive. contains()CharSequencestartsWith()startsWith(prefix, offset)endsWith()regionMatches(ignoreCase, ...)
String s = "The quick brown fox jumps over the lazy dog";
// contains(CharSequence) β case-sensitive substring check
System.out.println(s.contains("fox")); // true
System.out.println(s.contains("Fox")); // false
System.out.println(s.contains("")); // true β empty string is always contained
// Case-insensitive contains
String lower = s.toLowerCase();
System.out.println(lower.contains("FOX".toLowerCase())); // true
// startsWith(prefix) / endsWith(suffix)
String filename = "report_2025.csv";
System.out.println(filename.startsWith("report")); // true
System.out.println(filename.endsWith(".csv")); // true
System.out.println(filename.endsWith(".txt")); // false
// startsWith(prefix, toffset) β check from an offset
String url = "https://example.com/path";
System.out.println(url.startsWith("example.com", 8)); // true (skip "https://")
// Practical: file type checks
List<String> files = List.of("data.csv", "readme.md", "config.json", "App.java");
List<String> javaFiles = files.stream()
.filter(f -> f.endsWith(".java"))
.collect(Collectors.toList());
System.out.println(javaFiles); // [App.java]
// Check multiple prefixes β no built-in, use stream
String[] prefixes = {"http://", "https://"};
boolean isUrl = Arrays.stream(prefixes).anyMatch(url::startsWith);
System.out.println(isUrl); // true
// indexOf / lastIndexOf β when you need position too
int idx = s.indexOf("fox"); // 16
int last = s.lastIndexOf("the"); // 31 (second "the")
int notFound = s.indexOf("cat"); // -1
// regionMatches β substring comparison at given offsets
// regionMatches(ignoreCase, toffset, other, ooffset, len)
boolean match = "HelloWorld".regionMatches(true, 0, "HELLO", 0, 5);
System.out.println(match); // true
toUpperCase() / toLowerCase() with Locale
The no-argument toUpperCase()toLowerCase()"i".toUpperCase()"Δ°""I"Locale.ENGLISHLocale.ROOT
// Basic case conversion
String s = "Hello World";
System.out.println(s.toUpperCase()); // HELLO WORLD
System.out.println(s.toLowerCase()); // hello world
// Always pass a Locale for locale-sensitive characters
// Classic example: Turkish 'i' β toUpperCase() in Turkish locale yields 'Δ°' (dotted I)
// but in English locale it yields 'I' (undotted I)
String dotless = "title";
System.out.println(dotless.toUpperCase(Locale.ENGLISH)); // TITLE
System.out.println(dotless.toUpperCase(new Locale("tr"))); // TΔ°TLE β note Δ°
// Always use Locale.ROOT for programmatic/technical strings (URLs, keys, SQL)
String header = "Content-Type";
System.out.println(header.toLowerCase(Locale.ROOT)); // content-type
// Locale.ROOT is culture-neutral β safest for non-display strings
String key = "UserName";
String normalised = key.toLowerCase(Locale.ROOT); // username
// Avoid the no-arg overloads for anything that will be stored, indexed, or compared
// Bad: str.toUpperCase() β uses JVM default locale, non-portable
// Good: str.toUpperCase(Locale.US) β explicit, predictable
// Capitalizing the first letter (no built-in)
String word = "hello";
String capitalised = word.isEmpty()
? word
: Character.toUpperCase(word.charAt(0)) + word.substring(1);
System.out.println(capitalised); // Hello
// Title-case each word
String sentence = "the quick brown fox";
String titleCase = Arrays.stream(sentence.split(" "))
.map(w -> Character.toUpperCase(w.charAt(0)) + w.substring(1))
.collect(Collectors.joining(" "));
System.out.println(titleCase); // The Quick Brown Fox
toUpperCase()toLowerCase()LocaleLocale.ROOTLocaleisBlank(): Java 11+
isBlank()truestrip()isEmpty()truefalseisBlank()strip().isEmpty()
// isBlank() β returns true if the string is empty or contains only whitespace
// Uses the same Unicode definition as strip() (Character.isWhitespace())
System.out.println("".isBlank()); // true
System.out.println(" ".isBlank()); // true
System.out.println(" \t\n ".isBlank()); // true
System.out.println(" hi ".isBlank()); // false
System.out.println("0".isBlank()); // false
// isBlank() vs isEmpty()
String empty = "";
String spaces = " ";
System.out.println(empty.isEmpty()); // true
System.out.println(spaces.isEmpty()); // false
System.out.println(empty.isBlank()); // true
System.out.println(spaces.isBlank()); // true β isEmpty() would miss this
// Filtering blank lines from a text block
String text = """
line one
line two
line three
""";
List<String> nonBlank = text.lines()
.filter(line -> !line.isBlank())
.collect(Collectors.toList());
System.out.println(nonBlank); // [line one, line two, line three]
// Validate user input β null-safe pattern
static boolean hasValue(String s) {
return s != null && !s.isBlank();
}
System.out.println(hasValue(null)); // false
System.out.println(hasValue("")); // false
System.out.println(hasValue(" ")); // false
System.out.println(hasValue("text")); // true
// lines() β Java 11+ β splits on line terminators, returns Stream<String>
// Handles \n, \r\n, \r without regex
long lineCount = "one\ntwo\r\nthree\rfour".lines().count();
System.out.println(lineCount); // 4
// Pre-Java 11 equivalent of isBlank()
// str.trim().isEmpty() β but trim() misses Unicode whitespace
// str.strip().isEmpty() β correct, but requires Java 11 anyway
isBlank()trim().isEmpty()strip().isEmpty()isBlank()