Module 5, Part 1: Arrays#
Up until now, we have seen how to write programs that handle values of various
types — e.g., int
, boolean
, String
… Moreover, all the programs we have
seen until now have a common characteristic: we exactly know how many values
each program maintains in memory at each point during its execution. This can be
determined by selecting a position in the program code, and looking at which
variables are in scope.
However, a program may sometimes need to handle a number of values that is only known at run-time. In this case, we can use arrays. An array is a structured data type: when a value of type “array” is created, it acts as a container for other values, which we can access and modify.
Arrays#
An array is a collection of values of the same type; each value contained in an array is identified by an index, which is the position of the value inside the array itself. Most programming languages offer arrays as a fundamental data stucture, i.e. a way to organise, store, and access values in the computer memory.
Before delving into arrays, we first consider a problem that requires us to use arrays. Then, we explore:
the fundamentals of arrays in Java, and
how to loop over arrays.
We also discuss a very useful example: how to split a string into an array of strings.
Goal: an Interactive Program that Reads Lotto Numbers#
Our goal is to write a program that runs on the console (a.k.a. terminal) and behaves as follows:
Asks the user how many Lotto numbers they want to play;
Reads the Lotto numbers one by one, ensuring that:
each number is between 1 and 36, and
each number is unique.
If one of the conditions above does not hold, the program asks the user to enter a correct Lotto number instead.
Finally, the program prints a summary of all the Lotto numbers provided by the user.
Based on what we have seen so far, the description above means that we need to write a program that uses some form of loop. However, we have not yet seen how a Java program can store and read an arbitrary number of values (in this case, determined by how many Lotto numbers the user wishes to play). To achieve this, we will use an array to store the lotto numbers.
(Lotto numbers)
The following Java program behaves according to the description above, and uses an array. We discuss arrays in the rest of this section.
Besides the array, the program below uses some constructs that deserve a few comments:
On line 11, the
for
statement has an empty update statement (notice that there is nothing between the last semicolon;
and the closing parenthesis)
on that line). This simply means that thefor
loop does not execute any update statement after the loop body — it just checks the loop condition again. The loop variablei
is updated on line 32 (but only if the condition!isDuplicate
on line 28 istrue
).On line 17, the
for
loop body uses acontinue
statement to “skip” the rest of the loop body for the current loop iteration, as described in The continue Statement.On lines 21 and 33, the program uses the increment statements
j++
andi++
: they are equivalent toj = j + 1
andi = i + 1
, respectively.On line 25 there is a
break
statement: if executed, that statement only breaks the immediately surroundingfor
loop (lines 21–27), and the execution continues from line 28.On lines 40–42 there is a special form of
for
loop that iterates over the values stored in an array: we will discuss it shortly.On line 41, we use
System.out.print(...)
to print something on the console without adding a “newline” at the end. To see the difference betweenSystem.out.print(...)
andSystem.out.println(...)
, try the following on the Java shell:System.out.print("Output 1 "); System.out.println("Output 2");
and compare its output with the output produced by:
System.out.println("Output 1 "); System.out.println("Output 2");
1class Lotto {
2 public static void main(String[] args) {
3 var scanner = new java.util.Scanner(System.in);
4 scanner.useLocale(java.util.Locale.ENGLISH);
5
6 System.out.print("How many Lotto numbers do you want to play? ");
7 var howMany = scanner.nextInt();
8
9 var numbers = new int[howMany]; // Array that will contain the numbers
10
11 for (var i = 0; i < numbers.length; ) {
12 System.out.print("Enter a number between 1 and 36: ");
13 var n = scanner.nextInt();
14
15 if ((n < 1) || (n > 36)) {
16 System.out.println("Number out of range!");
17 continue;
18 }
19
20 var isDuplicated = false; // Was the last number entered before?
21 for (var j = 0; j < i; j++) {
22 if (numbers[j] == n) {
23 System.out.println("You have already entered " + n);
24 isDuplicated = true;
25 break;
26 }
27 }
28
29 if (!isDuplicated) {
30 numbers[i] = n;
31 var left = numbers.length - (i + 1);
32 System.out.println("OK, " + left + " numbers left");
33 i++; // Move on to read the next Lotto number
34 }
35 }
36
37 scanner.close();
38
39 System.out.print("You entered the numbers: ");
40 for (var n: numbers) {
41 System.out.print(n + " "); // Print without a final newline
42 }
43 System.out.println(""); // Print a final newline
44 }
45}
Arrays in Java: the Basics#
In Java, arrays are objects and are created using new
, as follows:
(as usual, we experiment on the Java shell)
1jshell> var ints = new int[5]
2ints ==> int[5] { 0, 0, 0, 0, 0 }
3| created variable ints : int[]
In the example above, new int[5]
creates a new array containing 5 values of
type int
; then, the new array is used to declare a variable that we have
called ints
. After that, the Java shell tells us that:
on line 2: the variable
ints
gives us access to an array that contains 5 values of typeint
— and each one of these values is 0. This is represented by the Java shell as{ 0, 0, 0, 0, 0 }
;on line 3: the variable
ints
has typeint[]
, which is the type of an array containing values of typeint
.
In general, we can create arrays containing any number of values of the same
type, and we can also choose that type freely. For instance, we can create an
array of values of type double
:
jshell> var doubles = new double[2 + 3];
doubles ==> double[5] { 0.0, 0.0, 0.0, 0.0, 0.0 }
| created variable doubles : double[]
Notice that the number of values stored in the array can be any expression of
type int
, such as 2 + 3
above. Therefore, we can also write e.g.
new double[n]
, where n
is a variable whose value is not known while we write
the code (e.g. because the value of n
is read from the terminal when the
program runs).
(Arrays filled with default values)
In the examples above, we have created the arrays ints
and doubles
without
specifying which values they contain: consequently, Java has created the
arrays by using default values — and such default values depend on the
type of the array: for instance, an array of int
s is filled with the value 0,
while an array of double
s is filled with the value 0.0.
We can also create an array by specifying which values it contains:
1jshell> var speeds = new double[] {10.0, 18.2, 42.3}
2speeds ==> double[3] { 10.0, 18.2, 42.3 }
3| created variable speeds : double[]
Notice line 2 above: it says that the array in the variable speeds
contains
the three values we have specified when creating the array object (on line 1).
Note
If we create an array by explicitly providing the array contents (as we did when
defining the variable speeds
above), we cannot specify at the same time the
length of the array — i.e. writing new double[3] {10.0, 18.2, 42.3}
gives
an error. (Try it!)
After an array object has been created, we can see how many values it contains
by accessing its length
field, which contains a value of type int
: (we will
see what an “object field” is exactly later in the course)
jshell> System.out.println("The length of 'ints' is: " + ints.length)
The length of 'ints' is: 5
jshell> System.out.println("The length of 'speeds' is: " + speeds.length)
The length of 'speeds' is: 3
Important
The length of an array is fixed when the array is created, and cannot be changed afterwards.
To access a value stored in an array, we use the index of the value, i.e. the position of the value insude the array, counting from 0. To do that, we use the notation:
array_expr[int_expr]
where:
array_expr
is any expression that produces an array (e.g. a variable of type array, such asspeeds
above), andint_expr
is any expression of typeint
.
For example: (remember that the array in the variable speeds
is { 10.0, 18.2, 42.3 }
)
jshell> System.out.println("The value of speeds[0] is: " + speeds[0])
The value of speeds[0] is: 10.0
jshell> System.out.println("The value of speeds[1] is: " + speeds[1])
The value of speeds[1] is: 18.2
jshell> System.out.println("The value of speeds[2] is: " + speeds[2])
The value of speeds[2] is: 42.3
We can also change a value stored in an array, by performing an assignment that replaces the value with a specified index. For example, if we try:
jshell> speeds[1] = 1234.5
...
and we display again the contents of the array speeds
on the Java shell, we
will notice that its second value (i.e. the value with index 1) is now
1234.5 (while it was 18.2 before).
jshell> speeds
speeds ==> double[3] { 10.0, 1234.5, 42.3 }
| value of speeds : double[]
Important
If we try to access an array value in a position that is beyond the length of
the array, we get an error, as an exception. You can see it for yourself: try
to access e.g. speeds[3]
on the Java shell! (Remember that array indexes
are counted from 0, so speeds[3]
is trying to access the 4th element of the array.)
Looping over Array Contents: the For-Each Statement#
To loop over all the values stored in an array, we can use e.g. a for
loop, by
incrementing an index and making sure that it does not go beyond the last index
of the array. For example: (Try it on the Java shell!)
for (var i = 0; i < speeds.length; i++) {
System.out.println("The value of speeds[" + i + "] is: " + speeds[i]);
}
Important
Since the indexes of an array are counted from 0, the last value of an array
arr
is stored at position arr.length - 1
. For this reason, before running
the loop body, the for
loop above checks that the index i
is less than the
array length: when i
becomes equal to the array length, the loop condition
evaluates to false
(which mean that the index i
is beyond the last array
index), and the loop ends.
Looping over all values stored in an array is a very common programming pattern,
and it is quite easy to make mistakes when writing the code that increments and
checks the array index. For this reason, Java offers a specialised form of loop,
called for-each
statement (or enhanced for
loop), designed to
simplify loops over array elements, and avoid mistakes. The syntax is:
for (var x: array_expr) {
// Loop body, repeated for each value of the array produced by array_expr
}
// Statements executed after the loop ends
The for-each
loop is executed as follows:
first,
array_expr
is evaluated, and it must produce an array;then, for each value stored in the array produced by
array_expr
:the current array value is assigned to the variable
x
; andthe loop body is executed, and it can use the variable
x
to access the current array value;
finally, after the last array value has been used, the execution continues with the statements (if any) that follow the loop.
The for-each
loop uses the the array values in order, based on their index.
For example: (Try it on the Java shell!)
for (var s: speeds) {
System.out.println("The array 'speeds' contains the value: " + s);
}
The output of the for-each
loop above is:
The array 'speeds' contains the value: 10.0
The array 'speeds' contains the value: 1234.5
The array 'speeds' contains the value: 42.3
Important
The for-each
loop provides access to each value stored in an array by
copying the current value in the loop variable. Consequently, if you change
the loop variable, the change is not reflected in the array! For example,
consider: (using the array speeds
from the previous examples)
for (var s: speeds) {
System.out.println("The value of variable 's' is: " + s);
s = 42.0;
System.out.println("The value of variable 's' is now: " + s);
}
If you execute the loop above on the Java shell, you will see that the value of
the variable s
changes at each loop — and when the variable is assigned the
value 42.0
, the assignments only modifies s
, not the content of the array
speeds
. You can verify this fact by visualising the contents of speeds
before and after executing the loop above.
Using Arrays: Some Examples#
This section contains some common examples array usage.
Splitting a string into an array of strings (Example 35)
Static methods taking arrays as arguments (Example 36)
(Splitting a string into an array of strings)
We have already seen
some useful String methods,
but String
objects offer much more. For instance, the String
object method
split(separator)
computes and returns an array of String
objects; each
object stored in that array, in turn, is a sub-string of the original string,
obtained by splitting the original string using the given separator
.
For example, if you want to split a string around each space " "
, you
can try:
jshell> "This is a test".split(" ")
$1 ==> String[4] { "This", "is", "a", "test" }
| created scratch variable $1 : String[]
Or, if you want to split a string around each occurrence of ", "
(i.e. a comma
followed by a space):
jshell> "This is a sentence, and this is another sentence".split(", ")
$2 ==> String[2] { "This is a sentence", "and this is another sentence" }
| created scratch variable $2 : String[]
Note
The split(...)
method provided by String
objects is very flexible, because
the “separator” is actually a
regular expression
that can specify rather complex splitting patterns. You don’t need to learn
regular expressions in this course, but you will get an error if you try to
split a string using a separator that happens to be an invalid regular
expression: try e.g. "Hello".split("[")
on the Java shell.
(Arrays as method arguments)
In Java we can write static methods that take arrays as arguments. For example,
the following static method returns the sum of all values contained in its argument
values
— which has type int[]
, and thus, is an array of int
egers.
Observe that the program uses a for-each loop
to examine all array elements.
(Try copy&pasting this code snippet on the Java shell!)
static int sum(int[] values) {
var sum = 0; // Will contain the sum of all elements of 'values'
for (var v: values) {
sum = sum + v;
}
return sum;
}
You can try the static method above on the Java shell. For instance, you can
create an array of integers called arr
…
jshell> var arr = new int[] {1, 2, 3, 4}
arr ==> int[4] { 1, 2, 3, 4 }
| created variable arr : int[]
…and then call sum(arr)
to compute the sum of all its values.
jshell> System.out.println("The sum of the values in 'arr' is: " + sum(arr))
The sum of values in 'arr' is: 10
Concluding Remarks#
You should now have an understanding of how to define and use arrays to handle collections of a fixed number of values (each one having the same type). With this knowledge, you should be able to understand each line of the programs in Example 34.
References and Further Readings#
You are invited to read the following sections of the reference book: (Note: they sometimes mention Java features that we will address later in the course)
Section 8.1 - “Array Elements”
Section 8.2 - “Declaring and Using Arrays”
Exercises#
Note
These exercises are not part of the course assessment. They are provided to help you self-test your understanding.
(Some practice with arrays)
Try the following tasks:
Create an array containing values of type
int
, containing 5 numbers from 1 to 5.Create an array containing 5 values of type
int
, filled with the default value 0. Then, modify the values stored in the array, so that, after your modifications, the array contains the numbers from 1 to 5.Create an array containing 1000 values of type
double
, filled with the default value 0.0.Create an array containing 1000 values of type
double
, filled with the default value 0.0. Then, modify the values stored in the array, so that, after your modifications, the array contains the numbers from 1.0 to 1000.0 (NOTE: you might want to use a loop to perform this task…).
Lab and Weekly Assessments#
During the lab you can try the exercises above or begin your work on the weekly assessments below.
Important
For each assessment, you can download the corresponding handout and submit your solution on DTU Autolab: https://autolab.compute.dtu.dk/courses/02312-E24.
For details on how to use Autolab and the assessment handouts, and how to submit your solutions, please read these instructions.
If you have troubles, you can get help from the teacher and TAs.
01 - Count the Occurrences#
Your task is to edit the file Utils.java
provided in the handout. In the class
Utils
, implement the static method with the following signature:
static int count(int v, int[] values)
The static method must count how many times the value v
occurs in the array
values
, and return the result. Note that values
might have 0 elements.
The static method Utils.count(...)
is used in the test program contained in the
file Occurrences.java
, which is also included in the handout: you should read
Occurrences.java
and try to run it, but you must not modify it.
When you are done, submit the modified file Utils.java
on DTU Autolab.
Important
Besides testing your solution by running ./grade
, make sure you are also able
to manually compile this multi-file Java program (using javac
) and then run it
(using java
), as explained in Splitting Code into Separate Files.
Warning
The automatic grading on DTU Autolab includes some additional secret checks that test your submission with additional inputs. After you submit, double-check your grading result on DTU Autolab: if the secret checks fail, then your solution is not correct, and you should fix it and resubmit.
02 - Maximum 3#
This is a variation of the assessment 05 - Maximum 2. Your task
is to edit the file Utils.java
provided in the handout. In the class Utils
,
implement a static method that:
is named
max
;takes one argument: an array of values of type
double
;returns a value of type
double
.
The static method Utils.max(...)
must return the maximum among the values
contained in the array passed as argument. You can assume that the array passed
as argument has length 1 or greater.
The static method Utils.max(...)
is used in the test program contained in the
file Maximum.java
, which is also included in the handout: you should read
Maximum.java
and try to run it, but you must not modify it.
When you are done, submit the modified file Utils.java
on DTU Autolab.
Important
Besides testing your solution by running ./grade
, make sure you are also able
to manually compile this multi-file Java program (using javac
) and then run it
(using java
), as explained in Splitting Code into Separate Files.
Warning
The automatic grading on DTU Autolab includes some additional secret checks that test your submission with additional inputs. After you submit, double-check your grading result on DTU Autolab: if the secret checks fail, then your solution is not correct, and you should fix it and resubmit.
Hint
To see how to write a static method that takes an array as argument, see
Example 36. The signature of the static method
count(...)
in 01 - Count the Occurrences may also be helpful.
03 - Even Numbers#
Edit the file Evens.java
provided in the handout, and write a program that
reads from the console a whole line containing one or more integer numbers
separated by “,
” (i.e. a comma and a space), and prints how many of those
numbers are even.
For instance, if the line read from the console is:
1, 32, 4, 12, 5, 66
then the program must print:
4
When you are done, submit the modified file Evens.java
on DTU Autolab.
Hint
The file Evens.java
already contains some code that reads a line from the
console, and turns it into an array of integers (after splitting the line as
shown in Example 35).
04 - Statistics#
Edit the file Statistics.java
provided in the handout, and write a program
that reads from the console a whole line containing one or more numbers
separated by “;
” (i.e. a semicolon and a space), and prints their mean and
standard deviation. The numbers may contain decimal digits, and should be
handled as double
s.
For instance, if the line read from the console is:
1.0; 2; 3; 4.0
then the program must print:
Mean: 2.5
Standard deviation: 1.118033988749895
Remember that, if we have a set of \(n\) input values \(x_1, \ldots, x_n\), then their mean \(\bar{x}\) is computed as:
and their standard deviation \(\sigma\) (greek letter “sigma”) is computed as:
When you are done, submit the modified file Statistics.java
on DTU Autolab.
Hint
You can reuse and adapt some code from the file
Evens.java
provided with 03 - Even Numbers.To obtain a
double
from aString
, you can useDouble.parseDouble(...)
. For instance,Double.parseDouble("3.14")
produces the value 3.14 (of typedouble
).To compute the power and the square root in the standard deviation formula, you can use
Math.pow(...)
andMath.sqrt(...)
, respectively. For instance:jshell> Math.pow(3.0, 2) $1 ==> 9.0 | created scratch variable $1 : double
jshell> Math.sqrt(25.0) $2 ==> 5.0 | created scratch variable $2 : double