Strings in Java
By the Syncfusion DevTutorials team · Last updated
Work with Java text: immutability, the String Pool, literals and text blocks, formatting, common String methods, comparing strings, and building text with StringBuilder and StringBuffer.
Think about a printed name badge.
The name is printed on the card. You cannot rub out one letter and write a new one. If the name is wrong, you print a fresh badge and throw the old one away.
A Java String works the same way. Once a string is created, its text never changes. Every so-called change actually creates a new string.
In simple words: a String is a piece of text, and it cannot be changed after it is created.
What You Will Learn
In this lesson, you will learn:
- What a
Stringis and why it is immutable. - How Java saves memory with the String Pool.
- How to join text and format it neatly.
- The most useful
Stringmethods. - How to compare strings correctly.
- How
StringBuilderandStringBufferbuild text efficiently. - When to use
Stringand when to useStringBuilder.
Start With a Working Example
Press Run.
A String answers questions about its own text
public class Main {
public static void main(String[] args) {
String email = " Asha.Kumar@Mail.com ";
String clean = email.trim().toLowerCase();
System.out.println("Clean: " + clean);
System.out.println("Length: " + clean.length());
System.out.println("Gmail user? " + clean.endsWith("@gmail.com"));
System.out.println("Name part: " + clean.substring(0, clean.indexOf("@")));
}
}
Expected output:
Clean: asha.kumar@mail.com
Length: 19
Gmail user? false
Name part: asha.kumar
trim() removes spaces at both ends. toLowerCase() makes every letter small. The other methods measure, check, and cut the text.
Try This
Change the email to "ravi@gmail.com". Predict all four lines, then press Run.
Introduction to Strings
A string is a sequence of characters. It can hold a word, a sentence, a number written as text, or even nothing at all.
String name = "Meena";
String sentence = "Java is fun.";
String empty = "";
Strings are everywhere in real programs: names, passwords, messages, file names, and web addresses.
Each character in a string has a position called an index. Like arrays, the index starts at 0.
Index: 0 1 2 3 4
M e e n a
String Immutability
Immutable means "cannot be changed".
Once a String is created, its characters can never change. Methods like toUpperCase() do not change the original. They return a new string.
toUpperCase returns a new string and leaves the original alone
public class Main {
public static void main(String[] args) {
String city = "pune";
city.toUpperCase();
System.out.println("After calling toUpperCase: " + city);
city = city.toUpperCase();
System.out.println("After storing the result: " + city);
}
}
Expected output:
After calling toUpperCase: pune
After storing the result: PUNE
The first call made a new string, "PUNE", but nobody stored it. So it was thrown away, and city still pointed to "pune".
The second time, the new string was stored back in city. The variable now points to the new string. The old "pune" string itself never changed.
Why Strings Are Immutable
- Safety. A string passed to a method cannot be changed behind your back.
- Sharing. Many variables can safely share one string. This makes the String Pool possible.
- Security. File paths and passwords cannot be changed after they are checked.
String Pool
The String Pool is a special area of memory where Java keeps string literals.
When you write a literal like "Java", Java first looks in the pool. If "Java" is already there, it reuses that same string. It does not make a second copy.
Think of a shared library book. If ten students want the same book, the library lends the same copy. It does not print ten copies.
This only works because strings are immutable. If one variable could change the shared string, every other variable would change too.
new String("Java") skips the pool. It always makes a brand-new object.
Literals share one pooled string, new does not
public class Main {
public static void main(String[] args) {
String a = "Java";
String b = "Java";
String c = new String("Java");
System.out.println("a == b: " + (a == b));
System.out.println("a == c: " + (a == c));
System.out.println("a.equals(c): " + a.equals(c));
}
}
Expected output:
a == b: true
a == c: false
a.equals(c): true
a and b point to the same pooled string, so == is true.
c is a separate object made with new, so a == c is false, even though the text is the same.
equals() compares the text itself, so it is true.
String Pool Rest of memory
┌──────────┐ ┌──────────┐
│ "Java" │ ◄── a, b │ "Java" │ ◄── c
└──────────┘ └──────────┘
There is rarely a good reason to write new String("..."). Use a literal.
String Literals
A string literal is text written directly in the code, inside double quotes.
Some characters need an escape sequence, which is a backslash followed by a letter or symbol:
| Escape | Meaning |
|---|---|
\n | New line |
\t | Tab |
\" | Double quote |
\\ | Backslash |
Text Blocks
For text that spans many lines, Java has text blocks. A text block starts and ends with three double quotes, """.
Escapes and a text block
public class Main {
public static void main(String[] args) {
System.out.println("Name:\tAsha");
System.out.println("She said \"Hello\"");
System.out.println("Path: C:\\Users\\Asha");
String address = """
12 Lake Road
Chennai
600001""";
System.out.println(address);
}
}
Expected output:
Name: Asha
She said "Hello"
Path: C:\Users\Asha
12 Lake Road
Chennai
600001
The text block keeps its line breaks. Java removes the indentation that all lines share, so the address starts at the left edge.
String Formatting
Concatenation
Concatenation means joining strings together. You use the + operator, or the concat() method.
When either side of + is a String, Java turns the other side into text and joins them.
+ joins text, and order matters
public class Main {
public static void main(String[] args) {
String first = "Asha";
String last = "Kumar";
System.out.println(first + " " + last);
System.out.println(first.concat(" ").concat(last));
System.out.println("Score: " + 40 + 2);
System.out.println("Score: " + (40 + 2));
System.out.println(40 + 2 + " is the score");
}
}
Expected output:
Asha Kumar
Asha Kumar
Score: 402
Score: 42
42 is the score
Java works from left to right.
- In
"Score: " + 40 + 2, the text comes first, so40and2are joined as text. - In
40 + 2 + " is the score", the two numbers come first, so they are added to make42before the text is joined.
Use brackets whenever you want maths inside a sentence.
+ can join a string with any value. Numbers and boolean values become their text form. Objects are turned into text with their toString() method. A null value becomes the word null.
Formatting Methods
Joining many pieces with + can get messy. Formatting methods let you write a template with placeholders, then fill them in.
String.format(template, values...)returns the formatted string.System.out.printf(template, values...)prints it straight away."template".formatted(values...)does the same asString.format, in a shorter form.
Each placeholder starts with %:
| Placeholder | Used for | Example output |
|---|---|---|
%s | Any value as text | Asha |
%d | Whole numbers | 42 |
%.2f | A decimal with 2 places | 3.50 |
%n | A new line | — |
%5d | A whole number, padded to 5 characters | 42 |
Templates with placeholders
public class Main {
public static void main(String[] args) {
String item = "Notebook";
int quantity = 3;
double price = 45.5;
String line = String.format("%s x %d = %.2f", item, quantity, quantity * price);
System.out.println(line);
System.out.printf("Total due: Rs. %.2f%n", quantity * price);
String report = "%s scored %d%%".formatted("Ravi", 87);
System.out.println(report);
}
}
Output:
Notebook x 3 = 136.50
Total due: Rs. 136.50
Ravi scored 87%
%.2f always shows two decimal places, so 136.5 becomes 136.50.
%% prints a real percent sign, because a single % starts a placeholder.
The values fill the placeholders in order. The first value goes into the first placeholder.
String Class
String is a class in the java.lang package. Java imports java.lang for you, so you never need an import for String.
Because String is a class, every string is an object. That is why you can call methods on it with a dot, like name.length().
A few facts about the String class:
- It is
final, so no other class can extend it. - A
Stringvariable can benull, which means it points to no string at all. Calling a method onnullstops the program with aNullPointerException. - An empty string
""is a real string with zero characters. It is not the same asnull.
String Methods
The String class has many methods. Here are the ones you will use most.
Length and Characters
Measure the text and read single characters
public class Main {
public static void main(String[] args) {
String word = "Programming";
System.out.println("Length: " + word.length());
System.out.println("First letter: " + word.charAt(0));
System.out.println("Last letter: " + word.charAt(word.length() - 1));
System.out.println("Is empty? " + word.isEmpty());
System.out.println("Is blank? " + " ".isBlank());
}
}
Expected output:
Length: 11
First letter: P
Last letter: g
Is empty? false
Is blank? true
charAt(index) returns one char. The last index is length() - 1, just like an array.
isBlank() is true for a string that is empty or contains only spaces.
Searching and Cutting
Find, check and cut parts of a string
public class Main {
public static void main(String[] args) {
String file = "report_2026_final.pdf";
System.out.println(file.indexOf("_"));
System.out.println(file.lastIndexOf("_"));
System.out.println(file.contains("2026"));
System.out.println(file.startsWith("report"));
System.out.println(file.endsWith(".pdf"));
System.out.println(file.substring(7, 11));
System.out.println(file.substring(file.lastIndexOf(".") + 1));
}
}
Expected output:
6
11
true
true
true
2026
pdf
indexOf returns the position of the first match, or -1 if there is none.
substring(7, 11) returns the characters from index 7 up to, but not including, index 11. With one argument, substring goes to the end of the string.
Changing Case, Spaces and Content
Remember: each of these returns a new string.
Every method here returns a new string
public class Main {
public static void main(String[] args) {
String raw = " hello world ";
System.out.println("[" + raw.trim() + "]");
System.out.println(raw.trim().toUpperCase());
System.out.println(raw.replace("world", "Java").trim());
System.out.println("ha".repeat(3));
String csv = "Asha,Ravi,Meena";
String[] names = csv.split(",");
System.out.println(names.length + " names, second is " + names[1]);
System.out.println(String.join(" | ", names));
}
}
Expected output:
[hello world]
HELLO WORLD
hello Java
hahaha
3 names, second is Ravi
Asha | Ravi | Meena
split(",") breaks the text into an array at every comma. String.join does the opposite: it glues an array back together with a separator.
String Methods at a Glance
| Method | Returns | Example | Result |
|---|---|---|---|
length() | Number of characters | "Java".length() | 4 |
charAt(i) | The character at index i | "Java".charAt(1) | 'a' |
indexOf(s) | First position of s, or -1 | "Java".indexOf("v") | 2 |
substring(a, b) | Characters from a up to b | "Java".substring(1, 3) | "av" |
contains(s) | Whether s appears | "Java".contains("av") | true |
startsWith(s) | Whether it begins with s | "Java".startsWith("J") | true |
toUpperCase() | All capitals | "Java".toUpperCase() | "JAVA" |
toLowerCase() | All small letters | "Java".toLowerCase() | "java" |
trim() | Without spaces at both ends | " Java ".trim() | "Java" |
replace(a, b) | Every a swapped for b | "Java".replace("a", "o") | "Jovo" |
split(s) | An array, broken at s | "a,b".split(",") | ["a", "b"] |
isEmpty() | Whether the length is 0 | "".isEmpty() | true |
repeat(n) | The text repeated n times | "ab".repeat(2) | "abab" |
String Comparison
Comparing strings is one of the most common sources of bugs in Java.
equals()
equals() checks whether two strings hold the same text. This is almost always what you want.
equalsIgnoreCase()
equalsIgnoreCase() also compares the text, but treats capital and small letters as the same.
==
== checks whether two variables point to the same object in memory. It does not compare the text.
It may seem to work with literals, because of the String Pool. But text that comes from user input, a file, or a method like substring is often a different object. Then == gives false, even when the text matches.
compareTo()
compareTo() compares two strings in dictionary order. It returns:
- a negative number if the first string comes first;
0if they are equal;- a positive number if the first string comes later.
Four ways to compare strings
public class Main {
public static void main(String[] args) {
String saved = "admin";
String typed = "ADMIN".toLowerCase();
System.out.println("equals: " + saved.equals(typed));
System.out.println("==: " + (saved == typed));
System.out.println("equalsIgnoreCase: " + "Chennai".equalsIgnoreCase("CHENNAI"));
System.out.println("apple vs banana: " + "apple".compareTo("banana"));
System.out.println("pear vs pear: " + "pear".compareTo("pear"));
System.out.println("mango vs grape: " + "mango".compareTo("grape"));
}
}
Expected output:
equals: true
==: false
equalsIgnoreCase: true
apple vs banana: -1
pear vs pear: 0
mango vs grape: 6
typed holds "admin", the same text as saved. But it was made at run time by toLowerCase(), so it is a separate object. equals says true, while == says false.
"apple" comes before "banana", so compareTo gives a negative number. Only the sign matters, not the exact value.
Always compare text with equals(). A safe habit is to put the known literal first: "admin".equals(input). That version never throws a NullPointerException, even when input is null.
StringBuilder
Every time you change a String, Java makes a new one. In a loop that adds text hundreds of times, that means hundreds of thrown-away strings.
A StringBuilder is a mutable (changeable) sequence of characters. It changes its own text in place, without making a new object each time.
Think of a whiteboard. You can add words, rub some out, and insert others, all on the same board.
StringBuilder changes its own text in place
public class Main {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb);
sb.insert(0, ">> ");
System.out.println(sb);
sb.replace(3, 8, "Hi");
System.out.println(sb);
sb.reverse();
System.out.println(sb);
System.out.println("Length: " + sb.length());
}
}
Expected output:
Hello World
>> Hello World
>> Hi World
dlroW iH >>
Length: 11
Each call changes the same sb object. There is no need to write sb = sb.append(...).
| Method | What it does |
|---|---|
append(x) | Adds x to the end |
insert(i, x) | Adds x at index i |
delete(a, b) | Removes characters from a up to b |
replace(a, b, s) | Replaces characters from a up to b with s |
reverse() | Reverses the text |
toString() | Returns the text as a normal String |
Building Text in a Loop
This is the main reason StringBuilder exists.
Build a long string in a loop
public class Main {
public static void main(String[] args) {
StringBuilder line = new StringBuilder();
for (int i = 1; i <= 5; i++) {
line.append(i);
if (i < 5) {
line.append(" - ");
}
}
String result = line.toString();
System.out.println(result);
}
}
Expected output:
1 - 2 - 3 - 4 - 5
toString() turns the finished builder into a normal String when you are done.
StringBuffer
StringBuffer has the same methods as StringBuilder. You use it the same way.
The difference is safety with threads. A thread is one path of work, and a program can run several at the same time.
StringBufferis thread-safe. Only one thread can change it at a time.StringBuilderis not thread-safe, but it is faster.
StringBuffer works just like StringBuilder
public class Main {
public static void main(String[] args) {
StringBuffer log = new StringBuffer();
log.append("Start");
log.append(" -> Load");
log.append(" -> Save");
log.append(" -> Done");
System.out.println(log);
System.out.println("Steps text length: " + log.length());
}
}
Expected output:
Start -> Load -> Save -> Done
Steps text length: 29
For normal programs that use one thread, choose StringBuilder. Use StringBuffer only when several threads change the same text.
Strings vs StringBuilder
String | StringBuilder | StringBuffer | |
|---|---|---|---|
| Can it change? | No (immutable) | Yes (mutable) | Yes (mutable) |
| A change creates | A new object | Nothing new, it edits itself | Nothing new, it edits itself |
| Thread-safe? | Yes, because it cannot change | No | Yes |
| Speed for many changes | Slow | Fast | A little slower than StringBuilder |
| Best for | Fixed text, keys, labels | Building text in a loop | Building text shared between threads |
Easy Way to Remember: text that stays the same is a String. Text you build step by step is a StringBuilder.
Common mistakes
The following mistakes are common when working with strings. Each row shows what you see, why it happens and how to fix it.
| Symptom | Cause | Fix |
|---|---|---|
| A string looks unchanged after a method call | The new string was not stored | Assign the result back: s = s.trim(); |
| A match fails when the text looks the same | == was used on strings | Use equals() |
StringIndexOutOfBoundsException | An index of length() or more was used | Use indexes from 0 to length() - 1 |
NullPointerException | A method was called on a null string | Check for null, or put the literal first |
Total: 55 instead of Total: 10 | Text came before the maths | Put the maths in brackets |
char cannot be converted to String | Single quotes were used | Use double quotes for a String |
What to Remember
- A
Stringis immutable. Its methods return new strings, so store the result. - Literals are shared in the String Pool.
new String(...)makes a separate object. - Join text with
+, and use brackets for maths. UseString.formatorprintffor neat output. length(),charAt,indexOf,substring,split,replace, andtrimcover most daily string work.- Compare text with
equals(), never with==. UsecompareTo()for dictionary order. - Use
StringBuilderto build text step by step. UseStringBufferonly when threads share the text.
Next: DateTime