String in Java – Creation, String Pool, Immutability and Methods
A String in Java is an object that represents an immutable sequence of characters. Strings are used everywhere, from user input and file contents to JSON, URLs and log messages, so Java gives them special support: literal syntax, a shared string pool, the + operator for concatenation and a rich set of methods.
This tutorial covers creating strings, the string pool, immutability and why it matters, comparing strings correctly, the most useful methods, text blocks, and efficient concatenation.
1. Creating Strings and the String Pool
String literals are stored in the string pool (part of the heap). When the same literal appears again, the JVM reuses the pooled object instead of creating a new one. new String(...) always creates a separate object:
public class StringCreation {
public static void main(String[] args) {
String a = "Java"; // literal: stored in the String pool
String b = "Java"; // reuses the same pooled object
String c = new String("Java"); // forces a new object on the heap
String d = c.intern(); // returns the pooled instance
System.out.println("a == b : " + (a == b)); // same object
System.out.println("a == c : " + (a == c)); // different objects
System.out.println("a.equals(c) : " + a.equals(c)); // same content
System.out.println("a == d : " + (a == d));
char[] chars = {'J', 'V', 'M'};
String fromChars = new String(chars);
String fromValue = String.valueOf(42);
String textBlock = """
{
"site": "JavaByTechie"
}"""; // text block (Java 15)
System.out.println(fromChars + " " + fromValue);
System.out.println(textBlock);
}
}
a == b : true
a == c : false
a.equals(c) : true
a == d : true
JVM 42
{
"site": "JavaByTechie"
}
- Literals with the same content share one pooled object, so
a == bis true. new String("Java")creates a distinct object, soa == cis false; avoid it in normal code.intern()returns the pooled copy of a string's content.- Text blocks (
""", Java 15) make multi-line strings such as JSON, SQL and HTML readable.
2. Strings Are Immutable
Once created, a String object never changes. Methods like toUpperCase() and replace() return new strings:
public class Immutability {
public static void main(String[] args) {
String s = "hello";
s.toUpperCase(); // result ignored: s is unchanged
System.out.println(s);
String upper = s.toUpperCase(); // a NEW string is returned
System.out.println(upper + " / original still: " + s);
String t = s;
s = s + " world"; // s now points to a new object
System.out.println("t = " + t + ", s = " + s);
}
}
hello HELLO / original still: hello t = hello, s = hello world
Why immutability matters:
- Pooling: sharing is safe only because nobody can change a pooled string.
- Security: file paths, URLs and class names cannot be altered after validation.
- Thread safety: strings can be shared between threads without synchronization.
- Hashing: the hash code is cached, making strings fast and reliable
HashMapkeys.
3. Comparing Strings: == vs equals()
| Comparison | Checks | Use |
|---|---|---|
a == b | Same object (reference) | Almost never for strings |
a.equals(b) | Same characters | Content equality |
a.equalsIgnoreCase(b) | Same characters, ignoring case | User input, codes |
a.compareTo(b) | Lexicographic order (negative, 0, positive) | Sorting |
Objects.equals(a, b) | Content, null-safe | When either may be null |
Write "admin".equals(role) rather than role.equals("admin") to avoid a NullPointerException when role is null.
4. Commonly Used String Methods
import java.util.Arrays;
public class CommonMethods {
public static void main(String[] args) {
String s = " Java By Techie ";
String t = s.strip();
System.out.println("strip() : [" + t + "]");
System.out.println("length() : " + t.length());
System.out.println("charAt(5) : " + t.charAt(5));
System.out.println("indexOf(\"By\") : " + t.indexOf("By"));
System.out.println("substring(5, 7) : " + t.substring(5, 7));
System.out.println("toLowerCase() : " + t.toLowerCase());
System.out.println("replace(' ', '-') : " + t.replace(' ', '-'));
System.out.println("contains(\"Tech\") : " + t.contains("Tech"));
System.out.println("startsWith(\"Java\") : " + t.startsWith("Java"));
System.out.println("split(\" \") : " + Arrays.toString(t.split(" ")));
System.out.println("isBlank() of \" \" : " + " ".isBlank());
System.out.println("repeat(3) : " + "ab".repeat(3));
System.out.println("join : " + String.join(", ", "Java", "Spring", "Kafka"));
System.out.println("equalsIgnoreCase : " + "JAVA".equalsIgnoreCase("java"));
System.out.println("compareTo : " + "apple".compareTo("banana"));
System.out.println("formatted : " + "%s scored %d".formatted("Asha", 92));
System.out.println("chars().count() : " + t.chars().filter(Character::isUpperCase).count() + " uppercase");
}
}
strip() : [Java By Techie]
length() : 14
charAt(5) : B
indexOf("By") : 5
substring(5, 7) : By
toLowerCase() : java by techie
replace(' ', '-') : Java-By-Techie
contains("Tech") : true
startsWith("Java") : true
split(" ") : [Java, By, Techie]
isBlank() of " " : true
repeat(3) : ababab
join : Java, Spring, Kafka
equalsIgnoreCase : true
compareTo : -1
formatted : Asha scored 92
chars().count() : 3 uppercase
| Category | Methods |
|---|---|
| Inspect | length, charAt, isEmpty, isBlank (11), chars |
| Search | indexOf, lastIndexOf, contains, startsWith, endsWith, matches |
| Extract | substring, split, lines (11), toCharArray |
| Transform | toUpperCase, toLowerCase, trim, strip (11), replace, replaceAll, repeat (11), indent (12) |
| Build | concat, join, format, formatted (15), valueOf |
strip() removes all Unicode whitespace, while the older trim() removes only characters up to U+0020.
5. Concatenation and Performance
The + operator is fine for a few pieces; the compiler optimises it. In loops, however, each += creates a new string and copies all previous characters. Use StringBuilder instead:
public class ConcatPerformance {
public static void main(String[] args) {
int n = 20_000;
long start = System.nanoTime();
String s = "";
for (int i = 0; i < n; i++) s += "x"; // creates a new String every time: O(n^2)
long plusMs = (System.nanoTime() - start) / 1_000_000;
start = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) sb.append("x"); // appends in place
String built = sb.toString();
long sbMs = (System.nanoTime() - start) / 1_000_000;
System.out.println("Same result: " + s.equals(built));
System.out.println("StringBuilder faster: " + (sbMs < plusMs));
}
}
Same result: true StringBuilder faster: true
| Class | Mutable? | Thread-safe? | Use for |
|---|---|---|---|
String | No | Yes (immutable) | Fixed text, keys, constants |
StringBuilder | Yes | No | Building text in one thread (most cases) |
StringBuffer | Yes | Yes (synchronized) | Legacy code shared across threads |
6. Under the Hood
- Since Java 9, compact strings store Latin-1 text in one byte per character instead of two, roughly halving memory for most strings.
- Since Java 7, the string pool lives in the main heap, so pooled strings can be garbage-collected.
Stringisfinal, so it cannot be subclassed and its behaviour is guaranteed.
7. Summary
- A
Stringis an immutable sequence of characters; methods return new strings. - Literals are pooled and shared;
new String()creates separate objects. - Compare content with
equals(), never with==. - Use text blocks for multi-line text and
StringBuilderfor building strings in loops.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is a String in Java?
An object of the final class java.lang.String that represents an immutable sequence of characters.
Q2. Why are strings immutable in Java?
For safe pooling, security, thread safety and reliable cached hash codes for use as map keys.
Q3. What is the string pool?
A JVM-managed area of the heap where string literals are stored once and shared, saving memory.
Q4. What is the difference between == and equals() for strings?
== compares references (same object); equals() compares characters. Always use equals() for content.
Q5. How many objects does new String("Java") create?
Up to two: the literal "Java" in the pool (if not already there) and a new String object on the heap.
Q6. What does intern() do?
It returns the pooled string with the same content, adding it to the pool if necessary.
Q7. What is the difference between String, StringBuilder and StringBuffer?
String is immutable. StringBuilder is mutable and not synchronized. StringBuffer is mutable and synchronized.
Q8. Why is String final?
So no subclass can break its immutability or change its behaviour, which the JVM, security code and collections rely on.
Q9. What is the difference between trim() and strip()?
trim() removes characters up to U+0020. strip() (Java 11) removes all Unicode whitespace.
Q10. What is the difference between isEmpty() and isBlank()?
isEmpty() is true only for length 0. isBlank() (Java 11) is also true for strings containing only whitespace.
Q11. Is string concatenation with + slow?
Not for a single expression, which the compiler optimises. Inside loops it creates many temporary strings; use StringBuilder there.
Q12. What are text blocks?
Multi-line string literals delimited by """, standard since Java 15, that preserve formatting and need fewer escape characters.
Q13. How do I convert other types to String?
Use String.valueOf(x), Integer.toString(n), obj.toString() or concatenation with "". String.valueOf is null-safe.
Q14. How do I convert a String to a number?
Use Integer.parseInt, Double.parseDouble and similar methods, which throw NumberFormatException for invalid input.
Q15. How do I reverse a String?
new StringBuilder(s).reverse().toString().
Q16. Is String thread-safe?
Yes. Because it is immutable, any number of threads can share it safely.
Q17. What are compact strings?
A Java 9 optimisation that stores strings containing only Latin-1 characters with one byte per character, reducing memory use.
Q18. Why should passwords be stored in char[] rather than String?
A char[] can be wiped after use, while an immutable String stays in memory until garbage-collected and may appear in dumps.
Q19. How does split() work?
It splits around matches of a regular expression and returns an array; trailing empty strings are removed. Escape regex characters, for example split("\\.").
Q20. What does compareTo() return?
A negative number if the string sorts before the argument, zero if equal, and a positive number if it sorts after.