Fundamentals 10 min read

Mastering Java Strings: When to Use equals vs == and Common Pitfalls

Java's String class is immutable and stored in a constant pool; the article explains the difference between == and equals, demonstrates common methods for inspection, transformation, splitting, and conversion, and shows best practices for concatenation with StringBuilder, thread‑safe StringBuffer, and newer utilities like join, repeat, format, and text blocks.

CodeNotes
CodeNotes
CodeNotes
Mastering Java Strings: When to Use equals vs == and Common Pitfalls

What is String

String is the most frequently used class in Java for storing text. It is immutable: every modification creates a new object while the original remains unchanged.

String literal pool

Java stores string literals in a constant pool so that identical literals share the same object.

String a = "hello";
String b = "hello";
System.out.println(a == b);   // true, same pool object

String c = new String("hello");
System.out.println(a == c);   // false, new creates a heap object
System.out.println(a.equals(c)); // true, same content

Therefore, == compares references, equals() compares content. Placing a constant first in equals() avoids NullPointerException.

Common String methods

Information retrieval

String s = "Hello, World!";
s.length();          // 13
s.charAt(0);         // 'H'
s.indexOf("World"); // 7
s.contains("World"); // true
s.startsWith("Hello"); // true
s.endsWith("!");   // true
s.isEmpty();         // false
s.isBlank();         // false (Java 11+)

Transformations

String s = "  Hello World  ";
s.trim();            // "Hello World"
s.strip();           // "Hello World" (Java 11+)
s.toUpperCase();    // "  HELLO WORLD  "
s.toLowerCase();    // "  hello world  "
s.replace("World","Java"); // "  Hello Java  "

Substring and split

String s = "2024-05-25";
s.substring(5);          // "05-25"
s.substring(0,4);        // "2024"
s.split("-");            // ["2024","05","25"]
Two pitfalls of split() : The argument is a regular expression, so special characters like . must be escaped. Trailing empty strings are discarded unless a negative limit is supplied. <code>"a.b.c".split("."); // returns empty array! "a.b.c".split("\\."); // ["a","b","c"] "a,b,,".split(","); // ["a","b"] "a,b,,".split(",", -1); // ["a","b","",""] </code>

String comparison

Never use == to compare content; use equals() (or equalsIgnoreCase() for case‑insensitive comparison).

String a = new String("hello");
String b = new String("hello");
System.out.println(a == b);          // false, compares addresses
System.out.println(a.equals(b));   // true, compares content
System.out.println(a.equalsIgnoreCase("HELLO")); // true

Constant‑first pattern prevents NullPointerException:

String status = null;
"active".equals(status); // safe, returns false

StringBuilder for efficient concatenation

In loops, avoid the + operator; use StringBuilder to modify a single mutable buffer.

// Bad: creates many temporary String objects
String result = "";
for (int i = 0; i < 1000; i++) {
    result += i;
}

// Good: modifies the same buffer
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i);
}
String result = sb.toString();

Common StringBuilder methods:

StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(", ").append("World");
sb.insert(5, "!");
sb.delete(0, 5);
sb.reverse();
sb.toString();

StringBuilder vs StringBuffer

StringBuilder

: not thread‑safe, fast, suitable for single‑threaded code. StringBuffer: methods are synchronized, slower, required only when multiple threads share the same mutable buffer.

Newer Java utilities (Java 8+)

// Join multiple strings with a delimiter (Java 8+)
String.join("-", "2024", "05", "25"); // "2024-05-25"
String.join(",", list); // joins List<String>

// Repeat a character N times (Java 11+)
"=".repeat(20); // 20 equal signs

// Format with placeholders
String.format("Name:%s Age:%d", "Zhang", 25); // "Name:Zhang Age:25"

// Switch on String (Java 7+)
switch (status) {
    case "NEW" -> System.out.println("New order");
    case "PAID" -> System.out.println("Paid");
    default -> System.out.println("Unknown");
}

Text blocks (Java 15+)

Triple‑quoted strings allow multi‑line literals without manual newline characters or concatenation. Common leading indentation is stripped automatically.

String json = """
{
    "name": "Zhang",
    "age": 25
}
""";

String sql = """
SELECT id, name, status
FROM orders
WHERE user_id = ?
  AND status = 'PAID'
""";

String and primitive conversion

// Number to String
String s1 = String.valueOf(100); // "100"
String s2 = 100 + "";           // "100"

// String to number
int n = Integer.parseInt("100");   // 100
double d = Double.parseDouble("3.14"); // 3.14

// Invalid format throws NumberFormatException
// int err = Integer.parseInt("abc"); // throws

Practical examples

// Build dynamic SQL (e.g., MyBatis)
StringBuilder sql = new StringBuilder("SELECT * FROM orders WHERE 1=1");
if (status != null) {
    sql.append(" AND status = '").append(status).append("'");
}
if (userId != null) {
    sql.append(" AND user_id = ").append(userId);
}

// Mask phone number
String phone = "13812345678";
String masked = phone.substring(0,3) + "****" + phone.substring(7); // 138****5678

// Split CSV line
String csv = "Zhang,25,Male,Beijing";
String[] fields = csv.split(",");
String name = fields[0]; // "Zhang"

Summary

String is immutable; literals use the constant pool, new String() always creates a new heap object.

Use equals() for content comparison; == checks reference identity. Placing a constant first avoids NullPointerException.

Prefer StringBuilder for concatenation in single‑threaded code; use StringBuffer only when thread‑safe mutation is required. split() takes a regular expression; escape special characters and use a negative limit to retain trailing empty strings.

Java 8+ utilities such as String.join, repeat, format, and switch on strings simplify common tasks.

Text blocks (Java 15+) provide clean multi‑line literals with automatic indentation handling.

Convert between strings and numbers with Integer.parseInt, Double.parseDouble, handling NumberFormatException as needed.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaStringJava 8StringBuildertext blocksequals vs ==
CodeNotes
Written by

CodeNotes

Discuss code and AI, and document daily life and personal growth.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.