Section 3.4 List
Next, letβs look at a program which reads numbers from a file and produces a histogram showing the frequency of the numbers. The data file we will use has one number between 0 and 9 on each line of the file. Here is a simple Python program that creates and prints a histogram.
Test running the program. It will read this data:
Lets review what is happening in this little program. First, we create a list and initialize the first 10 positions in the list to be 0. Next we open the data file called βtest.datβ. Third, we have a loop that reads each line of the file. As we read each line we convert it to an integer and increment the counter at the position in the list indicated by the number on the line we just read. Finally we iterate over each element in the list, printing out both the position in the list and the total value stored in that position.
To write the Java version of this program we will have to introduce several new Java concepts. First, you will see the Java equivalent of a list, called an
ArrayList. Next, you will see three different kinds of loops used in Java. Two of the loops we will use are going to be very familiar, the third one is different from what you are used to in Python but is easy when you understand the syntax:
-
while (condition) { code }
-
The
code will be repeatedly executed until the
condition becomes false.
-
for (initialization statement; condition; loop statement) { code }
-
The
code will be repeatedly executed until the
condition becomes false. As shown in the example below, the
initialization statement and
loop statement make this form useful for iterating over a range of numbers, similar to how you might use
for i in range(10) in Python.
-
for (Type variable : collection) { code }
-
The
code will be executed once for each element in the
collection. Each execution,
variable will be assigned to the next element of
collection. Known as the βfor-eachβ loop. This form is useful for iterating over members of a collection, similar to how you might use
for a in array in Python.
Here is the Java code needed to write the exact same program:
Before going any further, I suggest you try to compile the above program and run it on some test data that you create.
Now, letβs look at what is happening in the Java source. As usual, we declare the variables we are going to use at the beginning of the method. In this example we are declaring a
Scanner variable called
data, an integer called
idx and an
ArrayList called
count. However, there is a new twist to the
ArrayList declaration. Unlike Python where lists can contain just about anything, in Java we let the compiler know what kind of objects our array list is going to contain. In this case the
ArrayList will contain
Integers. The syntax we use to declare what kind of object the list will contain is the
<Type> syntax.
Technically, you donβt
have to declare what is going to be in an array list. The compiler will allow you to leave the
<``*Type*>`` off the declaration. If you donβt tell Java what kind of object is going to be on the list Java will give you a warning message like this:
Note: Histo.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
Without the
<Integer> part of the declaration Java simply assumes that
any object can be on the list. However, without resorting to an ugly notation called casting, you cannot do anything with the objects on a list like this! So, if you forget you will surely see more errors later in your code. (Try it and see what you get)
Lines 13β20 are required to open the file. Why so many lines to open a file in Java? The additional code mainly comes from the fact that Java forces you to reckon with the possibility that the file you want to open is not going to be there. If you attempt to open a file that is not there you will get an error. A try/catch construct allows us to try things that are risky, and gracefully recover from an error if one occurs. The following example shows the general structure of a try/catch block.
try {
Put some risky code in here, like opening a file
} catch (Exception e) {
If an error happens in the try block an exception is thrown. We will catch that exception here!
}
Notice that in line 16 we are catching an
IOException. In fact, we will see later that we can have multiple catch blocks to catch different types of exceptions. If we want to be lazy and catch any old exception we can catch an
Exception which is the parent of all exceptions. However, catching
Exception is a terrible practice, since you may inadvertently catch exceptions you do not intend to, making it harder to identify bugs in your program.
On line 22 we create our
ArrayList and give it an initial size of 10. Strictly speaking, it is not necessary to give the
ArrayList any size. It will grow or shrink dynamically as needed, just like a list in Python. On line 23 we start the first of three loops. The for loop on lines 23β25 serves the same purpose as the Python statement
count = [0]*10, that is it initializes the first 10 positions in the
ArrayList to hold the value 0.
The syntax of this for loop probably looks very strange to you, but in fact it is not too different from what happens in Python using range. In fact
for (Integer i = 0; i < 10; i++) is exactly equivalent to the Python
for i in range(10) The first statement inside the parenthesis declares and initializes a loop variable
i. The second statement is a Boolean expression that is our exit condition. In other words we will keep looping as long as this expression evaluates to true. The third clause is used to increment the value of the loop variable at the end of iteration through the loop. In fact
i++ is Java shorthand for
i = i + 1 Java also supports the shorthand
i-- to decrement the value of i. Like Python, you can also write
i += 2 as shorthand for
i = i + 2 Try to rewrite the following Python for loops as Java for loops:
-
-
-
-
for x,y in zip(range(10),range(0,20,2)) [hint, you can separate statements in the same clause with a ,]
The next loop (lines 27β30) shows a typical Java pattern for reading data from a file. Java while loops and Python while loops are identical in their logic. In this case, we will continue to process the body of the loop as long as
data.hasNextInt() returns true.
Line 29 illustrates another important difference between Python and Java. Notice that in Java we can not write
count[idx] = count[idx] + 1. This is because in Java there is no overloading of operators. Everything except the most basic math and logical operations is done using methods. So, to set the value of an
ArrayList element we use the
set method. The first parameter of
set indicates the index or position in the
ArrayList we are going to change. The next parameter is the value we want to set. Notice that, once again, we cannot use the indexing square bracket operator to retrieve a value from the list, but we must use the
get method.
The last loop in this example is similar to the Python for loop where the object of the loop is a Sequence. In Java we can use this kind of for loop over all kinds of sequences, which are called Collection classes in Java. The for loop on line 33
for(Integer i : count) is equivalent to the Python loop
for i in count: This loop iterates over all of the elements in the ArrayList called count. Each time through the loop the Integer variable
i is bound to the next element of the
ArrayList. If you tried the experiment of removing the
<Integer> part of the
ArrayList declaration you probably noticed that you had an error on this line. Why?
You have attempted
of
activities on this page.