The String Constant Pool
Java's String Constant Pool is a specialized memory area designed to store string literals, optimizing memory usage and performance. Its location has evolved across Java versions.
Key Characteristics of the String Pool
- Storage Location: In Java 6 and earlier, the pool resided in the PermGen (Permanent Generation). Starting with Java 7, it was moved to the main heap memory. Java 8 replaced PermGen with Metaspace, but the pool remains on the heap.
- Literal Storage: When a string literal (e.g.,
"text") is encountered in code, the JVM checks the pool. If an identical string exists, a reference to that existing object is returned. Otherwise, a new String object is created in the pool. - Immutability: String objects are immutable. Any operation that modifies a string results in the creation of a new String object, leaving the original in the pool unchanged.
- Garbage Collection: Strings in the pool are subject to garbage collection when they are no longer referenced.
Implementation Details
newKeyword: Creating a string withnew String("text")always generates a new object on the heap, outside the pool, even if an identical literal exists.intern()Method: This method places a string's canonical representation into the pool. If the pool already contains an equal string, that reference is returned. Otherwies, the string is added to the pool, and its reference is returned.
String literalOne = "data"; // Pool reference
String literalTwo = "data"; // Same pool reference
String heapStr = new String("data"); // New heap object
String internedStr = heapStr.intern(); // Returns pool reference
System.out.println(literalOne == literalTwo); // true (same object)
System.out.println(literalOne == heapStr); // false (different objects)
System.out.println(literalOne == internedStr); // true (interned to pool)
Core String Class Methods
The java.lang.String class provides immutable sequences of characters and includes numerous methods for manipulation.
Common Operations
- Comparison:
equals(Object obj),equalsIgnoreCase(String str). - Length:
length()returns character count. - Character Acess:
charAt(int index). - Concatenation:
concat(String str)or the+operator. - Extraction:
substring(int start, int end). - Splitting:
split(String regex). - Case Conversion:
toLowerCase(),toUpperCase(). - Searching:
indexOf(int ch),indexOf(String str). - Replacement:
replace(char oldChar, char newChar). - Trimming:
trim()removes leading/trailing whitespace. - Formatting:
String.format(String format, Object... args).
public class StringOperationsDemo {
public static void main(String[] args) {
String sample = " Java Programming ";
System.out.println("Trimmed: '" + sample.trim() + "'");
System.out.println("Uppercase: " + sample.toUpperCase());
System.out.println("Substring (5-15): " + sample.substring(5, 15));
String[] parts = sample.trim().split(" ");
System.out.println("Split words: " + java.util.Arrays.toString(parts));
System.out.println(String.format("Formatted: Score is %d out of %d", 95, 100));
}
}
Regular Expressions in Java
Regular expressions (regex) define patterns for matching, searching, and manipulating text strings.
Basic Components
- Literals: Characters like
a,1match themselves. - Character Classes:
[abc]matches any single charactera,b, orc.[^abc]matches any character except these. - Predefined Classes:
\d(digit),\s(whitespace),\w(word character). - Quantifiers:
*: Zero or more times.+: One or more times.?: Zero or one time.{n}: Exactlyntimes.{n,}: At leastntimes.{n,m}: Betweennandmtimes.
- Boundary Matchers:
^(line start),$(line end),\b(word boundary). - Groups: Parentheses
()create capturing groups.
Usage in Java
The java.util.regex package contains the Pattern and Matcher classes.
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexValidation {
public static void main(String[] args) {
// Pattern for a simple username (alphanumeric, 3-15 chars)
String userPattern = "^[a-zA-Z0-9_]{3,15}$";
Pattern compiledPattern = Pattern.compile(userPattern);
String testName = "Valid_User123";
Matcher matcher = compiledPattern.matcher(testName);
if (matcher.matches()) {
System.out.println("Username is valid.");
} else {
System.out.println("Invalid username.");
}
// Example: Finding all numbers in a string
String text = "Order 123 has 5 items.";
Pattern digitPattern = Pattern.compile("\\d+"); // One or more digits
Matcher digitMatcher = digitPattern.matcher(text);
while (digitMatcher.find()) {
System.out.println("Found number: " + digitMatcher.group());
}
}
}
Special Characterrs and Escaping
Many regex symbols have special meanings. To match them literally, escape them with a backslash (\\ in a Java string).
\.matches a literal dot.\\*matches a literal asterisk.\\(matches a literal opening parenthesis.
Advanced Constructs
- Non-capturing Groups:
(?:pattern)groups without capturing. - Lookahead/Lookbehind:
(?=pattern)Positive lookahead.(?!pattern)Negative lookahead.(?<=pattern)Positive lookbehind.(?<!pattern)Negative lookbehind.
- Greedy vs. Reluctant Quantifiers: By default,
*and+are greedy (match as much as possible). Adding?makes them reluctant (match as little as possible). E.g.,.*?.