AlgoInsight

Free lesson · Java Basic To Advance

String Basics

Easy7 min readjava

The Most-Used Class

Of all the classes in Java's standard library, String is used most. Every program handles text. Logging, configuration, user input, file paths, network protocols, JSON parsing — all built on strings. Mastering String is foundational, and the subtleties (immutability, the String pool, equality, the StringBuilder distinction) come up in nearly every Java interview.

Module 5 covers Strings in depth. We start with the basics: creation, access, common methods. Later Topics cover String methods in detail (5.2), immutability and the pool (5.3), StringBuilder for mutation (5.4), formatting (5.6), comparison (5.7), and regex (5.8). The Module closes with a Signature Interview Lens (5.9) covering the highest-frequency String interview questions.

I'm Olena, continuing through Module 5. Strings are deceptively simple — the syntax is friendly but the underlying mechanics have caught every Java developer at least once.

What a String Is

A String in Java is an immutable sequence of characters. The internal representation has evolved across Java versions:

The compact-string optimization (JEP 254) was a major memory savings for typical applications, where most strings are ASCII. The behavior is unchanged from the developer's perspective — only the internal storage is different.

The critical word is immutable. Once a String is created, its content cannot be changed. Every operation that "modifies" a String actually returns a new String. We cover immutability in detail in Topic 5.3.

Creating Strings

Two ways:

String literal:

String name = "Olena";

The most common form. Java has special handling for string literals — they're stored in the String pool (Topic 5.3), and identical literals reference the same object.

Constructor:

String name = new String("Olena");
String fromBytes = new String(new byte[]{72, 105});      // "Hi"
String fromChars = new String(new char[]{'H', 'i'});      // "Hi"
String substring = new String("Hello", 1, 3);             // "ell"

Using new String("...") creates a new String object even if the same content already exists in the pool. This is almost always wrong — it allocates unnecessary memory. The literal form is preferred:

// Bad — creates unnecessary object
String s1 = new String("hello");

// Good — uses the pool
String s2 = "hello";

The exception: when you specifically need to ensure a separate object, which is extremely rare. For everyday code, always use literals.

Accessing Characters

Strings are not arrays, but they have similar access patterns:

String name = "Olena";

System.out.println(name.length());       // 5
System.out.println(name.charAt(0));      // 'O'
System.out.println(name.charAt(4));      // 'a'

// name.charAt(5) throws StringIndexOutOfBoundsException

Note: length() is a method on String (with parens), but length is a property on arrays (no parens). This inconsistency catches everyone at least once.

Indexing is zero-based, like arrays. The last character is at length() - 1.

For iterating over all characters:

String text = "Hello";
for (int i = 0; i < text.length(); i++) {
    char c = text.charAt(i);
    System.out.println(c);
}

// Enhanced for doesn't work directly on String
// for (char c : text) { ... }  // compile error

// But you can convert to a char array
for (char c : text.toCharArray()) {
    System.out.println(c);
}

Strings aren't Iterable<Character> directly (a long-standing design limitation), so the enhanced for loop needs an explicit conversion.

Interactive animation: A String reads like an array - zero-based charAt and exclusive ends, but length() takes parentheses.

Concatenation

Two ways:

Using +:

String greeting = "Hello, " + name + "!";

The + operator concatenates Strings. It also converts other types to String automatically:

String result = "Score: " + 42;          // "Score: 42"
String mixed = 1 + 2 + " items";          // "3 items" (left-to-right)
String mixed2 = "items: " + 1 + 2;        // "items: 12"

The left-to-right evaluation matters. In the first version, 1 + 2 is integer arithmetic (= 3), then 3 + " items" is concatenation. In the second, "items: " + 1 is concatenation immediately, then ... + 2 is also concatenation.

Using concat:

String greeting = "Hello, ".concat(name).concat("!");

Less common. Returns a new String. Doesn't handle other types — both operands must be Strings.

Under the hood, + is converted by the compiler to StringBuilder operations (Topic 5.4). For one or two concatenations, + is fine. For many concatenations in a loop, use StringBuilder explicitly.

Interactive animation: += in a loop allocates a new String every pass, while one StringBuilder appends into a single buffer.

Useful String Methods (Preview)

A sampling of the most-used methods. Topic 5.2 covers them in depth:

String s = "Hello, World!";

s.length();              // 13
s.charAt(7);             // 'W'
s.indexOf("World");      // 7
s.indexOf("xyz");        // -1 (not found)
s.substring(7, 12);      // "World"
s.toUpperCase();         // "HELLO, WORLD!"
s.toLowerCase();         // "hello, world!"
s.contains("World");     // true
s.startsWith("Hello");   // true
s.endsWith("!");         // true
s.replace("World", "Java"); // "Hello, Java!"
s.trim();                // "Hello, World!" (no surrounding spaces here)
s.split(", ");           // ["Hello", "World!"]
s.isEmpty();             // false
s.isBlank();             // false (Java 11+)

Each returns a new String — the original is unchanged. This is fundamental: String methods don't mutate.

String s = "hello";
s.toUpperCase();           // returns "HELLO" but discarded
System.out.println(s);     // still "hello"

s = s.toUpperCase();        // now we assign the result
System.out.println(s);     // "HELLO"

Forgetting to capture the return value is one of the most common Java beginner mistakes.

String Equality

Two ways to compare strings, with very different semantics:

String a = "hello";
String b = "hello";
String c = new String("hello");

System.out.println(a == b);          // true — both reference the pool
System.out.println(a == c);          // false — c is a separate object
System.out.println(a.equals(c));     // true — same content

Always use .equals() for content comparison. == compares references and returns true only when both variables point to the same object. Due to String pooling, == happens to work for literals — but this is unreliable. Strings from input, parsing, or arithmetic might not be in the pool.

For case-insensitive comparison:

"hello".equalsIgnoreCase("HELLO");   // true

We cover String comparison in detail in Topic 5.7. For now: .equals() always.

Interactive animation: == is true for two literals but false for new String or typed input, while .equals() compares content every time.

Default Behavior with null

A String reference can be null. Operations on null Strings throw NullPointerException:

String s = null;
s.length();          // NPE
s.equals("hello");   // NPE

// Defensive — null-safe equality
"hello".equals(s);   // false, no NPE (literal on left)
Objects.equals(s, "hello");  // false, no NPE either way

The pattern "literal".equals(maybeNull) is sometimes called "Yoda comparison" — putting the literal first to avoid NPE on a null left side. Objects.equals() is symmetric and handles null on either side.

graph TD
    A[String Creation] --> B[Literal: &quot;hello&quot;]
    A --> C[Constructor: new String]
    A --> D[Methods returning String]

    B --> E[Stored in String pool]
    B --> F[Identical literals share object]

    C --> G[New object created<br/>not from pool]

    D --> H[Result is in pool or heap<br/>depending on operation]

    style B fill:#10b981,color:#fff
    style C fill:#dc2626,color:#fff
    style D fill:#f59e0b,color:#fff
This diagram shows the three ways Strings get created in Java. String literals — quoted text in source code — are stored in the String pool, a special memory area that deduplicates identical strings. Two literal references to "hello" point to the same object. Using the new String constructor explicitly creates a new object, bypassing the pool — this is almost always wasteful. String methods like toUpperCase or substring return new String objects whose pool status depends on the operation. The pool is the key to understanding why string equality with double-equals sometimes works and sometimes doesn't.

String Conversion

Converting other types to String:

int n = 42;
String s1 = String.valueOf(n);     // "42"
String s2 = Integer.toString(n);   // "42"
String s3 = "" + n;                 // "42" (concatenation)
String s4 = n + "";                 // "42" (same)

double d = 3.14;
String s5 = String.valueOf(d);     // "3.14"

boolean b = true;
String s6 = String.valueOf(b);     // "true"

Object o = new ArrayList<>();
String s7 = String.valueOf(o);     // "[]" or whatever toString returns
String s8 = o.toString();           // same, but NPE if o is null

String.valueOf() handles null safely — it returns "null" instead of throwing NPE. For that reason, it's often preferred over toString() directly when the value might be null.

Converting String to other types:

String s = "42";
int n = Integer.parseInt(s);       // 42
double d = Double.parseDouble("3.14");   // 3.14
boolean b = Boolean.parseBoolean("true"); // true

int invalid = Integer.parseInt("hello");   // NumberFormatException

parseXxx methods throw NumberFormatException on invalid input. Always wrap in try/catch if the input is untrusted (user input, file content, network data).

Common Pitfalls

Warning: Using == for String comparison. Sometimes works (literals share pool), sometimes fails (different objects with same content). Always use .equals().

Forgetting that String methods return new Strings. s.toUpperCase() doesn't change s — you have to assign: s = s.toUpperCase(). Many beginners write s.trim(); expecting the variable to change.

Using new String("literal"). Creates an unnecessary object. Use the literal directly.

Calling methods on null Strings. String s = null; s.length(); throws NPE. Use defensive patterns like "literal".equals(s) or Objects.equals() for null-safe comparison.

Confusing length() and length. length() is for String. length (no parens) is for arrays. size() is for collections. Mixing them up is a frequent compile error.

Inefficient concatenation in loops. String s = ""; for (...) s += item; creates a new String each iteration — O(n²) total. Use StringBuilder for loops (Topic 5.4).

Why This Matters in Interviews

Interview: String questions appear in every Java interview. The basics (equality, immutability, common methods) are screen-level. The deeper material (String pool, StringBuilder performance, regex) comes in technical rounds.

Topic 5.9 covers the Interview Lens with full senior-candidate answers to the highest-frequency String questions.

Try It

Exercise: Verify each behavior in your IDE:

  1. Compare two literal Strings with == and .equals(). Note both are true.
  2. Compare a literal with new String("...") using ==. Note it's false.
  3. Call s.toUpperCase() without assigning. Print s — note it's unchanged.
  4. Try Integer.parseInt("abc"). Observe the NumberFormatException.
  5. Try String.valueOf(null) vs ((Object)null).toString(). Note the difference (one returns "null", the other throws NPE).
  6. Concatenate 1000 strings in a loop with += vs StringBuilder. Time both. Note the dramatic difference.

Each behavior is something interviewers expect you to know precisely.

Back to Java Basic To Advance