Course outline

Java / Basic / Lesson 5

Arrays, strings, and text boundaries

Work with sequences while distinguishing fixed-size arrays, immutable strings, reference identity, content equality, and Unicode units.

About 5 min readContent reviewed
On this page

Lesson goals

  • Traverse arrays without invalid indices.
  • Compare text contents and construct strings efficiently.
  • Choose appropriate text-length and parsing rules.

Know what an array owns

An array has a fixed length selected at construction and indexed positions from zero through length minus one. An int array contains primitive values; a String array contains references that may be null. Creating an array does not create every referenced object. Distinguish the array's existence, its length, and the validity of each element before using it.

Assigning an array variable to another variable shares the same array reference. Arrays.copyOf creates a new array, but copying a reference array is shallow: the referenced mutable elements remain shared. Use an enhanced for loop when only values are needed and an indexed loop when positions matter. Neither traversal removes the need to define behavior for empty input.

Observe independent storage after copying

The example copies three primitive elements, changes the copy, and sums the original. The original remains 2, 4, 6, so its total is 12 and the first copied element is 99. This proves the arrays have different element storage, not a universal deep-copy guarantee for every kind of object graph.

A sum accumulator should use a type wide enough for the accepted domain. If the program accepts millions of arbitrary int values, an int sum may overflow even though every individual element is legal. Null input, empty input, and oversized input need explicit contracts. Performance claims about copying should consider data size and mutation requirements rather than avoiding copies reflexively.

java Copying a primitive array
public class Main {

 public static void main(String[] args) throws Exception {
int[] original={2,4,6};
int[] copy=java.util.Arrays.copyOf(original,original.length);
copy[0]=99;
int total=0;
for (int value:original) { total+=value; }
System.out.println(total);
System.out.println(copy[0]);
 }
}
Expected output
12
99

Changing copy[0] does not modify original[0]. The enhanced loop visits each original value once.

Compare contents rather than references

String is immutable: methods that appear to modify it return another string. == compares reference identity, while equals compares string contents. Literal interning can make identity comparisons appear to work in a small demonstration and then fail for input read at runtime. The example deliberately creates a distinct String object so this distinction cannot be hidden by a shared literal reference.

Use an explicit null policy: Objects.equals(a,b) compares nullable references safely, while a.equals(b) requires a non-null receiver. Case-insensitive comparison and locale-aware ordering are separate requirements; neither should be guessed from a user's display name. When matching protocol tokens, document the normalization and locale rule rather than changing human text indiscriminately.

java Reference identity and text equality
public class Main {

 public static void main(String[] args) throws Exception {
String first="java";
String second=new String("java");
System.out.println(first==second);
System.out.println(first.equals(second));
 }
}
Expected output
false
true

new constructs a distinct object. Its content still equals the literal, so the two comparisons answer different questions.

Choose the correct unit for text operations

String.length counts UTF-16 code units. A supplementary character such as an emoji can occupy two positions, so charAt does not necessarily return one full Unicode code point. codePointCount and codePoints support code-point reasoning, while user-perceived grapheme clusters can require still another layer. An input limit of โ€œten charactersโ€ is incomplete until the product defines its unit.

Substring uses a beginning index inclusive and an end index exclusive. Check 0 <= start <= end <= length; an end equal to length is valid. Splitting at an arbitrary char index can cut a surrogate pair. For external bytes, decode with an explicit charset such as UTF-8 and validate malformed-input behavior instead of relying on the machine's default encoding.

Separate text construction from interpretation

For repeated construction in a loop, StringBuilder can collect pieces without repeatedly expressing whole-string replacement. Its mutability also means it should not be shared unsafely across threads. Prefer String.join for a simple delimiter operation when it communicates intent clearly. Choose readability first, then measure significant workloads before claiming one syntax is faster.

Parsing is a boundary operation with a format and a range. Integer.parseInt rejects malformed or out-of-range numeric text; it does not validate a business rule such as positive stock. Decide whether whitespace is accepted before parsing and preserve the original input only in appropriately restricted diagnostics. Do not catch every parsing problem and silently substitute zero, because that turns invalid data into a plausible result.

Common errors and fixes

ArrayIndexOutOfBoundsException

Why it happens
An index lies outside the array's half-open range.
How to fix it
Validate the index and use < length in traversal.
Prevent it next time
Test empty and last-element access.

Equal strings compare false with ==

Why it happens
Reference identity was used for content equality.
How to fix it
Use equals or Objects.equals according to null policy.
Prevent it next time
Test strings built independently from input.

NumberFormatException

Why it happens
Input is malformed or outside the parser's numeric range.
How to fix it
Reject or report invalid text at the input boundary.
Prevent it next time
Test whitespace, signs, overflow, and domain limits.

Check your understanding

1. Two variables refer to the same int array. One changes element zero. What does the other see?

Show worked solution

The changed element, because both variables refer to one mutable array. A primitive-array copy would have separate element storage; a shallow reference-array copy would still share its referenced objects.

2. Why can length() be larger than codePointCount for a string?

Show worked solution

Supplementary code points use surrogate pairs and therefore two UTF-16 units. length counts units, while codePointCount counts code points. Neither always equals the number of visible grapheme clusters, so choose the measurement required by the product.

Key takeaways

  • Arrays have fixed length and zero-based half-open indexing.
  • String identity, content, and Unicode units differ.
  • Parsing and business validation are separate steps.

Official references