Published on Wed Feb 05 2025 12:00:00 GMT+0000 (Coordinated Universal Time) by Purusothaman Ramanujam
Google Guava String Utilities: Joiner, Splitter, and CharMatcher
Introduction
Google Guava provides excellent string utilities that make text processing more efficient and readable. The three main string utilities are Joiner, Splitter, and CharMatcher, each designed for specific string manipulation tasks.
In this post, we’ll explore these utilities and learn how they can simplify your string processing code.
Adding Guava to Your Project
Maven Dependency
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>32.1.3-jre</version></dependency>
Gradle Dependency
implementation 'com.google.guava:guava:32.1.3-jre'
Joiner
Joiner is a utility for joining strings with a delimiter. It’s more flexible and readable than using String.join()
:
import com.google.common.base.Joiner;import java.util.Arrays;import java.util.List;
public class JoinerExample { public static void main(String[] args) { List<String> fruits = Arrays.asList("apple", "banana", "cherry");
// Basic joining String joined = Joiner.on(", ").join(fruits); System.out.println(joined); // "apple, banana, cherry"
// Joining with null handling List<String> mixed = Arrays.asList("apple", null, "cherry");
// Skip nulls String joinedWithNull = Joiner.on(", ").skipNulls().join(mixed); System.out.println(joinedWithNull); // "apple, cherry"
// Replace nulls with default value String joinedWithDefault = Joiner.on(", ").useForNull("unknown").join(mixed); System.out.println(joinedWithDefault); // "apple, unknown, cherry"
// Joining map entries Map<String, Integer> map = Map.of("one", 1, "two", 2, "three", 3); String mapJoined = Joiner.on("; ").withKeyValueSeparator("=").join(map); System.out.println(mapJoined); // "one=1; two=2; three=3" }}
Joiner Features
- Null Handling: Skip or replace null values
- Key-Value Separator: Join maps with custom separators
- Appendable: Append to StringBuilder or other Appendable objects
- Immutable: Joiner instances are immutable and reusable
Splitter
Splitter is the counterpart to Joiner, providing powerful string splitting capabilities:
import com.google.common.base.Splitter;import java.util.List;
public class SplitterExample { public static void main(String[] args) { String input = "apple,banana,cherry";
// Basic splitting List<String> split = Splitter.on(",").splitToList(input); System.out.println(split); // [apple, banana, cherry]
// Split with trimming String messyInput = " apple , banana , cherry "; List<String> trimmed = Splitter.on(",").trimResults().splitToList(messyInput); System.out.println(trimmed); // [apple, banana, cherry]
// Split with empty string handling String withEmpty = "apple,,banana,cherry"; List<String> withEmptyHandling = Splitter.on(",") .omitEmptyStrings() .splitToList(withEmpty); System.out.println(withEmptyHandling); // [apple, banana, cherry]
// Split with limit List<String> limited = Splitter.on(",").limit(2).splitToList(input); System.out.println(limited); // [apple, banana,cherry]
// Split on multiple delimiters String multiDelimiter = "apple,banana;cherry:orange"; List<String> multiSplit = Splitter.onPattern("[,;:]").splitToList(multiDelimiter); System.out.println(multiSplit); // [apple, banana, cherry, orange] }}
Splitter Features
- Trimming: Automatically trim whitespace from results
- Empty String Handling: Omit or include empty strings
- Limiting: Limit the number of splits
- Pattern Splitting: Split on regular expressions
- Map Splitting: Split strings into key-value pairs
CharMatcher
CharMatcher provides utilities for working with characters and character-based operations:
import com.google.common.base.CharMatcher;
public class CharMatcherExample { public static void main(String[] args) { String input = "Hello123World!@#";
// Remove all digits String noDigits = CharMatcher.digit().removeFrom(input); System.out.println(noDigits); // "HelloWorld!@#"
// Keep only letters String onlyLetters = CharMatcher.javaLetter().retainFrom(input); System.out.println(onlyLetters); // "HelloWorld"
// Replace whitespace with underscores String noWhitespace = CharMatcher.whitespace().replaceFrom("hello world", "_"); System.out.println(noWhitespace); // "hello_world"
// Count digits int digitCount = CharMatcher.digit().countIn(input); System.out.println(digitCount); // 3
// Check if string contains only letters boolean onlyLettersCheck = CharMatcher.javaLetter().matchesAllOf("Hello"); System.out.println(onlyLettersCheck); // true
// Check if string contains any digits boolean hasDigits = CharMatcher.digit().matchesAnyOf("Hello123"); System.out.println(hasDigits); // true
// Collapse whitespace String collapsed = CharMatcher.whitespace().collapseFrom("hello world", ' '); System.out.println(collapsed); // "hello world"
// Trim from both ends String trimmed = CharMatcher.whitespace().trimFrom(" hello world "); System.out.println(trimmed); // "hello world" }}
CharMatcher Predefined Matchers
CharMatcher.digit()
: Matches digits (0-9)CharMatcher.javaLetter()
: Matches Java identifier lettersCharMatcher.javaLetterOrDigit()
: Matches Java identifier letters and digitsCharMatcher.whitespace()
: Matches whitespace charactersCharMatcher.anyOf("abc")
: Matches any character in the stringCharMatcher.noneOf("abc")
: Matches any character not in the stringCharMatcher.inRange('a', 'z')
: Matches characters in the specified range
Custom CharMatcher
public class CustomCharMatcherExample { public static void main(String[] args) { // Create custom matcher for vowels CharMatcher vowels = CharMatcher.anyOf("aeiouAEIOU");
String text = "Hello World"; String consonants = vowels.removeFrom(text); System.out.println(consonants); // "Hll Wrld"
// Combine matchers CharMatcher lettersAndDigits = CharMatcher.javaLetterOrDigit(); CharMatcher notLettersOrDigits = lettersAndDigits.negate();
String cleaned = notLettersOrDigits.removeFrom("Hello123!@#World"); System.out.println(cleaned); // "Hello123World" }}
Practical Examples
CSV Processing
public class CSVProcessor { public static List<String> parseCSVLine(String line) { return Splitter.on(",") .trimResults() .omitEmptyStrings() .splitToList(line); }
public static String createCSVLine(List<String> values) { return Joiner.on(",").join(values); }
public static void main(String[] args) { String csvLine = " apple , banana , cherry "; List<String> parsed = parseCSVLine(csvLine); System.out.println(parsed); // [apple, banana, cherry]
String newLine = createCSVLine(parsed); System.out.println(newLine); // "apple,banana,cherry" }}
Text Cleaning
public class TextCleaner { public static String cleanText(String text) { return CharMatcher.whitespace() .trimAndCollapseFrom(text, ' ') .toLowerCase(); }
public static String removeSpecialCharacters(String text) { return CharMatcher.javaLetterOrDigit() .or(CharMatcher.whitespace()) .retainFrom(text); }
public static void main(String[] args) { String dirtyText = " Hello World!@# "; String cleaned = cleanText(dirtyText); System.out.println(cleaned); // "hello world"
String specialRemoved = removeSpecialCharacters(dirtyText); System.out.println(specialRemoved); // " Hello World " }}
Best Practices
- Use Joiner for String Concatenation: More readable than StringBuilder
- Handle Nulls Explicitly: Always consider null handling in your string operations
- Use Splitter for Complex Parsing: More flexible than String.split()
- Leverage CharMatcher for Character Operations: More efficient than regex for simple operations
- Cache CharMatcher Instances: They are immutable and reusable
Common Pitfalls
- Forgetting Null Handling: Always consider null values in your string operations
- Overusing Regex: Use CharMatcher for simple character operations instead of regex
- Not Trimming Results: Use trimResults() when splitting user input
- Ignoring Empty Strings: Consider whether to omit empty strings in splits
Performance Considerations
- CharMatcher is Fast: Much faster than regex for simple character operations
- Immutable Objects: Joiner and Splitter instances can be reused
- Lazy Evaluation: Splitter uses lazy evaluation for large strings
- Memory Efficient: CharMatcher operations are memory efficient
Conclusion
Guava’s string utilities provide powerful, readable, and efficient ways to handle string operations. Joiner simplifies string concatenation, Splitter offers flexible string parsing, and CharMatcher provides fast character-based operations.
These utilities can significantly improve your code’s readability and performance compared to manual string manipulation or regex operations. Start with the basic operations and gradually explore more advanced features as your needs grow.
Resources
Written by Purusothaman Ramanujam
← Back to blog