Skip to content

9. Strings in Java

Table of Contents


9.1 Strings & Text Blocks

9.1.1 Strings

9.1.1.1 Initializing Strings

In Java, a String is an object of the java.lang.String class, used to represent a sequence of characters.

Strings are immutable: once created, their content cannot be changed. Any operation that seems to modify a string actually creates a new one.

You can create and initialize strings in several ways:

String s1 = "Hello";                    // string literal
String s2 = new String("Hello");        // using constructor (not recommended)
String s3 = s1.toUpperCase();           // creates a new String ("HELLO")

Note

  • String literals are stored in the String pool, a special memory area used to avoid creating duplicate string objects.
  • Using the new keyword always creates a new object outside the pool.

9.1.1.2 The String Pool

Because String objects are immutable and widely used, they could easily occupy a large amount of memory in a Java program.

To reduce duplication, Java reuses all strings that are declared as literals (see example above), storing them in a dedicated area of the JVM known as the String Pool or Intern Pool.

Please check the Paragraph: "6.4.3 String Pool and Equality" in Chapter: 6. Instantiating Types for a deeper explanation and examples.

9.1.1.3 Special Characters and Escape Sequences

Strings can contain escape characters, which allow you to include special symbols or control characters (characters with a special meaning in Java).
An escape sequence starts with a backslash \.

Note

Table of Special Characters & Escape Sequences in Strings

Escape Meaning Java Example Result
\" double quote "She said \"Hi\"" She said "Hi"
\\ backslash "C:\\Users\\Alex" C:\Users\Alex
\n newline (LF) "Hello\nWorld" Hello
World
\r carriage return (CR) "A\rB" CR before B
\t tab "Name\tAge" Name    Age
\' single quote "It\'s ok" It's ok
\b backspace "AB\bC" AC (the B is removed visually)
\uXXXX Unicode code unit "\u00A9" ©

9.1.1.4 Rules for String Concatenation

As introduced in the Chapter on 5. Java Operators, the symbol + normally represents arithmetic addition when used with numeric operands.

However, when applied to Strings, the same operator performs string concatenation — it creates a new string by joining operands together.

Since the operator + may appear in expressions where both numbers and strings are present, Java applies a specific set of rules to determine whether + means numeric addition or string concatenation.

9.1.1.5 Concatenation Rules

  • If both operands are numeric, + performs numeric addition.
  • If at least one operand is a String, the + operator performs string concatenation.
  • Evaluation is strictly left-to-right, because + is left-associative.

This means that once a String appears on the left side of the expression, all subsequent + operations become concatenations.

Tip

Because evaluation is left-to-right, the position of the first String operand determines how the rest of the expression is evaluated.

  • Examples
// *** Pure numeric addition

int a = 10 + 20;        // 30
double b = 1.5 + 2.3;   // 3.8



// *** String concatenation when at least one operand is a String

String s = "Hello" + " World";  // "Hello World"
String t = "Value: " + 10;      // "Value: 10"



// *** Left-to-right evaluation affects the result

System.out.println(1 + 2 + " apples"); 
// 3 + " apples"  → "3 apples"

System.out.println("apples: " + 1 + 2); 
// "apples: 1" + 2 → "apples: 12"



// *** Adding parentheses changes the meaning

System.out.println("apples: " + (1 + 2)); 
// parentheses force numeric addition → "apples: 3"



// *** Mixed types with multiple operands

String result = 10 + 20 + "" + 30 + 40;
// (10 + 20) = 30
// 30 + ""  = "30"
// "30" + 30 = "3030"
String out = "3030" + 40; // "303040"

System.out.println(1 + 2 + "3" + 4 + 5);
// Step 1: 1 + 2 = 3
// Step 2: 3 + "3" = "33"
String r = "33" + 4;  // "334"
// Step 4: "334" + 5 = "3345"



// *** null is represented as a string when concatenated

System.out.println("AB" + null);
// ABnull

9.1.2 Text Blocks (since Java 15)

A text block is a multi-line string literal introduced to simplify writing large strings (such as HTML, JSON, or code) without the need for many escape sequences.

A text block starts and ends with three double quotes (""").

You can use text blocks everywhere you would use strings.

String html = """
    <html>
        <body>
            <p>Hello, world!</p>
        </body>
    </html>
    """;

Note

  • Text blocks automatically include line breaks and indentation for readability. Newlines are normalized to \n.
  • Double quotes inside the block usually don’t need escaping.
  • The compiler interprets the content between the opening and closing triple quotes as the string’s value.

9.1.2.1 Formatting: Essential vs Incidental Whitespace

  • Essential whitespace: spaces and newlines that are part of the intended string content.
  • Incidental whitespace: indentation in your source code that you don’t conceptually consider part of the text.
String text = """
        Line 1
        Line 2
        Line 3
        """;

Important

  • Leftmost character (baseline): the position of the first non-space character across all lines (or the closing """) defines the indentation baseline. Spaces to the left of this baseline are considered incidental and are removed.
  • The line immediately following the opening """ is not included in the output if it’s empty (typical formatting).
  • The newline before the closing """ is included in the content.
    In the example above, the resulting string ends with a newline after "Line 3": there are 4 lines in total.

Output with line numbers (showing the trailing blank line):

1: Line 1
2: Line 2
3: Line 3
4:

To suppress the trailing newline:

  • Use a line-continuation backslash at the end of the last content line.
  • Put the ending triple quotes on the same line as the last content.
String textNoTrail_1 = """
        Line 1
        Line 2
        Line 3\
        """;

// OR

String textNoTrail_2 = """
        Line 1
        Line 2
        Line 3""";

9.1.2.2 Line Count, Blank Lines, and Line Breaks

  • Every visible line break inside the block becomes \n.
  • Blank lines inside the block are preserved.
String textNoTrail_0 = """
        Line 1  
        Line 2 \n
        Line 3 

        Line 4 
        """;

Output:

1: Line 1
2: Line 2
3:
4: Line 3
5:
6: Line 4
7:

9.1.2.3 Text Blocks & Escape Characters

Escape sequences still work inside text blocks when needed (for example, for backslashes or explicit control characters).

String json = """
    {
      "name": "Alice",
      "path": "C:\\\\Users\\\\Alice"
    }\
    """;

You can also format a text block using placeholders and formatted():

String card = """
    Name: %s
    Age:  %d
    """.formatted("Alice", 30);

9.1.2.4 Common Errors (with fixes)

// ❌ Mismatched delimiters / missing closing triple quote
String bad = """
  Hello
World";      // ERROR — not a closing text block

// ✅ Fix
String ok = """
  Hello
  World
  """;
// ❌ Text blocks require a line break after the opening """
String invalid = """Hello""";  // ERROR

// ✅ Fix
String valid = """
    Hello
    """;
// ❌ Unescaped trailing backslash at end of a line inside the block
String wrong = """
    C:\Users\Alex\     // ERROR — backslash escapes the newline
    Documents
    """;

// ✅ Fix: escape backslashes, or avoid backslash at end of line
String correct = """
    C:\\Users\\Alex\\
    Documents\
    """;

9.2 Core String Methods

9.2.1 String Indexing

Strings in Java use zero-based indexing, meaning:

  • The first character is at index 0
  • The last character is at index length() - 1
  • Accessing any index outside this range causes a StringIndexOutOfBoundsException

  • Example:

String s = "Java";
// Indexes:  0    1    2    3
// Chars:    J    a    v    a

char c = s.charAt(2); // 'v'

9.2.2 length() Method

length() returns the number of characters in the string.

String s = "hello";
System.out.println(s.length());  // 5

The last valid index is always length() - 1.

9.2.3 Boundary Rules: Start Index vs End Index

Many String methods use two indices:

  • Start index — inclusive
  • End index — exclusive

In other words, substring(start, end) includes characters from index start up to, but not including, index end.

  • Start index must be >= 0 and <= length() - 1
  • End index may be equal to length() (the “virtual” position after the last character).
  • End index must not exceed length().
  • Start index must never be greater than end index.

  • Example:

String s = "abcdef";
s.substring(1, 4); // "bcd" (indexes 1,2,3)

This rule applies to most substring-based methods.

9.2.4 Methods Using Only Start Index (Inclusive)

Method Description Parameters Index Rule Example
substring(int start) Returns substring from start to end start start inclusive "abcdef".substring(2) → "cdef"
indexOf(String) First occurrence "Java".indexOf("a") → 1
indexOf(String, start) Start searching at index start start inclusive "banana".indexOf("a", 2) → 3
lastIndexOf(String) Last occurrence "banana".lastIndexOf("a") → 5
lastIndexOf(String, fromIndex) Search backward from index fromIndex fromIndex inclusive "banana".lastIndexOf("a", 3) → 3

9.2.5 Methods with Start Inclusive / End Exclusive

These methods follow the same slicing behavior: start included, end excluded.

Method Description Signature Example
substring(start, end) Extracts part of string (int start, int end) "abcdef".substring(1,4) → "bcd"
regionMatches Compares substring regions (toffset, other, ooffset, len) "Hello".regionMatches(1, "ell", 0, 3) → true
getBytes(int srcBegin, int srcEnd, byte[] dst, int dstBegin) Copies chars to byte array start inclusive, end exclusive Copies chars in [srcBegin, srcEnd)
copyValueOf(char[] data, int offset, int count) Creates a new string offset inclusive; offset+count exclusive Same rule as substring

9.2.6 Methods That Operate on Entire String

Method Description Example
toUpperCase() Uppercase version "java".toUpperCase() → "JAVA"
toLowerCase() Lowercase version "JAVA".toLowerCase() → "java"
trim() Removes leading/trailing whitespace " hi ".trim() → "hi"
strip() Unicode-aware trimming " hi\u2003".strip() → "hi"
stripLeading() Removes leading whitespace " hi".stripLeading() → "hi"
stripTrailing() Removes trailing whitespace "hi ".stripTrailing() → "hi"
isBlank() True if empty or whitespace only " ".isBlank() → true
isEmpty() True if length == 0 "".isEmpty() → true

9.2.7 Character Access

Method Description Example
charAt(int index) Returns char at index "Java".charAt(2) → 'v'
codePointAt(int index) Returns Unicode code point Useful for emojis or characters beyond BMP

9.2.8 Searching

Method Description Example
contains(CharSequence) Substring test "hello".contains("ell") → true
startsWith(String) Prefix "abcdef".startsWith("abc") → true
startsWith(String, offset) Prefix at index "abc".startsWith("b", 1) → true
endsWith(String) Suffix "abcdef".endsWith("def") → true

9.2.9 Replacement Methods

Method Description Example
replace(char old, char new) Replace characters "banana".replace('a','o') → "bonono"
replace(CharSequence old, CharSequence new) Replace substrings "ababa".replace("aba","X") → "Xba"
replaceAll(String regex, String replacement) Regex replace all "a1a2".replaceAll("\d","") → "aa"
replaceFirst(String regex, String replacement) First regex match only "a1a2".replaceFirst("\d","") → "aa2"

9.2.10 Splitting and Joining

Method Description Example
split(String regex) Split by regex "a,b,c".split(",") → ["a","b","c"]
split(String regex, int limit) Split with limit limit < 0 keeps all trailing empty strings

9.2.11 Methods Returning Arrays

Method Description Example
toCharArray() Returns char[] "abc".toCharArray()
getBytes() Returns byte[] using platform/default encoding "á".getBytes()

9.2.12 Indentation

Method Description Example
indent(int numSpaces) Adds (positive) or removes (negative) spaces from the beginning of each line; also adds a line break at the end if not already present str.indent(-20)
stripIndent() Removes all incidental leading whitespace from each line; does not add a final line break str.stripIndent()
  • Example:
var txtBlock = """

                    a
                      b
                     c""";

var conc = " a\n" + " b\n" + " c";

System.out.println("length: " + txtBlock.length());
System.out.println(txtBlock);
System.out.println("");
String stripped1 = txtBlock.stripIndent();
System.out.println(stripped1);
System.out.println("length: " + stripped1.length());

System.out.println("*********************");

System.out.println("length: " + conc.length());
System.out.println(conc);
System.out.println("");
String stripped2 = conc.stripIndent();
System.out.println(stripped2);
System.out.println("length: " + stripped2.length());

Output:

length: 9

a
  b
 c


a
  b
 c
length: 9
*********************
length: 8
 a
 b
 c

a
b
c
length: 5

9.2.13 Additional Examples

  • Example 1 — Extract [start, end)
String s = "012345";
System.out.println(s.substring(2, 5));
// includes 2,3,4 → prints "234"
  • Example 2 — Searching from a start index
String s = "hellohello";
int idx = s.indexOf("lo", 5); // search begins at index 5
  • Example 3 — Common pitfalls
String s = "abcd";
System.out.println(s.substring(1,1)); // "" empty string
System.out.println(s.substring(3, 2)); // ❌ Exception: start index (3) > end index (2)

System.out.println("abcd".substring(2, 4)); // "cd" — includes indexes 2 and 3; 4 is excluded but legal here

System.out.println("abcd".substring(2, 5)); // ❌ StringIndexOutOfBoundsException (end index 5 is invalid)