Arrays and Strings
Arrays and Strings
Arrays and strings are the two collections you will use in almost every exercise this year. Java handles both quite differently from C, and mostly more safely.
Arrays
An array holds a fixed number of values of one type, stored together and reached by index. Indexing starts at 0, so an array of five elements has valid indices 0 through 4.
Java arrays differ from C arrays in two important ways. They are objects, created with new and reached through a reference. And they know their own length, exposed as the field length.
public class Main {
public static void main(String[] args) {
int[] marks = {78, 65, 92, 41, 88};
int[] scores = new int[5];
scores[0] = 50;
scores[1] = 60;
System.out.println("Length: " + marks.length);
System.out.println("First: " + marks[0]);
System.out.println("Last: " + marks[marks.length - 1]);
System.out.println("Default value in a new int array: " + scores[4]);
int total = 0;
int highest = marks[0];
for (int i = 0; i < marks.length; i++) {
total += marks[i];
if (marks[i] > highest) {
highest = marks[i];
}
}
System.out.println("Total: " + total);
System.out.println("Highest: " + highest);
System.out.printf("Average: %.2f%n", (double) total / marks.length);
String[] subjects = {"Maths", "Physics", "Chemistry"};
for (String s : subjects) {
System.out.println("- " + s);
}
int[][] grid = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
for (int[] row : grid) {
for (int cell : row) {
System.out.print(cell + " ");
}
System.out.println();
}
}
}
Three details from that program.
marks.length is a field, not a method. There are no brackets. This is inconsistent with String.length(), which is a method with brackets, and mixing them up is a compile error you will make more than once.
An array made with new is filled with defaults: 0 for numeric types, false for boolean, null for object types. Unlike a local variable, it is never garbage.
The size is fixed at creation. new int[5] holds five ints forever. You cannot grow it; you would have to create a bigger array and copy across. That limitation is exactly what ArrayList solves.
marks[10] on a five-element array throws ArrayIndexOutOfBoundsException naming the bad index, and the program stops immediately. The same code in C reads whatever memory happens to be there and carries on with a wrong answer. An exception with a line number is a far better outcome than silent corruption, so treat it as the language helping you rather than the language complaining.
ArrayList
ArrayList is a resizable array from java.util. It grows as you add, tracks its own size, and is the right default when you do not know the count in advance.
Because it stores objects rather than primitives, you write ArrayList<Integer> and not ArrayList<int>. Java converts between int and Integer automatically, so in practice you rarely notice.
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<String> subjects = new ArrayList<>();
subjects.add("Maths");
subjects.add("Physics");
subjects.add("Chemistry");
subjects.add("English");
System.out.println("Count: " + subjects.size());
System.out.println("First: " + subjects.get(0));
subjects.remove("English");
subjects.set(1, "Applied Physics");
for (String s : subjects) {
System.out.println("- " + s);
}
System.out.println("Has Maths? " + subjects.contains("Maths"));
System.out.println("Index of Chemistry: " + subjects.indexOf("Chemistry"));
ArrayList<Integer> marks = new ArrayList<>();
marks.add(78);
marks.add(65);
marks.add(92);
int total = 0;
for (int m : marks) {
total += m;
}
System.out.printf("Average: %.2f%n", (double) total / marks.size());
System.out.println("Empty? " + marks.isEmpty());
marks.clear();
System.out.println("After clear: " + marks.size());
}
}
The methods you will use most:
| Method | Meaning |
|---|---|
add(x) |
Append x at the end |
get(i) |
The element at index i |
set(i, x) |
Replace the element at index i |
remove(i) |
Remove by index |
size() |
Number of elements |
contains(x) |
Whether x is present |
isEmpty() |
Whether the list has no elements |
clear() |
Remove everything |
Note the mismatch again: arrays use length, ArrayList uses size(), String uses length(). There is no logic to it; it is history.
One sharp edge: on an ArrayList<Integer>, remove(2) removes the element at index 2, while remove(Integer.valueOf(2)) removes the value 2. Java picks the overload by type, which is easy to get wrong here.
Strings
A String is an object holding a sequence of characters, and it is immutable: once created, the characters can never change. Every method that looks like it modifies a string actually returns a new one.
public class Main {
public static void main(String[] args) {
String name = " Priya Sharma ";
System.out.println("[" + name + "]");
System.out.println("[" + name.trim() + "]");
System.out.println("Unchanged: [" + name + "]");
String clean = name.trim();
System.out.println("Length: " + clean.length());
System.out.println("Upper: " + clean.toUpperCase());
System.out.println("Lower: " + clean.toLowerCase());
System.out.println("Char 0: " + clean.charAt(0));
System.out.println("Sub: " + clean.substring(0, 5));
System.out.println("Index: " + clean.indexOf("Sharma"));
System.out.println("Starts: " + clean.startsWith("Priya"));
System.out.println("Replace:" + clean.replace("Priya", "Meera"));
String[] parts = clean.split(" ");
for (String p : parts) {
System.out.println("Part: " + p);
}
System.out.println("equals: " + clean.equals("Priya Sharma"));
System.out.println("equalsIgnore: " + clean.equalsIgnoreCase("PRIYA SHARMA"));
System.out.println("compareTo: " + clean.compareTo("Priya Sharma"));
int vowels = 0;
for (char c : clean.toCharArray()) {
if ("aeiouAEIOU".indexOf(c) >= 0) vowels++;
}
System.out.println("Vowels: " + vowels);
}
}
Why immutability matters
It sounds like a restriction. It buys three concrete things.
Safety when sharing. If you pass a string to a method, that method cannot change it behind your back. You never have to defend against it.
Reuse. Because two identical string literals can never diverge, Java keeps one copy in an internal pool and points both at it, saving memory.
Predictability in collections. A string used as a key in a hash-based structure cannot change while it is in there, which would otherwise leave the structure unable to find its own entry.
The cost is that building a string in a loop with s = s + x creates a brand-new string every pass, copying everything each time. For a handful of pieces this is irrelevant. For thousands, use StringBuilder, which is a mutable buffer with an append method and a toString() at the end.
Common mistakes
array.length()orstring.length. Arrays use the fieldlength; String and ArrayList use methodslength()andsize().- Looping to
i <= array.length. The last valid index islength - 1. This throwsArrayIndexOutOfBoundsException. - Comparing strings with
==. It compares references. Use.equals(). - Expecting
s.toUpperCase()to changes. It returns a new string. Writes = s.toUpperCase();. - Writing
ArrayList<int>. Generics need object types:ArrayList<Integer>. - Confusing
remove(index)andremove(object)on anArrayList<Integer>. Wrap the value:remove(Integer.valueOf(2)). - Calling a method on a
nullarray element. Anew String[5]is full of nulls until you fill it.
Arrays, lists and strings cover most of the data handling in a first-year syllabus. Try reversing an array in place and counting word frequencies in a sentence, then look at the collection problems on the Practice page.