Java Full Course: Mastering the Language Strings in Java

Strings in Java

(Complete Notes | Beginner to Advanced | Professional & Exam-Oriented | Masterclass)

1. Introduction to Strings

In Java, a String is a sequence of characters used to represent text. Unlike many other programming languages where strings are arrays of characters, Java treats strings as objects of the built-in String class. Strings are immutable—once created, their values cannot be changed. This immutability enables features like string pooling, where literal strings are stored in a special heap area (the String Pool) to improve memory efficiency and performance.

Java provides three main types for working with sequences of characters:

  • String – immutable, thread safe, and the most commonly used.
  • StringBuilder – mutable, not thread safe; best for single threaded string manipulation.
  • StringBuffer – mutable, thread safe (synchronized); suitable for multi threaded environments.

In the following sections, we will explore:

  • Creating and initializing strings
  • String immutability and the String Pool
  • Common String methods (length, charAt, substring, equals, etc.)
  • String comparison (== vs equals())
  • Using StringBuilder and StringBuffer
  • Performance considerations and best practices

2. What is a String?

A String in Java is a sequence of characters. It is a class (java.lang.String) and represents an immutable object. Once a String object is created, its value cannot be changed. Any operation that appears to modify a string actually creates a new String object.


3. Creating Strings

There are two primary ways to create a String:

a) Using String Literal

String str1 = "Hello"; String str2 = "World";
  • This syntax creates a string literal. The JVM maintains a String Pool (also called String Intern Pool) to store such literals. If a literal already exists in the pool, a new object is not created; the existing reference is reused.
  • This is memory efficient and the recommended way.

b) Using the new Keyword

String str3 = new String("Hello");
  • This creates a new String object on the heap, even if the same value exists in the String Pool. It forces creation of a new object.

Comparison:

String a = "Java"; String b = "Java"; String c = new String("Java"); System.out.println(a == b); // true (same reference from pool) System.out.println(a == c); // false (different objects) System.out.println(a.equals(c)); // true (same content)

4. String Immutability and the String Pool

Immutability means that once a String object is created, its content cannot be changed. Any method that seems to modify the string (e.g., toUpperCase(), concat(), replace()) returns a new String object.

Why immutability?

  • Security: Strings are used in class loading, file paths, etc. Immutability prevents accidental or malicious changes.
  • Thread safety: Immutable objects can be shared freely without synchronization.
  • String Pool: Because strings are immutable, the JVM can safely store literals in a pool and reuse them, saving memory.

Example demonstrating immutability:

String s = "Hello"; s.toUpperCase(); // returns a new string, but s remains unchanged System.out.println(s); // Hello s = s.toUpperCase(); // assign the new string to s System.out.println(s); // HELLO

String Pool Internals:

  • When a string literal is created, the JVM checks if an identical string already exists in the pool. If yes, the reference is reused; otherwise, a new string is added to the pool.
  • You can manually add a string to the pool using intern():
String s1 = new String("Hello").intern(); String s2 = "Hello"; System.out.println(s1 == s2); // true

5. Common String Methods

The String class provides a rich set of methods. Here are the most frequently used ones:

MethodDescriptionExample
length()Returns the number of characters."Java".length() → 4
charAt(int index)Returns the character at the specified index."Java".charAt(1)'a'
substring(int beginIndex, int endIndex)Returns a substring (endIndex exclusive)."Hello".substring(1,4)"ell"
toLowerCase() / toUpperCase()Returns a new string in lower/upper case."Java".toUpperCase()"JAVA"
trim()Removes leading and trailing whitespace." Hi ".trim()"Hi"
replace(char old, char new)Replaces all occurrences of a character."Hello".replace('l','p')"Heppo"
startsWith(String prefix) / endsWith(String suffix)Checks prefix or suffix."Hello".startsWith("He")true
contains(CharSequence s)Checks if the string contains a sequence."Hello".contains("ell")true
indexOf(String str)Returns the index of the first occurrence."Hello".indexOf("l") → 2
lastIndexOf(String str)Returns the index of the last occurrence."Hello".lastIndexOf("l") → 3
equals(Object obj)Compares content (case sensitive)."Hi".equals("hi")false
equalsIgnoreCase(String another)Compares content ignoring case."Hi".equalsIgnoreCase("hi")true
compareTo(String another)Lexicographic comparison (returns int)."a".compareTo("b") → negative
split(String regex)Splits the string into an array."a,b,c".split(",")["a","b","c"]
join(CharSequence delimiter, CharSequence... elements)Joins strings with a delimiter (static).String.join("-", "a","b","c")"a-b-c"
isEmpty()Returns true if length is 0."".isEmpty()true
isBlank() (Java 11+)Returns true if string is empty or contains only whitespace." ".isBlank()true

Example usage:

String s = " Hello, World! "; System.out.println(s.trim()); // "Hello, World!" System.out.println(s.toUpperCase()); // " HELLO, WORLD! " System.out.println(s.substring(2, 7)); // "Hello" System.out.println(s.replace('o', '0')); // " Hell0, W0rld! " System.out.println(s.contains("World")); // true String[] parts = s.trim().split(","); System.out.println(Arrays.toString(parts)); // ["Hello", " World!"]

6. String Comparison

Crucial

[!IMPORTANT] Use equals() to compare content, not ==.

  • == compares references (whether they point to the same object).
  • equals() compares the character sequence.
String s1 = "Hello"; String s2 = "Hello"; String s3 = new String("Hello"); System.out.println(s1 == s2); // true (same literal) System.out.println(s1 == s3); // false (different objects) System.out.println(s1.equals(s3)); // true (same content)

Case insensitive comparison:

System.out.println("hello".equalsIgnoreCase("HELLO")); // true

Lexicographic comparison:

int result = "apple".compareTo("banana"); // negative because "apple" comes before "banana"

7. String Concatenation

Concatenation can be done in several ways:

a) Using + Operator

String s = "Hello" + " " + "World";
  • The compiler often uses StringBuilder behind the scenes.

b) Using concat() Method

String s = "Hello".concat(" ").concat("World");

c) Using StringBuilder or StringBuffer (efficient for many operations)

StringBuilder sb = new StringBuilder(); sb.append("Hello"); sb.append(" "); sb.append("World"); String s = sb.toString();
Tip

[!TIP] Performance note: For multiple concatenations in a loop, use StringBuilder (or StringBuffer for thread safety) to avoid creating many intermediate String objects.


8. StringBuilder and StringBuffer

Both classes are mutable sequences of characters. They are used when you need to modify strings frequently.

FeatureStringBuilderStringBuffer
MutabilityMutableMutable
Thread safetyNot synchronized (not thread safe)Synchronized (thread safe)
PerformanceFaster in single threaded environmentsSlower due to synchronization overhead
Common methodsappend(), insert(), delete(), reverse(), toString()Same as StringBuilder

Example:

StringBuilder sb = new StringBuilder("Hello"); sb.append(" World"); sb.insert(5, ","); sb.delete(5, 6); sb.reverse(); String result = sb.toString(); System.out.println(result); // "dlroW ,olleH"

When to use which:

  • Use String for immutable text.
  • Use StringBuilder for single threaded mutable text.
  • Use StringBuffer when multiple threads may access the same buffer.

9. Escape Sequences and Unicode

Java strings support escape sequences for special characters:

EscapeMeaning
`
`Newline
\tTab
\\\\Backslash
\"Double quote
\'Single quote
\uXXXXUnicode character (e.g., \u00A9 for ©)

Example:

String text = "Line1 Line2\tTabbed"; System.out.println(text);

10. Converting Other Types to String

  • Use String.valueOf() for any primitive or object:
String s = String.valueOf(123);
  • Or use concatenation with an empty string:
String s = "" + 123;
  • For objects, toString() is called automatically.

11. Common Pitfalls and Best Practices

PitfallExplanation / Solution
Using == for content comparisonAlways use equals() for content.
Inefficient concatenation in loopsUse StringBuilder instead of + in loops.
Assuming strings are mutableRemember immutability; each "modification" creates a new string.
Null stringsCalling methods on a null reference throws NullPointerException. Check with Objects.toString() or guard clauses.
String pool confusionUse intern() only when necessary; premature use can lead to memory issues.
Not specifying charset when converting bytesAlways specify charset to avoid platform dependent results: new String(bytes, StandardCharsets.UTF_8).

Best Practices:

  • Use string literals when possible to benefit from the String Pool.
  • For string concatenation in loops, prefer StringBuilder.
  • Use String.join() or String.format() for readable concatenation.
  • Use isEmpty() or isBlank() (Java 11+) to check for empty or blank strings.
  • When comparing strings, handle null appropriately, e.g., Objects.equals(str1, str2).

12. Key Points to Remember

  • Strings are objects of the String class and are immutable.
  • String literals are stored in the String Pool; duplicate literals share the same reference.
  • Use equals() for content comparison; == compares references.
  • StringBuilder (mutable, not thread safe) and StringBuffer (mutable, thread safe) are for efficient string manipulation.
  • Common methods: length(), charAt(), substring(), indexOf(), split(), trim(), toUpperCase(), toLowerCase().
  • Escape sequences ( , \t, etc.) allow special characters in strings.
  • Always consider immutability when designing classes; using String as a key in maps is safe because its hash code is cached.

13. Example: Putting It All Together

public class StringDemo { public static void main(String[] args) { // Creation String s1 = "Java"; String s2 = new String("Java"); // Comparison System.out.println(s1 == s2); // false System.out.println(s1.equals(s2)); // true // Immutability String s = "Hello"; s.toUpperCase(); // creates new string, but s unchanged System.out.println(s); // Hello s = s.toUpperCase(); // now s points to new string System.out.println(s); // HELLO // StringBuilder for efficient concatenation StringBuilder sb = new StringBuilder("Count: "); for (int i = 1; i <= 5; i++) { sb.append(i).append(", "); } sb.delete(sb.length() - 2, sb.length()); // remove last ", " System.out.println(sb.toString()); // Count: 1, 2, 3, 4, 5 // Using String methods String text = " Java Programming "; System.out.println(text.trim()); // "Java Programming" System.out.println(text.substring(2, 6)); // "Java" System.out.println(text.contains("Prog")); // true System.out.println(text.toLowerCase()); // " java programming " // Splitting String csv = "apple,banana,cherry"; String[] fruits = csv.split(","); System.out.println(Arrays.toString(fruits)); // [apple, banana, cherry] // Joining String joined = String.join(" | ", fruits); System.out.println(joined); // apple | banana | cherry } }

Hi! Need help with studies? 👋
AI