4.3.1 Arrays Store Many Values of One Type
Suppose a program keeps the scores from five quizzes. With only what you know so far, you would declare five variables: quiz1, quiz2, quiz3, quiz4, and quiz5. That works, but it causes problems quickly. A class with 30 quizzes needs 30 declarations. And if the program asks “which quiz do you want to see?” and gets back the number 3, there is no way to turn that number into the name quiz3; you would need a long chain of if statements, one per quiz.
In Topic 4.2 you saw that a data set is a collection of related values that a program works through one value at a time. Java needs a way to keep such a collection under one name, with each value reachable by its position. Think of a row of numbered mailboxes in an apartment lobby: one bank of boxes, all the same size, each with a number on the door. You find a box by its number, not by a separate name.
That structure is an array: a single object that stores a fixed number of values, all of the same type. Each value in an array is called an element. The type of the elements is the array’s element type. An array of int holds only int values; an array of String holds only String references. (The mailbox analogy stops working in one way: real mailboxes can hold letters of any shape, but every slot in a Java array holds exactly one value of the element type.)
Why must every element have the same type? Java needs to know, when your code mentions an element, what kind of value it is, so that it can check your code before it runs (the same reason every variable has a declared type, from Topic 1.2). If one array could hold a name in one slot and a score in the next, Java could not tell whether + on an element means addition or concatenation.
Key idea
An array stores many values of one element type under a single name. The elements can be primitive values, such as
int or double, or object references, such as String.
Declaring and creating an array
Making an array takes two parts, which are usually written in one statement:
int[] scores = new int[5];
| Piece | What it is |
|---|---|
int[] |
The type of the variable: “array of int”. The empty square brackets mean “array of”. |
scores |
The variable’s name. It will hold a reference to the array. |
new int[5] |
Creates a new array object with room for 5 int elements. The number in the brackets is the size. |
= |
Stores the reference to the new array in scores, as with any object (Topic 1.13). |
An array is an object, so it is created with the keyword new, just like the objects you made in Topic 1.13. And as with every object, the variable does not contain the array itself; it holds a reference to it. Here is a picture of memory after the statement runs (you will see in 4.3.3 why every slot holds 0):
scores --> [ 0 | 0 | 0 | 0 | 0 ]
Worked example: Arrays with different element types
Each statement below creates one array. Read the left side as “this variable refers to an array of …” and the right side as “make a new array with room for … elements”.
double[] prices = new double[3];
boolean[] seatTaken = new boolean[40];
String[] names = new String[4];| Variable | Element type | Number of elements | Kind of element |
|---|---|---|---|
prices |
double |
3 | primitive value |
seatTaken |
boolean |
40 | primitive value |
names |
String |
4 | reference to a String object |
The element type is written twice, once on each side, and the two must match. The size appears only on the right, inside new, because the size belongs to the array object, not to the variable. A variable of type double[] can refer to a double array of any size.
Watch out
Mismatched element types. The type on the left and the type after new must be the same:
public class WrongElementType
{
public static void main(String[] args)
{
int[] scores = new double[5];
String[] names = new String[4];
}
}WrongElementType.java:5: error: incompatible types: double[] cannot be converted to int[]
int[] scores = new double[5];
^
1 errorStudents sometimes expect this to work because a single double value can be cast to int (Topic 1.5). But an array of double is a different kind of object from an array of int, and Java never converts one array type into another. Line 6 is fine because both sides say String. Fix line 5 by making both sides agree: int[] scores = new int[5];.
A second common slip is putting the size on the left, as in int[5] scores;. Java reports error: ']' expected, because the brackets in a type are always empty. The size goes after new.
public class SizeInDeclaration
{
public static void main(String[] args)
{
int[5] scores;
}
}Pause and try
Question 1 · Multiple choice
A weather program needs one array to hold the rainfall, in inches, for each of the 12 months. Which statement creates it correctly?
double[] rainfall = new double(12);double rainfall = new double[12];double[] rainfall = new double[12];double[] rainfall = new int[12];
Check your reasoning
C. The variable’s type is double[] (array of double), and new double[12] creates a double array with 12 elements. The element types match on both sides.
- A is wrong: an array’s size goes in square brackets, not parentheses. Java reports
'[' expected. - B is wrong: the variable is declared as a single
double, not an array ofdouble, so it cannot hold a reference to an array. Java reportsincompatible types: double[] cannot be converted to double. - D is wrong: the element types disagree. Java reports
incompatible types: int[] cannot be converted to double[]; it never converts one array type into another.
Reread 4.3.1 Arrays Store Many Values of One Type if you chose differently.
Question 2 · Short answer
A student wants one array to store each player’s name and that player’s score, alternating: name, score, name, score. Explain why Java does not allow this kind of array.
Check your reasoning
Model answer: Every element of an array has the same element type, which is fixed when the array is declared. An array of String can hold only String references, and an array of int can hold only int values, so names and scores cannot share one array. Java requires this so that it always knows what type an element is and can check the code before it runs. The usual solution is two arrays, one of String for the names and one of int for the scores.
A complete answer says:
- All elements of one array have the same type.
- Names (
String) and scores (int) are different types.
Reread 4.3.1 Arrays Store Many Values of One Type if your answer was missing one of these.
4.3.2 Reading and Changing Elements with an Index
An array is only useful if you can reach the values inside it. In the mailbox picture, you open a box by its number. In Java, that number is the element’s index: its position in the array. You met indexes in Topic 1.15, where the characters of a String were numbered starting from 0. Arrays use the same numbering. The first element is at index 0, the second at index 1, and so on.
To name one element, write the array variable, then the index in square brackets: scores[2] means “the element of scores at index 2”. This is called accessing an element. An expression like scores[2] behaves exactly like a variable of the element type: you can print it, use it in arithmetic, and assign a new value to it.
Key idea
arrayName[index] names one element. On the right side of = (or anywhere a value is needed) it reads the element;
on the left side of = it stores a new value in that element.
Here is how the indexes line up for an array of three scores:
index: 0 1 2
value: 88 92 75
Worked example: Storing and reading quiz scores
Read each line and decide whether it stores into an element (the element is on the left of =) or reads one.
int[] scores = new int[3];
scores[0] = 88;
scores[1] = 92;
scores[2] = 75;
System.out.println(scores[1]);
scores[2] = scores[2] + 10;
System.out.println(scores[2]);
System.out.println(scores[0] + scores[1]);| Line | What happens | scores[0] |
scores[1] |
scores[2] |
Printed |
|---|---|---|---|---|---|
| 1 | Create an array of 3 int elements |
0 | 0 | 0 | |
| 2 | Store 88 at index 0 | 88 | 0 | 0 | |
| 3 | Store 92 at index 1 | 88 | 92 | 0 | |
| 4 | Store 75 at index 2 | 88 | 92 | 75 | |
| 5 | Read index 1 | 88 | 92 | 75 | 92 |
| 6 | Read index 2 (75), add 10, store the 85 at index 2 | 88 | 92 | 85 | |
| 7 | Read index 2 | 88 | 92 | 85 | 85 |
| 8 | Read indexes 0 and 1 and add them as int values |
88 | 92 | 85 | 180 |
92
85
180Line 6 shows the two roles in one statement. Java evaluates the right side first, so scores[2] there reads 75. Then the left side scores[2] receives the result, 85. This is the same right-to-left order you learned for assignment in Topic 1.4; an element is just another place to store a value.
The index does not have to be a literal number. Any expression that produces an int works, including a variable or a little arithmetic. This is what solves the problem from 4.3.1: a number the program computes (or reads as input) can choose the element.
Worked example: Choosing the element with a variable
stepCounts holds the steps walked on four days. The variable day picks which day to look at.
int[] stepCounts = new int[4];
stepCounts[0] = 4200;
stepCounts[1] = 6100;
stepCounts[2] = 3900;
stepCounts[3] = 7500;
int day = 2;
System.out.println(stepCounts[day]);
System.out.println(stepCounts[day + 1]);
stepCounts[day] += 500;
System.out.println(stepCounts[day]);
day = 0;
System.out.println(stepCounts[day]);| Line | Index expression | Index used | Effect | Printed |
|---|---|---|---|---|
| 7 | day |
2 | Reads stepCounts[2] |
3900 |
| 8 | day + 1 |
3 | Reads stepCounts[3] |
7500 |
| 9 | day |
2 | += adds 500: 3900 becomes 4400 |
|
| 10 | day |
2 | Reads stepCounts[2] |
4400 |
| 12 | day |
0 | day was changed to 0 on line 11 |
4200 |
3900
7500
4400
4200Java works out the index expression first, then goes to that element. On line 8, day + 1 is 3, so the element at index 3 is read; day itself is not changed. Line 9 shows that the compound assignment operators from Topic 1.6 work on elements too: stepCounts[day] += 500; means stepCounts[day] = stepCounts[day] + 500;. Lines 10 and 12 are the same code, stepCounts[day], but they read different elements because day holds a different value each time.
Watch out
Counting from 1. People number things starting at 1, so “the first score” feels like index 1:
int[] scores = new int[3];
scores[0] = 88;
scores[1] = 92;
scores[2] = 75;
System.out.print("First score: ");
System.out.println(scores[1]);First score: 92The program compiles and runs, but it prints the second score. This is a logic error, so Java gives no message at all. The first element is always at index 0. A quick check: the element at index k is element number k + 1 when you count like a person. Fix line 6 to System.out.println(scores[0]);, which prints First score: 88.
Pause and try
Question 3 · Tracing
Trace this code. Give the value of each element after every line, and the exact output.
int[] prices = new int[3];
prices[0] = 12;
prices[1] = prices[0] * 2;
prices[2] = prices[1] - prices[0];
prices[0] = prices[2] + 1;
System.out.println(prices[0]);
System.out.println(prices[1]);
System.out.println(prices[2]);Check your reasoning
13
24
12| Line | Right side worked out | prices[0] |
prices[1] |
prices[2] |
|---|---|---|---|---|
| 1 | (array created) | 0 | 0 | 0 |
| 2 | 12 | 12 | 0 | 0 |
| 3 | 12 * 2 = 24 | 12 | 24 | 0 |
| 4 | 24 − 12 = 12 | 12 | 24 | 12 |
| 5 | 12 + 1 = 13 | 13 | 24 | 12 |
Line 5 changes only prices[0]. Changing one element never changes the others, even though prices[1] was originally computed from prices[0]; line 3 stored the number 24, not a formula.
Reread 4.3.2 Reading and Changing Elements with an Index if your trace differed.
Question 4 · Multiple choice
An array temps holds seven daily temperatures, Sunday through Saturday, in order. Which expression is Wednesday’s temperature?
temps[4]temps[3]temps(3)temps.3
Check your reasoning
B. Sunday is index 0, Monday 1, Tuesday 2, and Wednesday 3. An element is accessed with square brackets.
- A is wrong: Wednesday is the fourth day, but counting from 1 instead of 0 gives the index of Thursday.
- C is wrong: parentheses are for method calls; elements use square brackets.
- D is wrong: the dot operator reaches a method or attribute by name, not an element by position.
Reread 4.3.2 Reading and Changing Elements with an Index if you chose differently.
4.3.3 New Arrays Start with Default Values
In 4.3.2 the first row of each trace showed every element as 0 before anything was stored. That was not a guess. When new creates an array, Java does not leave the memory holding leftover junk. It fills every element with a default value that depends only on the element type.
You have seen these exact values before. In Topic 3.4, instance variables got default values before a constructor set them. Array elements follow the same rules, for the same reason: memory for a new object always starts in a known state, so a program never reads an unpredictable value.
| Element type | Default value |
|---|---|
int |
0 |
double |
0.0 |
boolean |
false |
any reference type, like String |
null |
Key idea
An array created with new has every element set to the default for its type: 0 for int, 0.0 for double,
false for boolean, and null for any reference type.
Worked example: Reading elements nobody assigned
None of these elements is ever assigned. Each print shows the default.
int[] goals = new int[3];
double[] heights = new double[3];
boolean[] present = new boolean[3];
String[] names = new String[3];
System.out.println(goals[0]);
System.out.println(heights[1]);
System.out.println(present[2]);
System.out.println(names[0]);0
0.0
false
nullLine 6 prints 0.0, not 0, because the element type is double, and a double always prints with a decimal point. Line 8 prints the word null: names[0] holds no reference at all, since no String object has been created for that slot. println shows a missing reference as null.
Default values are not only something to watch out for; programs rely on them. Here is a tally of votes for three candidates. Each element counts the votes for one candidate, and each count needs to start at 0, which new already did.
Worked example: A vote tally that starts at zero
int[] votes = new int[3];
votes[1]++;
votes[2]++;
votes[1]++;
System.out.println(votes[0]);
System.out.println(votes[1]);
System.out.println(votes[2]);| Line | Statement | votes[0] |
votes[1] |
votes[2] |
|---|---|---|---|---|
| 1 | create array | 0 | 0 | 0 |
| 2 | votes[1]++ |
0 | 1 | 0 |
| 3 | votes[2]++ |
0 | 1 | 1 |
| 4 | votes[1]++ |
0 | 2 | 1 |
0
2
1votes[1]++ adds 1 to the element at index 1 (Topic 1.6). Nobody had to write votes[0] = 0; first. Candidate 0 got no votes, and the default 0 correctly says so.
Watch out
Treating null elements as empty strings. A new String array holds null in every slot, not "". A null element is not a String object, so calling a method on it fails:
public class NullName
{
public static void main(String[] args)
{
String[] names = new String[3];
names[0] = "Ava";
System.out.println(names[0].length());
System.out.println(names[1].length());
}
}3
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "<local1>[1]" is null
at NullName.main(NullName.java:8)Line 7 works: names[0] refers to "Ava", which has 3 characters. Line 8 crashes with the NullPointerException from Topic 1.14, because names[1] was never assigned and still holds null. (The text after the exception name varies between Java versions.) Students expect "" because an empty string sounds like “nothing yet”, but "" is a real String object with length 0, and null means no object at all. Fix it by storing a String in the element before calling a method on it, for example names[1] = "Ben";.
Pause and try
Question 5 · Tracing
Write the exact output.
double[] tips = new double[4];
boolean[] paid = new boolean[4];
tips[1] = 3.5;
paid[1] = true;
tips[2] = tips[1] + tips[3];
System.out.println(tips[2]);
System.out.println(tips[0]);
System.out.println(paid[0]);
System.out.println(paid[1]);Check your reasoning
3.5
0.0
false
trueBoth arrays start with defaults: every tips element is 0.0 and every paid element is false. Line 3 sets tips[1] to 3.5 and line 4 sets paid[1] to true. On line 5, tips[3] was never assigned, so it is still 0.0, and 3.5 + 0.0 is 3.5. Line 7 prints the untouched tips[0] (0.0) and line 8 the untouched paid[0] (false).
Reread 4.3.3 New Arrays Start with Default Values if your output differed.
Question 6 · Multiple choice
After String[] titles = new String[5]; runs, what does titles[4] hold?
""(an empty string)- The four-letter string
"null" null- Nothing; reading an element before assigning it is a compile error
Check your reasoning
C. String is a reference type, and every element of a new reference-type array starts as null, meaning it refers to no object.
- A is wrong:
""is an actualStringobject. Java does not create anyStringobjects for the elements. - B is wrong:
printlnshows anullelement as the lettersnull, but the element holds no string at all. - D is wrong: elements always have a value, the default, so reading one is legal. (Calling a method on it would throw a
NullPointerException.)
Reread 4.3.3 New Arrays Start with Default Values if you chose differently.
4.3.4 Creating an Array with an Initializer List
Often you already know every value when you write the program: the days of the school week, the prices on a menu, the answer key to a quiz. Creating an array with new and then assigning each element on its own line works, but it takes one line per element and makes the values hard to see at a glance.
Java has a shorter way. An initializer list is a list of values inside curly braces, separated by commas, that creates an array and fills it in one step:
String[] days = {"Mon", "Tue", "Wed", "Thu", "Fri"};
| Piece | What it is |
|---|---|
String[] days |
Declares a variable that refers to an array of String |
{ |
Starts the list of starting values |
"Mon", "Tue", … |
The elements, in index order: "Mon" goes to index 0, "Tue" to index 1 |
} |
Ends the list |
There is no new and no size. Java counts the values in the list (five here) and makes an array of exactly that many elements. Every value in the list must fit the element type.
Key idea
{88, 92, 75} creates an array, sets its size to the number of values listed, and stores the values in order starting at index 0.Worked example: Three arrays from initializer lists
String[] days = {"Mon", "Tue", "Wed", "Thu", "Fri"};
double[] prices = {2.50, 3.75, 1.25};
boolean[] answers = {true, false, true, true};
System.out.println(days[2]);
System.out.println(prices[1]);
System.out.println(answers[1]);
days[0] = "Monday";
System.out.println(days[0]);Each list sets both the size and the contents:
days index: 0 1 2 3 4
value: "Mon" "Tue" "Wed" "Thu" "Fri"
prices index: 0 1 2
value: 2.5 3.75 1.25
answers index: 0 1 2 3
value: true false true trueWed
3.75
false
MondayLine 4 reads index 2 of days, the third value in its list. Line 7 shows that an array made from an initializer list is an ordinary array: you can change its elements afterward with square brackets, just like an array made with new.
The values in the list do not have to be literals. Any expression of the right type is allowed, and Java evaluates each one when the array is created.
Worked example: Expressions in the list
int base = 10;
int[] targets = {base, base * 2, base * 3 + 5};
System.out.println(targets[2]);
base = 50;
System.out.println(targets[0]);| Line | What happens | targets |
base |
|---|---|---|---|
| 1 | base gets 10 |
10 | |
| 2 | base is 10, base * 2 is 20, base * 3 + 5 is 35 |
{10, 20, 35} |
10 |
| 3 | Prints index 2 | {10, 20, 35} |
10 |
| 4 | base gets 50 |
{10, 20, 35} |
50 |
| 5 | Prints index 0 | {10, 20, 35} |
50 |
35
10Line 5 still prints 10. On line 2 Java copied the value of base into the element. The element and base are separate storage, so changing base later does not reach back into the array.
Both ways of creating an array are useful. Here they are side by side:
| Question | new int[3] |
{88, 92, 75} |
|---|---|---|
| How is the size decided? | The number in the brackets | The number of values in the list |
| What do the elements start as? | Default values (0 here) |
The listed values |
| When is it the better choice? | Values are not known yet, or start at 0 | All values are known when writing the code |
Watch out
Using an initializer list after the declaration. An initializer list is allowed only as part of the declaration that creates the array. It cannot be assigned to an existing array variable later:
public class InitializerLater
{
public static void main(String[] args)
{
int[] scores = {88, 92, 75};
scores = {90, 95, 80};
}
}InitializerLater.java:6: error: illegal start of expression
scores = {90, 95, 80};
^(Java prints a few more errors on the same line, because once it is confused it misreads the rest of the line.) Students try this because line 5 worked, so line 6 looks like the same idea. But the braces only mean “array values” right after a declaration such as int[] scores =; anywhere else, Java does not know what type of array to build. To change the values of the existing array, assign the elements one at a time: scores[0] = 90;, scores[1] = 95;, scores[2] = 80;.
Pause and try
Question 7 · Tracing
Write the exact output. Work out each index expression before you read the element.
int[] laps = {4, 7, 2, 9};
laps[2] = laps[0] + laps[3];
laps[0] = laps[laps[2] - 10];
System.out.println(laps[0]);
System.out.println(laps[2]);Check your reasoning
9
13| Line | Work | laps |
|---|---|---|
| 1 | The list makes four elements | {4, 7, 2, 9} |
| 2 | laps[0] + laps[3] is 4 + 9 = 13; store at index 2 |
{4, 7, 13, 9} |
| 3 | Index: laps[2] - 10 is 13 − 10 = 3; laps[3] is 9; store at index 0 |
{9, 7, 13, 9} |
On line 3, the index expression uses the new value of laps[2] (13), because line 2 already ran. Using the original 2 would give the index 2 − 10 = −8, which is not a position in the array at all; a trace that reaches that point should make you recheck which value the element holds now.
Reread 4.3.4 Creating an Array with an Initializer List and 4.3.2 Reading and Changing Elements with an Index if your trace differed.
Question 8 · Debugging
This program does not compile. Find both errors, explain each one, and write corrected lines.
public class MixedList
{
public static void main(String[] args)
{
int[] ages = {15, 16.5, 17};
String[] labels = {"gold", 2, "bronze"};
}
}Check your reasoning
Every value in an initializer list must fit the array’s element type.
- Line 5:
16.5is adouble, butagesis an array ofint. Java will not silently drop the.5(Topic 1.5), so it reportsincompatible types: possible lossy conversion from double to int. If ages are whole numbers, useint[] ages = {15, 16, 17};. If half-years matter, change the array type:double[] ages = {15, 16.5, 17};. - Line 6:
2is anint, butlabelsis an array ofString. Java reportsincompatible types: int cannot be converted to String. Use a string:String[] labels = {"gold", "silver", "bronze"};.
Reread 4.3.4 Creating an Array with an Initializer List and 4.3.1 Arrays Store Many Values of One Type if you missed either error.
4.3.5 Array Length Is Fixed
Code that works with an array often needs to know how many elements it has, for example to reach the last element. Hard-coding the number is risky: if someone later changes the initializer list from 4 values to 6, every 3 that meant “the last index” is now wrong.
Every array carries its own count. The number of elements is the array’s length, and you read it with the length attribute: write the array variable, a dot, and length, with no parentheses. colors.length is a value stored with the array object, not a method call.
The length is set once, at the moment the array is created (by the number in new int[6] or by the count of values in the list), and it can never change afterward. Java gives an array one block of memory with room for exactly that many elements, side by side; there is no extra room to grow into. The length attribute acts like a final variable from Topic 3.7: you may read it, but no statement can assign to it.
Key idea
An array’s length is fixed when the array is created. Read it with arrayName.length (no parentheses). The last
element is always at index arrayName.length - 1.
Worked example: Reading the length
String[] colors = {"red", "green", "blue", "gold"};
int[] blank = new int[6];
System.out.println(colors.length);
System.out.println(blank.length);
System.out.println(colors[colors.length - 1]);
System.out.println(colors[0].length());| Line | Expression | Value | Printed |
|---|---|---|---|
| 3 | colors.length |
4 values in the list | 4 |
| 4 | blank.length |
the size given to new, even though every element is 0 |
6 |
| 5 | colors[colors.length - 1] |
index 4 − 1 = 3, which holds "gold" |
gold |
| 6 | colors[0].length() |
the String "red" has 3 characters |
3 |
4
6
gold
3Line 5 is the standard way to reach the last element: it works for an array of any length, because it asks the array itself. Line 6 is a different thing: colors[0] is a String, and length() with parentheses is the String method from Topic 1.15.
Lines 5 and 6 sit next to each other on purpose, because these two are easy to mix up:
| You have… | How to get its size | Why | Example |
|---|---|---|---|
| an array | .length |
length is an attribute of the array |
colors.length |
a String |
.length() |
length is a method of String |
"red".length() |
Worked example: Trying to make an array bigger
A program has three scores and wants to add a fourth. A student writes scores = new int[4];, hoping to stretch the array:
int[] scores = {88, 92, 75};
scores = new int[4];
scores[3] = 81;
System.out.println(scores.length);
System.out.println(scores[0]);
System.out.println(scores[3]);4
0
81The length did go from 3 to 4, so it looks as though the array grew. It did not. Line 2 created a brand-new array of four elements, all 0, and stored its reference in scores. The old array, holding 88, 92, and 75, still has length 3; the program simply has no reference to it anymore. Line 5 proves it: scores[0] is 0, not 88.
before line 2: scores --> [ 88 | 92 | 75 ]
after line 2: scores --> [ 0 | 0 | 0 | 0 ]
[ 88 | 92 | 75 ] (no variable refers to this one)A variable can be pointed at a different array, but an existing array’s length never changes. To keep the old values in a bigger array, a program has to create the new array and then copy each value across, element by element.
Watch out
Writing length() or assigning to length. Both of these come from treating an array like a String or like an ordinary variable:
public class LengthMistakes
{
public static void main(String[] args)
{
int[] scores = {88, 92, 75};
System.out.println(scores.length());
scores.length = 4;
}
}LengthMistakes.java:6: error: cannot find symbol
System.out.println(scores.length());
^
symbol: method length()
location: variable scores of type int[]
LengthMistakes.java:7: error: cannot assign a value to final variable length
scores.length = 4;
^
2 errorsLine 6: arrays have no length() method, so Java cannot find one. Remove the parentheses: scores.length. Line 7: the length is final, so Java refuses to change it. There is no fix that resizes the array; create a new array of the size you need instead.
Pause and try
Question 9 · Tracing
Write the exact output.
double[] times = {12.4, 11.9, 13.2, 12.8, 12.1};
int last = times.length - 1;
System.out.println(times.length);
System.out.println(times[last]);
System.out.println(times[times.length / 2]);Check your reasoning
5
12.1
13.2The list has 5 values, so times.length is 5 and line 3 prints 5. Line 2 stores 5 − 1 = 4 in last, and times[4] is the last value, 12.1. On line 5, times.length / 2 is 5 / 2, which is int division (Topic 1.3), giving 2; times[2] is 13.2, the middle value.
Reread 4.3.5 Array Length Is Fixed if your output differed.
Question 10 · Multiple choice
int[] scores refers to an array. Which expression is the number of elements in the array?
scores.length()scores.lengthscores[scores.length]scores.length - 1
Check your reasoning
B. An array’s number of elements is its length attribute, written without parentheses.
- A is wrong:
length()with parentheses is theStringmethod. Arrays have no such method, so this is a compile error (cannot find symbol). - C is wrong: this tries to read an element at index
scores.length, which is one past the last valid index. - D is wrong: this is the index of the last element, which is one less than the number of elements.
Reread 4.3.5 Array Length Is Fixed if you chose differently.
4.3.6 Valid Indexes and Out-of-Bounds Errors
Indexes start at 0, and the last element is at length - 1. Put those together and you get the full rule: for an array of length n, the valid indexes are 0, 1, 2, … up to n - 1, inclusive. An array of length 3 has valid indexes 0, 1, and 2, and nothing else. Index 3 is not “the end of the array”; it is a slot that does not exist.
index: -1 | 0 1 2 | 3
[ 88 | 92 | 75 ]
out valid indexes out
Using any index outside that range, whether to read or to store, makes Java throw an ArrayIndexOutOfBoundsException while the program runs. This is the array version of the StringIndexOutOfBoundsException from Topic 1.15. Java checks every index at the moment it is used, because silently reading or writing memory outside the array would damage other data in the program.
Why doesn’t the compiler catch it? The compiler checks only that the index is an int. It does not know what value a variable like day will hold or how long an array will be when the line runs, so a bad index can be found only while the program runs.
Key idea
The valid indexes of an array are 0 through length - 1, inclusive. Any other index, including length itself or a
negative number, throws an ArrayIndexOutOfBoundsException when that line runs.
Worked example: One step too far
The most common out-of-bounds index is length itself:
public class OffByOne
{
public static void main(String[] args)
{
int[] scores = {88, 92, 75};
System.out.println(scores[scores.length - 1]);
System.out.println(scores[scores.length]);
System.out.println("Done");
}
}75
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
at OffByOne.main(OffByOne.java:7)| Line | Index used | Valid? | Result |
|---|---|---|---|
| 6 | scores.length - 1 is 2 |
yes | prints 75 |
| 7 | scores.length is 3 |
no | exception; the program stops |
| 8 | (never runs) |
The program compiles without complaint. Line 6 runs normally. Line 7 throws the exception, and because nothing handles it, the program ends right there; Done is never printed. The message names the bad index and the array’s length, which is the first thing to read when you see this error. (The wording after the exception name can vary between Java versions.)
Negative indexes are just as invalid, and they often come from converting a person’s numbering (starting at 1) to an index by subtracting 1.
Worked example: A negative index
public class NegativeIndex
{
public static void main(String[] args)
{
String[] floors = {"Lobby", "Gym", "Pool"};
int choice = 1;
floors[choice - 1] = "Entrance";
System.out.println(floors[0]);
choice = 0;
floors[choice - 1] = "Basement";
System.out.println(floors[0]);
}
}Entrance
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 3
at NegativeIndex.main(NegativeIndex.java:10)On line 7, choice - 1 is 0, a valid index, so "Lobby" is replaced by "Entrance" and line 8 prints it. On line 10, choice - 1 is −1. Storing into an element is checked exactly like reading one, so the exception is thrown before anything is stored, and line 11 never runs.
When an index comes from a calculation or from input, you can make sure it is valid before using it with an if statement and a compound condition from Topics 2.3 and 2.5:
Worked example: Checking an index first
public class GuardedLookup
{
public static void main(String[] args)
{
String[] prizes = {"sticker", "pen", "mug", "hoodie"};
int pick = 4;
if (pick >= 0 && pick < prizes.length)
{
System.out.println(prizes[pick]);
}
else
{
System.out.println("No prize at that spot");
}
pick = 3;
if (pick >= 0 && pick < prizes.length)
{
System.out.println(prizes[pick]);
}
else
{
System.out.println("No prize at that spot");
}
}
}No prize at that spot
hoodieThe condition pick >= 0 && pick < prizes.length is exactly the valid-index rule written in Java. Notice <, not <=: with 4 prizes, prizes.length is 4, and 4 is not a valid index. On line 7, pick is 4, so 4 < 4 is false and the else branch runs instead of crashing. On line 16, pick is 3, which passes both tests, so line 18 reads prizes[3].
Watch out
Expecting the array to grow when you store past the end. Some students expect scores[3] = 60; on a three-element array to add a fourth element:
public class StoreOutOfBounds
{
public static void main(String[] args)
{
int[] scores = new int[3];
scores[0] = 88;
scores[1] = 92;
scores[2] = 75;
System.out.println(scores.length);
scores[3] = 60;
System.out.println(scores.length);
}
}3
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
at StoreOutOfBounds.main(StoreOutOfBounds.java:10)Line 10 does not add anything. The length was fixed at 3 when the array was created (4.3.5), so index 3 does not exist and Java throws the exception. If the program needs room for four scores, create the array with new int[4] from the start.
Pause and try
Question 11 · Multiple choice
After int[] codes = new int[8];, which expression throws an ArrayIndexOutOfBoundsException when it runs?
codes[0]codes[7]codes[8]codes[codes.length - 8]
Check your reasoning
C. The array has length 8, so its valid indexes are 0 through 7. Index 8 is one past the end.
- A is wrong: 0 is always the first valid index of an array that has any elements.
- B is wrong: 7 is
length - 1, the last valid index. - D is wrong:
codes.length - 8is 8 − 8 = 0, a valid index.
Reread 4.3.6 Valid Indexes and Out-of-Bounds Errors if you chose differently.
Question 12 · Short answer
A student says, “My program compiled with no errors, so every array index in it must be valid.” Explain why the student is wrong.
Check your reasoning
Model answer: The compiler checks only that each index is an int; it does not work out what value the index will have. Indexes often come from variables or calculations whose values are known only while the program runs, so the compiler cannot tell whether they will be in the range 0 to length - 1. Java checks each index when the line actually runs and throws an ArrayIndexOutOfBoundsException then, as OffByOne.java did after compiling cleanly.
A complete answer says:
- The compiler checks the type of the index, not its value.
- An out-of-range index is found only while the program runs, as an
ArrayIndexOutOfBoundsException.
Reread 4.3.6 Valid Indexes and Out-of-Bounds Errors if your answer was missing one of these.
4.3.7 Arrays of Object References
In 4.3.1 you read that elements can be primitive values or object references. So far most examples used int, double, and boolean, where each element holds the value itself. When the element type is a class, such as String or a class you wrote in Unit 3, each element holds a reference to an object, exactly as a variable of that class type would (Topic 1.13).
That one fact explains everything about these arrays:
- Creating the array does not create the objects.
new Player[3]makes an array with three slots for references. Each slot starts asnull(4.3.3). NoPlayerobjects exist until you create them withnew Player(…)and store them in the slots. - An element can be used like any variable of its class.
team[0].getName()follows the reference inteam[0]and callsgetNameon that object, using the dot operator from Topic 1.14. - Copying an element copies the reference. As in Topic 3.6, two elements, or an element and a variable, can refer to the same object.
Key idea
In an array of a class type, each element holds a reference to an object, or null. new ClassName[n] creates only
the slots; each object must be created separately and stored in an element before its methods can be called.
Worked example: A team roster
This file has two classes. Java allows only one public class per file, so the helper class here leaves off public; in a real project each class gets its own file.
class Player
{
private String name;
private int points;
public Player(String name)
{
this.name = name;
points = 0;
}
public String getName()
{
return name;
}
public int getPoints()
{
return points;
}
public void addPoints(int amount)
{
points += amount;
}
}
public class TeamRoster
{
public static void main(String[] args)
{
Player[] team = new Player[3];
System.out.println(team[0]);
team[0] = new Player("Ana");
team[1] = new Player("Ben");
team[1].addPoints(6);
team[0].addPoints(4);
team[1].addPoints(2);
System.out.println(team[0].getName());
System.out.println(team[1].getPoints());
System.out.println(team[2]);
}
}| Line | What happens | team[0] |
team[1] |
team[2] |
Printed |
|---|---|---|---|---|---|
| 32 | Array of 3 references created | null |
null |
null |
|
| 33 | Print team[0] |
null |
null |
null |
null |
| 34 | New Player Ana, 0 points |
Ana, 0 | null |
null |
|
| 35 | New Player Ben, 0 points |
Ana, 0 | Ben, 0 | null |
|
| 36 | addPoints(6) on Ben |
Ana, 0 | Ben, 6 | null |
|
| 37 | addPoints(4) on Ana |
Ana, 4 | Ben, 6 | null |
|
| 38 | addPoints(2) on Ben |
Ana, 4 | Ben, 8 | null |
|
| 39 | team[0].getName() |
Ana, 4 | Ben, 8 | null |
Ana |
| 40 | team[1].getPoints() |
Ana, 4 | Ben, 8 | null |
8 |
| 41 | Print team[2] |
Ana, 4 | Ben, 8 | null |
null |
null
Ana
8
nullIn the table, “Ana, 4” is short for “a reference to the Player object whose name is Ana and whose points are 4”. The objects live outside the array; the array holds only the references. team[2] was never given an object, so it is still null at the end.
The same rules apply to an array of String. Each element refers to a String object, so you can call String methods from Topic 1.15 on an element:
cities --> [ ref | ref | ref ]
| | |
v v v
"Denver" "Austin" "Boston"
Worked example: Calling String methods on elements
String[] cities = {"Denver", "Austin", "Boston"};
String code = cities[1].substring(0, 3);
System.out.println(code);
System.out.println(cities[2].length());
cities[0] = cities[0] + " CO";
System.out.println(cities[0]);Aus
6
Denver COLine 2 calls substring(0, 3) on the object cities[1] refers to, "Austin", giving "Aus". Line 4 asks "Boston" for its length, 6. Line 5 builds a new String by concatenation and stores its reference in cities[0]; strings are immutable (Topic 1.15), so the element now refers to a different object, "Denver CO".
Because elements hold references, an element and a variable can be aliases, two names for one object.
Worked example: Two names for one player
SharedPlayer.java uses the same Player class as TeamRoster.java; only main (starting at line 30) is different.
class Player
{
private String name;
private int points;
public Player(String name)
{
this.name = name;
points = 0;
}
public String getName()
{
return name;
}
public int getPoints()
{
return points;
}
public void addPoints(int amount)
{
points += amount;
}
}
public class SharedPlayer
{
public static void main(String[] args)
{
Player star = new Player("Cara");
Player[] lineup = new Player[2];
lineup[0] = star;
lineup[1] = new Player("Dev");
lineup[0].addPoints(10);
System.out.println(star.getPoints());
star.addPoints(3);
System.out.println(lineup[0].getPoints());
lineup[0] = lineup[1];
System.out.println(lineup[0].getName());
System.out.println(star.getName());
}
}| Line | What happens | Cara’s points | lineup[0] refers to |
Printed |
|---|---|---|---|---|
| 32 | star refers to a new Player, Cara |
0 | ||
| 34 | The reference in star is copied into lineup[0] |
0 | Cara | |
| 36 | addPoints(10) through lineup[0] changes Cara’s object |
10 | Cara | |
| 37 | star.getPoints() asks the same object |
10 | Cara | 10 |
| 38–39 | Adding 3 through star, then reading through lineup[0] |
13 | Cara | 13 |
| 40 | The reference in lineup[1] (Dev) is copied into lineup[0] |
13 | Dev | |
| 41–42 | lineup[0] now names Dev; star still names Cara |
13 | Dev | Dev, Cara |
10
13
Dev
CaraLine 34 did not copy the player; it copied the reference, so changes made through either name show up through the other. Line 40 replaced only the reference stored in lineup[0]. It did not change Cara’s object or the variable star.
Watch out
Calling a method on a slot that has no object. Students often assume new Player[2] creates two players:
class Player
{
private String name;
private int points;
public Player(String name)
{
this.name = name;
points = 0;
}
public String getName()
{
return name;
}
public int getPoints()
{
return points;
}
public void addPoints(int amount)
{
points += amount;
}
}
public class EmptyRoster
{
public static void main(String[] args)
{
Player[] team = new Player[2];
team[0] = new Player("Ana");
team[0].addPoints(5);
System.out.println(team[0].getPoints());
team[1].addPoints(5);
System.out.println(team[1].getPoints());
}
}5
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Player.addPoints(int)" because "<local1>[1]" is null
at EmptyRoster.main(EmptyRoster.java:36)Line 32 created two empty slots. Line 33 filled team[0], so lines 34 and 35 work. team[1] was never filled; it is still null, so line 36 throws a NullPointerException. Notice that this is not an index problem: index 1 is valid. The slot exists, but nothing is in it. The fix is to create the object first, for example team[1] = new Player("Ben"); before line 36. (The text after the exception name varies between Java versions.)
Pause and try
Question 13 · Tracing
RosterTrace.java uses the same Player class as TeamRoster.java. Write the exact output.
class Player
{
private String name;
private int points;
public Player(String name)
{
this.name = name;
points = 0;
}
public String getName()
{
return name;
}
public int getPoints()
{
return points;
}
public void addPoints(int amount)
{
points += amount;
}
}
public class RosterTrace
{
public static void main(String[] args)
{
Player[] squad = new Player[3];
squad[2] = new Player("Eli");
squad[0] = new Player("Fay");
squad[1] = squad[2];
squad[1].addPoints(7);
squad[2].addPoints(1);
squad[0].addPoints(squad[2].getPoints());
System.out.println(squad[0].getPoints());
System.out.println(squad[1].getName());
System.out.println(squad[2].getPoints());
}
}Check your reasoning
8
Eli
8| Line | What happens | Eli’s points | Fay’s points |
|---|---|---|---|
| 33 | squad[2] refers to a new Player, Eli |
0 | |
| 34 | squad[0] refers to a new Player, Fay |
0 | 0 |
| 35 | The reference in squad[2] is copied into squad[1]: both name Eli |
0 | 0 |
| 36 | squad[1].addPoints(7) changes Eli |
7 | 0 |
| 37 | squad[2].addPoints(1) changes Eli again |
8 | 0 |
| 38 | squad[2].getPoints() is 8; Fay gets 8 |
8 | 8 |
Only two Player objects exist. squad[1] and squad[2] are aliases for Eli, so line 40 prints Eli and line 41 prints Eli’s 8 points. If you printed 7 and 1 separately, you treated squad[1] and squad[2] as different players; line 35 copied a reference, not an object.
Reread 4.3.7 Arrays of Object References if your trace differed.
Question 14 · Multiple choice
After Player[] bench = new Player[4]; runs, how many Player objects have been created?
- 0
- 1
- 4
- 5
Check your reasoning
A. new Player[4] creates one array object with four slots, each holding null. No Player constructor runs, so no Player objects exist yet.
- B is wrong: it counts the array as a
Player. The array is an object, but it is an array of references, not a player. - C is wrong: it assumes Java fills each slot with a new object. Slots start as
null(the default for reference types). - D is wrong: it counts four players plus the array; neither the players nor this total is right.
Reread 4.3.7 Arrays of Object References if you chose differently.
Putting it together
This program records lunch votes. It uses an initializer list for the menu, new with default values for the vote counts, the length attribute to keep the two arrays the same size, index arithmetic to reach the last element, and an index check before reading. Predict all five lines of output before you read the trace.
Worked example: Lunch vote
public class LunchVote
{
public static void main(String[] args)
{
String[] menu = {"Pizza", "Tacos", "Salad", "Soup"};
int[] votes = new int[menu.length];
votes[1]++;
votes[3]++;
votes[1]++;
votes[0] += 2;
System.out.println(menu.length + " choices");
System.out.println(menu[1] + ": " + votes[1]);
System.out.println(menu[2] + ": " + votes[2]);
int last = menu.length - 1;
System.out.println(menu[last] + ": " + votes[last]);
int request = 4;
if (request >= 0 && request < menu.length)
{
System.out.println(menu[request]);
}
else
{
System.out.println("Choice " + request + " is not on the menu");
}
}
}Setting up (lines 5–6). The initializer list makes menu an array of 4 String references. Line 6 creates votes with new int[menu.length], so it also has 4 elements, all starting at 0. Using menu.length instead of typing 4 keeps the arrays matched: if someone adds a fifth food to the list, votes grows with it the next time the program runs. The two arrays line up by index: votes[k] counts the votes for menu[k].
index: 0 1 2 3
menu: "Pizza" "Tacos" "Salad" "Soup"
votes: 0 0 0 0Counting (lines 8–11).
| Line | Statement | votes |
|---|---|---|
| 8 | votes[1]++ |
{0, 1, 0, 0} |
| 9 | votes[3]++ |
{0, 1, 0, 1} |
| 10 | votes[1]++ |
{0, 2, 0, 1} |
| 11 | votes[0] += 2 |
{2, 2, 0, 1} |
Reporting (lines 13–28).
| Line | Work | Printed |
|---|---|---|
| 13 | menu.length is 4 |
4 choices |
| 14 | menu[1] is "Tacos", votes[1] is 2 |
Tacos: 2 |
| 15 | menu[2] is "Salad", votes[2] is still the default 0 |
Salad: 0 |
| 17–18 | last is 4 − 1 = 3; menu[3] is "Soup", votes[3] is 1 |
Soup: 1 |
| 20–27 | request is 4; 4 < 4 is false, so the else runs instead of crashing |
Choice 4 is not on the menu |
4 choices
Tacos: 2
Salad: 0
Soup: 1
Choice 4 is not on the menuWithout the check on line 21, line 23 would try menu[4] and throw an ArrayIndexOutOfBoundsException, because an array of length 4 has no index 4.
Common mistakes
Arrays produce a handful of error messages over and over. Use this table to go from the message to the cause.
| Message (key words) | Usual cause | Fix |
|---|---|---|
incompatible types: double[] cannot be converted to int[] |
Element types differ on the two sides of = |
Use the same element type on both sides |
']' expected |
A size inside the brackets of the type, as in int[5] scores |
Leave the type’s brackets empty; put the size after new |
illegal start of expression at { |
An initializer list assigned after the declaration | Assign elements one at a time, or use the list in the declaration |
cannot find symbol … method length() |
length() written for an array |
Write length with no parentheses |
cannot assign a value to final variable length |
Trying to change an array’s length | Create a new array of the size you need |
ArrayIndexOutOfBoundsException (while running) |
An index below 0 or at least length, often arr[arr.length] |
Use 0 through length - 1; check an index before using it |
NullPointerException (while running) |
A method called on an element that is still null |
Store an object in the element first |
Vocabulary
| Term | Definition | Example |
|---|---|---|
| array | An object that stores a fixed number of values, all of the same type, under one name | int[] scores = new int[5]; |
| element | One value stored in an array | scores[2] |
| element type | The type every element of an array must have | double in double[] |
| index | An element’s position in an array, starting at 0 | 2 in scores[2] |
| default value | The value Java puts in each element when new creates an array |
0, 0.0, false, null |
| initializer list | Values in curly braces that create an array and set its size and contents in one step | {88, 92, 75} |
| length | The number of elements in an array, set at creation and never changed; read with .length |
scores.length |
| valid index | Any index from 0 through length - 1, inclusive |
0, 1, 2 for a length-3 array |
| ArrayIndexOutOfBoundsException | The run-time error thrown when code uses an index outside the valid range | scores[scores.length] |
Chapter summary
- An array is an object that stores many values of a single element type under one name. The elements can be primitive values or object references, and the array variable holds a reference to the array.
new int[5]creates an array of a given length with every element set to its default (0,0.0,false, ornull); an initializer list such as{88, 92, 75}creates an array whose length and contents come from the listed values, and it may appear only in the declaration.arrayName[index]reads or changes one element. The index can be anyintexpression, and the first element is at index 0.- An array’s length is fixed when it is created and is read with the
lengthattribute, without parentheses. Assigning a new array to a variable makes a new array; it never resizes the old one. - The valid indexes are 0 through
length - 1. Any other index throws anArrayIndexOutOfBoundsExceptionwhen the line runs, which the compiler cannot catch. - In an array of a class type, creating the array creates only
nullslots; each object must be created and stored before its methods are called, and copying an element copies a reference.
Review questions
Question 15 · Multiple choice
Which statement about arrays is true?
- After
boolean[] flags = new boolean[3];, every element offlagsistrue. - An array created with an initializer list can have its length increased later by adding values to the list.
- After
double[] rates = {1.5, 2.0};, the expressionrates[rates.length - 1]is2.0. - The valid indexes of an array of length 10 are 1 through 10.
Check your reasoning
C. rates.length is 2, so rates.length - 1 is 1, the last valid index, and rates[1] is 2.0.
- A is wrong: the default value for
booleanelements isfalse, nottrue. - B is wrong: the list is used once, when the array is created. After that the length is fixed and cannot be increased.
- D is wrong: indexes start at 0, so the valid indexes are 0 through 9. Index 10 would throw an
ArrayIndexOutOfBoundsException.
Reread 4.3.3 New Arrays Start with Default Values, 4.3.5 Array Length Is Fixed, and 4.3.6 Valid Indexes and Out-of-Bounds Errors if you chose differently.
Question 16 · Tracing
Write the exact output. Some elements are never assigned.
double[] miles = new double[4];
int[] trips = {2, 5, 1};
miles[trips[2]] = 3.5;
miles[0] = miles[1] * trips.length;
trips[0] = trips[0] + miles.length;
System.out.println(miles[0]);
System.out.println(miles[3]);
System.out.println(trips[0]);Check your reasoning
10.5
0.0
6| Line | Work | miles |
trips |
|---|---|---|---|
| 1 | Four double elements, all default |
{0.0, 0.0, 0.0, 0.0} |
|
| 2 | List of three int values |
{0.0, 0.0, 0.0, 0.0} |
{2, 5, 1} |
| 3 | Index trips[2] is 1; store 3.5 at miles[1] |
{0.0, 3.5, 0.0, 0.0} |
{2, 5, 1} |
| 4 | miles[1] * trips.length is 3.5 × 3 = 10.5 |
{10.5, 3.5, 0.0, 0.0} |
{2, 5, 1} |
| 5 | trips[0] + miles.length is 2 + 4 = 6 |
{10.5, 3.5, 0.0, 0.0} |
{6, 5, 1} |
Line 7 prints miles[3], which was never assigned and still holds the default 0.0. Each array has its own length: trips.length is 3 and miles.length is 4.
Reread 4.3.2 Reading and Changing Elements with an Index, 4.3.3 New Arrays Start with Default Values, and 4.3.5 Array Length Is Fixed if your trace differed.
Question 17 · Debugging
This program should print the highest badge, Platinum. Instead it prints 4 badges and then crashes. Explain the error and write the corrected line.
public class LastBadge
{
public static void main(String[] args)
{
String[] badges = {"Bronze", "Silver", "Gold", "Platinum"};
int count = badges.length;
System.out.println(count + " badges");
System.out.println("Top badge: " + badges[count]);
}
}Check your reasoning
Line 8 uses badges[count], and count holds badges.length, which is 4. The array has 4 elements at indexes 0 through 3, so index 4 does not exist and Java throws ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 4. Line 7 already ran, which is why 4 badges appears first. The length counts elements, but the last index is one less than that.
Corrected line 8:
System.out.println("Top badge: " + badges[count - 1]);Now the program prints 4 badges and then Top badge: Platinum.
Reread 4.3.6 Valid Indexes and Out-of-Bounds Errors if you missed it.
Question 18 · Multiple choice
What happens when this program runs?
class Book
{
private String title;
public Book(String title)
{
this.title = title;
}
public String getTitle()
{
return title;
}
}
public class ShelfNull
{
public static void main(String[] args)
{
Book[] shelf = new Book[3];
shelf[0] = new Book("Dune");
System.out.println(shelf[0].getTitle());
System.out.println(shelf[1].getTitle());
}
}- It prints
Dune, thennull. - It prints
Dune, then throws aNullPointerException. - It prints
Dune, then throws anArrayIndexOutOfBoundsException. - It does not compile, because
shelf[1]was never assigned.
Check your reasoning
B. Line 20 creates three null slots, and line 21 fills only shelf[0], so line 22 prints Dune. On line 23, shelf[1] is still null, and calling getTitle() on null throws a NullPointerException.
- A is wrong: printing
shelf[1]by itself would shownull, but line 23 calls a method on it, and there is no object to call it on. - C is wrong: index 1 is valid for an array of length 3; the slot exists but holds no object.
- D is wrong: elements always have a value (here the default
null), so the compiler accepts the code. The problem appears only when line 23 runs.
Reread 4.3.7 Arrays of Object References if you chose differently.
Question 19 · Short answer
A program declares int[] scores = new int[30]; for a class of 30 students. Midyear, 2 students join. A student suggests writing scores.length = 32;. Explain why this does not work, and describe what scores = new int[32]; would do instead.
Check your reasoning
Model answer: An array’s length is set when the array is created and can never change; the length attribute is final, so scores.length = 32; is a compile error (cannot assign a value to final variable length). Writing scores = new int[32]; does compile, but it does not enlarge the old array. It creates a separate new array of 32 elements, all 0, and makes scores refer to it. The 30 scores in the old array are no longer reachable through scores, so they would need to be copied into the new array one element at a time before the variable is changed.
A complete answer says:
- The length is fixed at creation;
lengthcannot be assigned. new int[32]makes a new array with default values; the old values are not carried over.
Reread 4.3.5 Array Length Is Fixed if your answer was missing one of these.
Question 20 · Tracing
Here the index of each element comes from another element of the same array. Write the exact output.
int[] code = {3, 0, 2, 1};
System.out.println(code[code[0]]);
code[code[3]] = code[code[2]] + 5;
System.out.println(code[1]);
System.out.println(code[code[1] - 5]);Check your reasoning
1
7
2Work from the inside out: evaluate the inner element to get an index, then read the outer one.
| Line | Inner work | Outer work | code |
|---|---|---|---|
| 1 | {3, 0, 2, 1} |
||
| 2 | code[0] is 3 |
code[3] is 1; prints 1 |
{3, 0, 2, 1} |
| 3 | Left: code[3] is 1. Right: code[2] is 2 |
code[2] + 5 is 7; store at index 1 |
{3, 7, 2, 1} |
| 4 | code[1] is 7; prints 7 |
{3, 7, 2, 1} |
|
| 5 | code[1] - 5 is 7 − 5 = 2 |
code[2] is 2; prints 2 |
{3, 7, 2, 1} |
On line 3, both index expressions are worked out before the value is stored, so the store goes to index 1 (the value of code[3]).
Reread 4.3.2 Reading and Changing Elements with an Index if your trace differed.
Question 21 · Multiple choice
Consider these three code segments.
// I
double[] d = new double[2];
d[2] = 1.5;
// II
boolean[] b = {true, false};
b[1] = !b[0];
System.out.println(b[1]);
// III
String[] s = new String[2];
System.out.println(s[0]);Which segments compile and run without throwing an exception?
- I only
- II only
- II and III only
- I, II, and III
Check your reasoning
C. Segment II stores !true, which is false, in b[1] and prints false. Segment III prints null, the default value of a String element; printing null is fine, only calling a method on it fails. Segment I compiles but throws an ArrayIndexOutOfBoundsException, because an array of length 2 has valid indexes 0 and 1 only.
- A is wrong: segment I is the one that fails, and II and III both work.
- B is wrong: it leaves out III, probably by confusing printing a
nullelement with calling a method on it. - D is wrong: it treats index 2 as valid for an array of length 2; the last valid index is
length - 1.
Reread 4.3.3 New Arrays Start with Default Values and 4.3.6 Valid Indexes and Out-of-Bounds Errors if you chose differently.
Reflection
- I can explain what an array is, why all its elements share one type, and declare and create one with new. Reread
- I can read and change one element using an index in square brackets, starting from index 0. Reread
- I can state the default value of each element of a new int, double, boolean, or reference-type array. Reread
- I can create an array with an initializer list and say how its length is decided. Reread
- I can use the length attribute, reach the last element, and explain why an array cannot grow. Reread
- I can list the valid indexes of an array and predict when an ArrayIndexOutOfBoundsException is thrown. Reread
- I can trace an array of object references, including null slots and two names for one object. Reread