OSJava.005: Java Strings — Literals, Immutability, equals(), length(), and substring()

Adult South Asian Java developer reviewing Java String source code and comparison results on a workstation

Java strings represent sequences of text as objects, not primitive variables. Whether a program reads a device identifier, checks an account name, parses logs, or formats a message, the java.lang.String class supplies tools for manipulating that text. In OSJava.005 you will build practical string values, distinguish object identity from text equality, and run one verified example using string methods.

This lesson follows OSJava.004: Java Control Flow and builds on OSJava.003: Expressions, Statements, and Blocks, which introduced executable expressions, and OSJava.002: Primitive Types and Variables, which distinguished primitive values from variable declarations. Revisit OSJava.001: The JDK, Bytecode, and JVM if you need a refresher on compiling a Java class.

Learning objectives

  • Create Java strings from literals and understand why they are reference types.
  • Distinguish equals(), equalsIgnoreCase(), and ==.
  • Read text with length(), charAt(), indexOf(), and substring().
  • Explain String immutability and why methods return new text values.
  • Recognize UTF-16 code-unit length versus Unicode code-point count.
  • Compile, run, and extend a Java string-handling diagnostic lab.

1. String objects and literals

A String is a class in java.lang, so Java programs use it without an explicit import. A text literal is enclosed in double quotation marks: "ASIC-S21". Single quotation marks denote a single char such as 'A', which is not the same type. A variable declared String model stores a reference to a string object; it is not an array of mutable characters. The official Dev.java Strings lesson explains that Java treats literals as string objects and their values are immutable.

String model = "ASIC-S21"; String note = "Status: " + model; char first = model.charAt(0); System.out.println(note); // Status: ASIC-S21 System.out.println(first); // A

Concatenation with + builds a resulting string. This is useful for compact human-readable diagnostics, but do not build complex SQL statements with concatenated untrusted input. Java’s String and JavaScript’s string primitive share many text operations yet differ in type rules; compare OSJavaScript.002: Values and Primitive Types when moving between languages.

2. Reading strings with methods

The length() method reports how many UTF-16 code units a string contains. charAt(0) returns the first UTF-16 code unit, because indexing begins at zero. indexOf("S21") finds the starting index of that text or returns -1 if absent. substring(begin, end) returns the region starting at begin and stopping before end; the end index is exclusive. Out-of-range positions throw an exception rather than returning a blank character.

String model = "ASIC-S21"; System.out.println(model.length()); // 8 System.out.println(model.charAt(0)); // A System.out.println(model.indexOf("S21")); // 5 System.out.println(model.substring(0, 4)); // ASIC System.out.println(model.contains("S21")); // true

For real-world input, test ranges and blank strings before indexing. The Java String API documentation defines the exact method contracts. Counting human-visible symbols is a separate problem: some Unicode code points use two UTF-16 code units, and combinations of code points can display as one grapheme.

Bro Code demonstrates useful Java String methods, including length, character lookup, case conversion, trimming, and replacement.

3. String content versus reference identity

Use equals() for content equality. By contrast, == tests whether two reference variables identify the same object, not whether the text matches. Some literals are interned, which can make a mistaken == comparison appear to work in a small demonstration. The correct choice for ordinary text comparison is equals(); choose equalsIgnoreCase() only when a case-insensitive comparison is actually required.

String a = "ready"; String b = new String("ready"); System.out.println(a.equals(b)); // true System.out.println(a == b); // false String nullable = null; System.out.println("ready".equals(nullable)); // false

Calling nullable.equals("ready") when nullable is null throws a NullPointerException. A constant on the left of equals() avoids that particular failure. When comparing labels that may differ by language or locale, do not assume that ignoring case implements every human-language equivalence. The boolean conditions used in OSGo.004: Control Flow are conceptually similar, but Java reference comparison has its own rules.

Coding with John explains the difference between Java reference identity with == and actual String content equality with equals().

4. Immutability, cleanup, and replacement

Once a Java String object is created, its text cannot be changed in place. A method such as replace(), toUpperCase(), or strip() returns a string result; assign that result if the cleaned version is needed later. The original object remains unchanged. strip() is available in Java 11 and newer; trim() predates it and uses a narrower whitespace definition. For repeated incremental editing, the mutable StringBuilder class is frequently more appropriate than repeatedly concatenating inside a large loop.

String raw = " ASIC-S21 "; String clean = raw.strip(); String revised = clean.replace("S21", "S19"); System.out.println(raw); // still contains spaces System.out.println(clean); // ASIC-S21 System.out.println(revised); // ASIC-S19

For multiline text, modern Java offers text blocks with triple double quotes on Java 15 and newer. They reduce the escape sequences required for embedded HTML, configuration, and other formatted data; see Oracle’s text-block programming guide. The lesson on HTML document structure offers an example of the sort of text developers may need to embed without losing its formatting.

Bro Code offers a second practical demonstration of String methods, including comparisons, cleanup, searches, and immutable replacement results.

5. Complete Java lab: normalize a miner identifier

Create a file named StringLab.java and enter the complete program below. It begins with a padded equipment identifier, removes surrounding whitespace, compares equivalent text, extracts a model prefix, and demonstrates why replacing part of a string does not modify the original. The final two lines contrast Java’s UTF-16 code-unit count with a Unicode code-point count.

public class StringLab { public static void main(String[] args) { String device = " ASIC-S21 "; String clean = device.strip(); String target = new String("ASIC-S21"); System.out.println("clean: " + clean); System.out.println("same text: " + clean.equals(target)); System.out.println("same object: " + (clean == target)); System.out.println("prefix: " + clean.substring(0, 4)); System.out.println("length: " + clean.length()); System.out.println("first letter: " + clean.charAt(0)); System.out.println("changed copy: " + clean.replace("S21", "S19")); System.out.println("original: " + clean); String symbol = "🔧"; System.out.println("UTF-16 units: " + symbol.length()); System.out.println("code points: " + symbol.codePointCount(0, symbol.length())); } }

Compile and execute on Java 11 or newer with javac StringLab.java followed by java StringLab. This exact example was compiled and executed using OpenJDK 21.0.12; the console output was:

clean: ASIC-S21 same text: true same object: false prefix: ASIC length: 8 first letter: A changed copy: ASIC-S19 original: ASIC-S21 UTF-16 units: 2 code points: 1

The first comparison is true because the normalized label and target have the same text. The identity comparison is false because the target was explicitly constructed as a different object. The substring ends before index 4, and the wrench symbol occupies two UTF-16 code units while representing one code point. Neither count necessarily measures user-perceived grapheme clusters in arbitrary Unicode text.

6. Common mistakes

  • Using == to compare text values instead of equals().
  • Using charAt(length()) even though the last valid index is length() - 1.
  • Expecting replace() or strip() to mutate an existing String object.
  • Confusing length() with a count of displayed symbols or all Unicode graphemes.
  • Ignoring null input before calling instance methods.
  • Treating a missing indexOf() result, -1, as a valid substring starting index.

Mini lab and exercises

  1. Change the identifier to " ASIC-S19 " and predict all eight ordinary string-processing output lines before compiling.
  2. Add a startsWith("ASIC") test after normalization and print its boolean result.
  3. Create a label "s21" and compare it with "S21" using both equals() and equalsIgnoreCase().
  4. Use indexOf('-') and substring() to extract the model name after the hyphen.
  5. Explain in one sentence why calling clean.replace("S21","S19") without saving the return value leaves clean unchanged.

Knowledge check and answers

  1. Is Java String a primitive type?
  2. What does "abc".substring(1, 3) return?
  3. What is the difference between equals() and == for strings?
  4. What index indicates indexOf() did not find a match?
  5. Why can length() report two for one emoji?
  6. Does assigning text = text.strip() mutate the original string object?

Answers: (1) No, it is an object/reference type. (2) "bc". (3) Content equality versus reference identity. (4) -1. (5) Java uses UTF-16 code units; supplementary code points occupy a surrogate pair. (6) No; the variable points to the method’s returned value, while the original object’s characters remain immutable.

Sources and next lesson

Primary technical references: Dev.java — Strings; Oracle’s String API; and Oracle’s text-block guide. OSJava.006 can introduce array creation and indexing; the full Open CERT subject rotation advances next to JavaScript.

Editor’s Note: We volunteer daily to ensure the credibility of the information on this platform is Verifiably True. If you would like to support our work and help further secure the integrity of our research initiatives, please scan the QR code below to donate 5,000 sats.

BitcoinVersus.Tech original Bitcoin donation QR for 5000 satoshis

For mobile scanning, open the lesson on a larger screen and scan the QR code with a compatible Bitcoin wallet. Verify the destination address before sending: 3C9o19EH5HSiwEPyCTmEKzxhNCbo2X6TTb.

BitcoinVersus.tech is not a financial advisor. This media platform reports on financial subjects purely for informational purposes.

Leave a Reply