Java Strings
Treat text as data with meaning. Learn to compare, search, and transform it deliberately while keeping original values, valid indexes, and missing information in view.
Before you start: complete Java Operators and Booleans. Every example is a complete Main.java program in the existing Java 21 runner. Predict the output before running, then change one value. The Unicode section is optional on your first pass.
What you will be able to do
- Read String method calls and use their returned values.
- Explain immutability without confusing it with final variables.
- Compare text contents rather than reference identity.
- Search text and extract a range using valid indexes.
- Apply deliberate whitespace and case rules while preserving original text.
- Handle null, empty, blank, and Unicode text as distinct cases.
A String is text with operations you can call
A String represents text, such as a learner's name, a course label, or an identifier containing leading zeroes. It is a reference type, not a primitive. Create ordinary text with double quotes. A single-quoted 'J' is a char, while the double-quoted "J" is a String, even though both can print the same visible letter.
A method call asks an object to perform a defined operation. In course.length(), course is the reference before the dot, length is the method name, and the empty parentheses mean no arguments are supplied. The returned int can be printed, stored, or used in another expression. charAt(0) takes an index argument and returns the char at that UTF-16 position.
For the simple text Java, indexes start at 0 and finish at 3. length() returns 4, not the last index. The last valid index is length() - 1 only when the String is nonempty. Read the labels in the example and predict each result before running it. The later Unicode section explains why a code unit is not always a complete visible character.
Main.java · Read text and an individual code unit
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Hello, Mina!
Course length: 4
First code unit: J
Last code unit: a
String transformations return results; they do not edit the old text
String objects are immutable: their contents cannot be changed after creation. Calling strip, replace, or a case-conversion method does not edit the original text. Instead, the call returns a String result. If you ignore that result, your variable continues to refer to its previous value.
The first strip call below is intentionally ignored. The bracketed output still contains the outside spaces. The next call saves its result in cleaned, which contains Mina without those spaces. original still refers to the unmodified text. A method may return the same String when no change is needed, so do not assume that every transformation necessarily allocates a distinct object.
Immutability and final describe different things. A non-final String variable can be reassigned to a different String, as cleaned is at the end. A final binding prevents reassignment of that variable; String's own design prevents editing the object's contents. Keep your original and cleaned values separately when a workflow needs both for review or display.
Main.java · Transform a value without changing the original
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
After ignored result: [ Mina ]
Saved result: [Mina]
Original still: [ Mina ]
Reassigned cleaned: [Mina / Java]
Test a different name
Replace Mina with Sami while leaving the outside spaces. The saved result becomes Sami, but the two original-value lines still include those spaces. Explain why calling strip alone did not update the original variable.
Use equals for text content, not ==
The expression first == second compares reference identity: do both references identify the same object? first.equals(second) asks whether the String contents match. The example deliberately uses new String twice to create separate objects containing the same text. This is a teaching demonstration, not a recommendation to wrap every literal in a constructor.
Ordinary String literals can share objects, which can make == appear to work in small tests. That does not make it a content-comparison strategy. equals is case-sensitive. equalsIgnoreCase can answer a deliberately case-insensitive comparison, but does not remove spaces, normalize every Unicode representation, or implement a locale-sensitive human-language ordering.
Choose the comparison rule before changing the input. A course key might intentionally accept JAVA and java as equivalent. A person's display name should not be rewritten merely to make a comparison convenient. A known non-null literal receiver, such as "Java".equals(candidate), returns false for a null candidate; calling candidate.equals(...) still fails if candidate is null.
Main.java · Compare contents, case, and references deliberately
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Same object: false
Same contents: true
Exact lowercase match: false
Ignoring case: true
Search results tell you whether text exists and where it begins
contains, startsWith, and endsWith return boolean answers. indexOf returns an int position for the first match, or -1 when no match exists. These common searches are case-sensitive. The code JAVA-204 therefore starts with JAVA but does not contain lowercase java.
The hyphen is at index 4: the four letters occupy indexes 0 through 3. A missing slash returns -1, which is not a valid extraction index. Before using a search result in charAt or substring, establish that the match exists and that any needed content after it is present. Do not assume every imported code contains the expected separator.
Search does not automatically validate a full format. startsWith("JAVA") also matches JAVASCRIPT, and contains only checks for a matching sequence somewhere. Decide whether you need an exact value, a prefix, or a complete structured format. In this lesson, the example is a fixed code, not a general parser for arbitrary course identifiers.
Main.java · Find exact text without extracting it
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Starts with JAVA: true
Ends with 204: true
Contains lowercase java: false
Hyphen index: 4
Missing slash index: -1
Extract a range: the beginning is included and the end is excluded
substring(begin, end) includes the begin position and stops before end. For JAVA-204, substring(0, 4) extracts the four letters without the hyphen. substring(5) starts at index 5 and continues to the end, producing the text 204. It remains a String, not an integer parsed from those digits.
The valid two-index rule is 0 <= begin <= end <= length. An empty range such as substring(4, 4) is allowed and returns an empty String. The end index can equal length because it is excluded. charAt is different: charAt(length) is outside the String, because it asks for a code unit at a position that does not exist.
A negative begin, an end beyond length, or begin greater than end causes an index exception. Our fixed positions are justified by this known example only. When content can vary, check its structure before extracting. Also remember that these indexes are UTF-16 positions: cutting arbitrary user text at a chosen code-unit index can split a surrogate pair or a visible combined character.
Main.java · Include the start, exclude the end
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Topic: JAVA
Number text: 204
Empty range: []
Complete range: JAVA-204
Whitespace and case conversion are policies, not automatic improvements
strip removes leading and trailing whitespace according to Java's Character.isWhitespace definition. It leaves interior spaces alone, so Mina Ben Ali keeps the spaces inside the name. trim uses the older boundary rule for code units up to U+0020. Neither operation means remove every possible invisible separator; for example, a nonbreaking space is not stripped by strip.
For a deliberately case-insensitive machine key, toLowerCase(Locale.ROOT) gives a locale-independent choice instead of silently using the computer's default locale. The fully qualified java.util.Locale.ROOT spelling lets the example run without adding an import. For human-language display text, case and locale rules require their own design rather than blindly applying this key transformation.
The chain rawTopic.strip().toLowerCase(...) first produces a boundary-cleaned String, then calls the case method on that result. Split a chain into named steps if that is easier to read or debug. These transformations do not validate a username, establish uniqueness, sanitize HTML, or make a value safe for SQL. Text cleanup is only the specific policy you actually implemented.
Main.java · Keep display names separate from machine keys
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Display name: [Mina Ben Ali]
Topic key: java
Original topic: [ JAVA ]
replace uses literal text; it is not a general rewriting rule
replace with String arguments replaces occurrences of the literal target sequence. In the draft below, both occurrences of Java become SQL. The original draft stays unchanged because String is immutable. When the target is a dot, that dot means a literal period, as the filename example makes visible.
Do not confuse replace with replaceAll, whose first argument is a regular expression. A dot has special meaning in a regular expression, so switching methods can radically change what matches. Regular expressions have their own lesson later; here we use literal replacement because it states the small editing task directly.
A replacement is also case-sensitive and does not understand sentence meaning. Replacing Java in JavaScript would affect that longer word too. If you need a whole-word or structured edit, define that rule first. Do not apply broad replacements to personal names, passwords, or user content simply because the resulting text looks cleaner in one example.
Main.java · Replace a literal piece of text
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Updated: SQL / SQL practice
Original: Java / Java practice
Literal dots replaced: lesson-v1-txt
Distinguish null, empty, and blank before calling methods
null means no String object is referenced. The empty String "" is an actual String with zero code units. A String containing three spaces has length three, so it is not empty, but isBlank returns true. isBlank also returns true for the empty String, using Java's whitespace definition for nonempty values.
All these instance methods need a non-null receiver. In missing == null || missing.isBlank(), the left test succeeds for null and short-circuits the method call, using the OR guard from the previous lesson. Reversing the order would attempt the method first and fail. Decide whether your application treats missing and blank as equivalent; do not silently erase the distinction when it matters.
Printing a missing reference as part of text can display the word null, but that display is not an empty value and not a useful missing-data policy by itself. A null-safe comparison such as "Java".equals(missing) is safe because the receiver is the literal, not the missing reference. Later lessons will use conditions to choose what to show or reject for each case.
Main.java · Missing, empty, and blank are different
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Missing or blank: true
Empty is empty: true
Blank is empty: false
Blank is blank: true
Literal equals missing: false
Check the empty and blank cases
The empty String is both empty and blank. Three spaces are blank but not empty. A null reference is neither a String containing spaces nor an empty String; calling isBlank on it without the guard fails.
Optional: length counts code units, not everything a reader calls a character
String uses UTF-16 indexing. A rocket emoji needs two code units, so length returns 2 even though codePointCount reports one code point. The example writes Unicode escapes so the representation is visible in the editor. You do not need to memorize the escape values to understand the counting difference.
Code points are not the end of the story either. The second example combines e with a combining acute accent. It has two code points, which are often displayed together as one accented letter. User-perceived character boundaries can therefore differ from both code-unit boundaries and code-point counts.
For these ASCII course-code examples, simple indexing is adequate. For real names, arbitrary snippets, or display limits, do not claim that substring(0, n) always preserves n complete visible characters. Choose text-processing rules appropriate to the application and its Unicode data. Also, equal-looking text can have different underlying sequences; equals does not automatically normalize them.
Main.java · Text length depends on what you are counting
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Rocket UTF-16 units: 2
Rocket code points: 1
Combining text UTF-16 units: 2
Combining text code points: 2
Repair ignored cleanup and reference comparison
The intended output is Name: Mina and Same text: true. The starter ignores a cleanup result and compares references instead of contents. Repair both problems without changing the original text or replacing the comparison with a hard-coded boolean.
Main.java · Repair the learner name
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Reveal the explained repair
Save strip's returned value and use that cleaned value in the output and comparison. Compare its contents with equals, not reference identity with ==. Merely changing == to equals still fails while the spaces remain; merely saving the stripped value still leaves identity comparison unreliable. rawName remains available with its original spaces.
Main.java · Repaired learner name
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Name: Mina
Same text: true
Independent lab: a learner-card preview
Create a local learner-card preview from fixed, non-null example values. Preserve a person's display-name casing, create a deliberately lowercase topic key, and show a revised note. This is text transformation practice, not an account-creation or data-validation system.
- Start with rawName containing two spaces, Mina, then two spaces; rawTopic containing two spaces, JAVA, then two spaces; and rawNote containing two spaces, Ready for Java, then two spaces.
- Save displayName as rawName.strip(), preserving the original rawName and the casing inside the name.
- Save topicKey by stripping rawTopic and lowercasing with java.util.Locale.ROOT.
- Build label from displayName, the separator space/slash/space, and topicKey. Compute nameUsable with !displayName.isBlank() and javaTopic with a content comparison to java.
- Save note as stripped rawNote with the literal Java replaced by practice. Print the seven labelled lines shown in the output contract.
- Do not hard-code transformed results. Test different casing, a blank name, and a different topic using the checklist.
Compare your result with this output contract, including the original-name spaces:
Name: Mina
Topic key: java
Label: Mina / java
Name usable: true
Java topic: true
Note: Ready for practice
Original name: [ Mina ]
Main.java · Build your learner card
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Show hints without revealing the solution
Use separate variables for raw and transformed values. Only the topic key needs lowercasing. Use !isBlank for the chosen name check and a known non-null literal for the java content comparison. The note uses literal replace, not a regular expression.
Reveal the explained lab solution
Main.java · Learner-card solution
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
The display name loses only boundary whitespace, so Mina remains in its original case. The topic key uses an explicit locale-independent case policy. equals compares the key's content. The note replacement changes a saved result, not rawNote. The nameUsable boolean only checks the chosen blank rule; it does not validate a person's name, and it does not stop this preview from printing a blank name.
Test changes and boundaries
Reset between experiments, and predict which output lines should remain unchanged.
- Use rawName with Sami and the same outside spaces: the display name, label, and original-name line should change; the topic checks should not.
- Use rawTopic containing mixed-case JaVa with outside spaces: the key should remain java and javaTopic should remain true.
- Use rawTopic containing SQL: the key should be sql and javaTopic false. The note still follows its own independent replacement rule.
- Use rawName containing only spaces: displayName becomes empty and nameUsable false. This preview reports that result; it does not reject or save anything.
- Use lowercase java in rawNote: literal replacement of Java should leave that lowercase word unchanged. Explain the case-sensitive policy before deciding whether to change it.
Common mistakes and how to diagnose them
Separate an ignored method result, an incorrect comparison, an invalid index, and a missing reference. Each has a different cause; random extra stripping or lowercasing will not solve them all.
The text did not change
Check whether you saved the returned String. Ignoring strip, replace, or case conversion leaves your variable pointing to its previous value. Also check that your search or replacement target matches the input's case.
Text equality passes one test and fails another
Look for == on String references. Shared literal objects can hide identity-comparison mistakes. Use equals for contents, decide your case rule, and account for null receivers deliberately.
StringIndexOutOfBoundsException or another index exception
Check the actual length, zero-based indexing, and the exclusive substring end. A missing indexOf result of -1 is not an extraction position. Empty text has no first or last charAt position.
NullPointerException
An instance method was called through a null reference. Guard before the call or use a known non-null receiver when the comparison policy permits it. Do not confuse null with an empty String.
Cleanup changes a name or key unexpectedly
Check which text policy you intended. Boundary stripping, interior-space editing, case conversion, and Unicode normalization are separate operations. Preserve original text when it is needed, and do not apply a machine-key rule to every display name.
An emoji or accent breaks a character limit
length, charAt, and substring use UTF-16 code-unit positions. A visible symbol may occupy more than one unit or code point. Do not assume that a count of code units is a user-perceived character count.
Frequently asked questions
Can a String variable change if String is immutable?
A non-final variable can be reassigned to a different String. The old object's contents do not change. A final variable cannot be reassigned; immutability is a property of String objects, not a synonym for final.
Should I use trim or strip?
Use the operation matching your whitespace policy. strip uses Character.isWhitespace; trim uses the older boundary rule up to U+0020. Neither is a universal remover of invisible characters. This Java 21 lesson uses strip for its deliberate boundary-cleanup rule.
Does equalsIgnoreCase make two names universally equivalent?
No. It ignores case according to its defined behavior, not every language, spacing, normalization, or identity rule. A person's name and a machine topic key may need very different comparison policies.
Is a String with spaces empty?
No. isEmpty checks zero length. isBlank also accepts empty text and text made entirely of Java-defined whitespace. A null reference supports neither method until an appropriate guard or other absence policy is applied.
Should I use StringBuilder instead of + everywhere?
No. Ordinary small concatenations such as this learner label are clear with +. StringBuilder can be useful for repeated incremental construction, particularly in loops. It is mutable and has different behavior from String; use it when that construction pattern is actually needed.
Preserve meaning while transforming text
String objects do not change in place. Save transformation results, compare contents deliberately, and distinguish code-unit indexes from visible text boundaries. A missing reference, empty text, and blank text are different inputs with different handling requirements.
Before moving on, explain why the lab preserves the raw name but lowercases only the machine topic key. Then explain why substring can use length as an excluded end while charAt cannot use it as a position. Next is Java Math.
Can you explain the text operation?
Answer all six questions and read the reasoning. Results are temporary on this page and do not save course progress.
References and related learning
The learner-card scenario, examples, explanations, and exercises are original SovranCode material. These official references support the language and API rules.
- Java 21 String API: comparison, searching, extraction, and transformation
- Java 21 Character API: isWhitespace
- Java 21 Locale API: ROOT
- Java 21 specification: String literals
Review boolean guards · Review text representations · Java course roadmap.
Last updated: