Java Strings

Su Suriya Ravichandran Updated 14 Nov 2026
6 min read ·Lesson 11 of 133

A String is a sequence of characters. It is the most used class in Java, and it has special language support: literals in double quotes, + for concatenation, and automatic conversion of other values when they are joined to text. This lesson covers how strings work; the Java Strings section later goes deeper into each operation.

Creating Strings

String greeting = "Hello";              // string literal
String empty = "";                      // empty string, length 0
String copy = new String("Hello");      // explicit object creation (rarely needed)
String fromChars = new String(new char[]{'J', 'a', 'v', 'a'});  // "Java"
String fromNumber = String.valueOf(42); // "42"

The literal form is the normal way. new String("Hello") creates a second object with the same content and has almost no legitimate use; it exists for historical reasons.

Strings Are Objects

String is a class in java.lang, not a primitive. A String variable holds a reference, can be null, and has methods.

String name = "Ada Lovelace";
System.out.println(name.length());        // 12
System.out.println(name.toUpperCase());   // ADA LOVELACE
System.out.println(name.charAt(0));       // A
System.out.println(name.indexOf("Love")); // 4

null and "" are different. "" is a real String object with zero characters; calling "".length() returns 0. null is the absence of any object; calling null.length() throws NullPointerException.

Immutability

Once a String is created, its characters can never change. Every method that appears to modify a string returns a new string.

String s = "java";
s.toUpperCase();
System.out.println(s);        // java: the original is unchanged

s = s.toUpperCase();
System.out.println(s);        // JAVA: s now refers to a new object

The first call creates "JAVA" and immediately discards it because nothing stores the result. Forgetting to reassign is a frequent early mistake with trim(), replace(), and toUpperCase().

Why strings are immutable

  • Safety when sharing. A string passed to a method cannot be altered by that method, so callers never need defensive copies. File paths, URLs, and database credentials passed around a program stay exactly as they were.
  • Thread safety. Immutable objects can be shared across threads without synchronization.
  • Hash caching. A string's hash code never changes, so it is computed once and cached. This makes String an efficient key in HashMap and HashSet.
  • The string pool. Identical literals can safely share one object, described next.

The String Pool

The JVM keeps a pool of string literals. When the same literal appears more than once, every occurrence refers to the same pooled object.

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

System.out.println(a == b);       // true: same pooled object
System.out.println(a == c);       // false: c is a separate object
System.out.println(a.equals(c));  // true: same characters

This is why == sometimes appears to work on strings and sometimes does not. It compares object identity, and whether two equal strings are the same object depends on how they were created. Strings built at runtime (from user input, concatenation of variables, file reads) are generally not pooled.

Always compare string content with equals:

if (input.equals("yes")) { ... }
if ("yes".equals(input)) { ... }          // safe even when input is null
if (input.equalsIgnoreCase("YES")) { ... }

Putting the literal first, "yes".equals(input), avoids a NullPointerException when input is null, because the method is called on the literal, which is never null.

Concatenation

+ joins strings and converts non-string operands to text:

String first = "Ada";
String last = "Lovelace";
int born = 1815;

String full = first + " " + last;                 // "Ada Lovelace"
String info = full + " was born in " + born;      // "Ada Lovelace was born in 1815"

concat does the same for two strings but does not accept non-string arguments and throws on null. + is preferred.

Concatenation in loops

Because strings are immutable, += in a loop creates a new string on every iteration and copies all previous characters each time:

String result = "";
for (int i = 0; i < 10_000; i++) {
    result += i + ",";        // 10,000 intermediate strings
}

For repeated appends, use StringBuilder, which is a mutable buffer:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10_000; i++) {
    sb.append(i).append(',');
}
String result = sb.toString();

For joining a collection with a separator, String.join is shorter still:

String csv = String.join(", ", List.of("red", "green", "blue"));  // "red, green, blue"

A single expression with several + operators (a + " " + b + "!") is fine; the compiler optimizes it. The cost appears only when concatenation is repeated across loop iterations.

Indexes and Characters

Characters in a string are numbered from 0. The last index is length() - 1.

 J   a   v   a
 0   1   2   3
String word = "Java";
char first = word.charAt(0);                 // 'J'
char last = word.charAt(word.length() - 1);  // 'a'
word.charAt(4);                              // StringIndexOutOfBoundsException

charAt returns a char, not a String. 'J' and "J" are different types.

Commonly Used Methods

MethodReturnsExampleResult
length()int"hello".length()5
charAt(i)char"hello".charAt(1)'e'
substring(a, b)String"hello".substring(1, 4)"ell"
indexOf(s)int"hello".indexOf("l")2 (−1 if absent)
contains(s)boolean"hello".contains("ell")true
startsWith(s) / endsWith(s)boolean"file.txt".endsWith(".txt")true
toUpperCase() / toLowerCase()String"Hi".toLowerCase()"hi"
trim() / strip()String" hi ".strip()"hi"
replace(a, b)String"a-b-c".replace("-", "/")"a/b/c"
split(regex)String[]"a,b,c".split(",")["a", "b", "c"]
isEmpty()boolean"".isEmpty()true
isBlank()boolean" ".isBlank()true
equals(s)boolean"a".equals("a")true
compareTo(s)int"apple".compareTo("banana")negative
repeat(n)String"ab".repeat(3)"ababab"

substring(a, b) includes index a and excludes index b, so its length is b - a. substring(a) runs to the end.

strip() (Java 11) removes all Unicode whitespace; trim() removes only characters with code ≤ U+0020. For modern code, prefer strip(), isBlank(), stripLeading(), and stripTrailing().

Special Characters

Escape sequences insert characters that cannot be typed directly in a literal:

String quote = "She said \"yes\"";       // She said "yes"
String path = "C:\\temp\\file.txt";      // C:\temp\file.txt
String lines = "first\nsecond";          // two lines
String tabbed = "Name:\tAda";            // tab between

For multi-line text, a text block (Java 15+) avoids most escapes:

String json = """
        {
          "name": "Ada",
          "born": 1815
        }
        """;

Converting To and From Strings

// To String
String a = String.valueOf(3.14);     // "3.14"
String b = Integer.toString(255);    // "255"
String c = "" + true;                // "true" (works, less explicit)

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

// To and from char arrays
char[] chars = "Java".toCharArray();
String back = new String(chars);

parseInt and similar methods throw NumberFormatException for text that is not a valid number, including text with surrounding spaces.

Practical Example: Processing User Input

import java.util.Scanner;

public class EmailCheck {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("Enter email: ");
        String raw = sc.nextLine();

        String email = raw.strip().toLowerCase();

        if (email.isEmpty()) {
            System.out.println("No email entered.");
            return;
        }

        int at = email.indexOf('@');
        if (at <= 0 || at != email.lastIndexOf('@') || at == email.length() - 1) {
            System.out.println("Invalid email: " + raw);
            return;
        }

        String user = email.substring(0, at);
        String domain = email.substring(at + 1);

        System.out.println("User:   " + user);
        System.out.println("Domain: " + domain);
        System.out.println("Gmail?  " + domain.equals("gmail.com"));
    }
}

Sample run:

Enter email:   Ada.L@Gmail.com
User:   ada.l
Domain: gmail.com
Gmail?  true

strip() removes accidental spaces and toLowerCase() normalizes case, both returning new strings that are stored back. indexOf('@') finds the separator; the condition rejects input where @ is missing (-1), first (0), repeated, or last. substring splits the address around the @, and equals compares the domain by content. Every step creates a new string and leaves raw untouched, which is why the error message can still show exactly what the user typed.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about Java Strings and get answers drawn from it.

Signed-in readers only.