Session 5

Beginning to Write Our Own Programs

CS 2530
Intermediate Computing

Opening Exercise: Lucky Isn't Right

What is the output of this piece of code?

    int[] integers = new int[10];
    integers[0] = 4;
    integers[1] = 1;
    integers[2] = 6;
    int sum = 0;
    for (int i=0; i < integers.length; i++)
      sum = sum + integers[i];

    System.out.println( "Sum = " + sum );

Note: System.out.println() is a way to write to standard output.

Eleven. Correct! Now, how about this piece of code?

    int[] integers = new int[10];
    integers[0] = 4;
    integers[1] = 1;
    integers[2] = 6;
    int sum = 0;
    for (int i=0; i < integers.length; i++)
      sum = sum * integers[i];

    System.out.println( "Product = " + sum );

Zero. How can the code give the correct answer in the first case and the wrong answer in the second?

Because it wasn't correct in the first case. It was lucky. The loop processes items in all ten slots of the array, but the array contains only three items. The rest of the slots hold the default value for ints, 0. That is the identity for addition, so it works fine in the first case. But in the second it zeros out the product.

Some of you have encountered a form of this problem on Homework 1.

Note, though, that there is a piece of advice tucked into the assignment to help:

Keep in mind that a Java array does not know how many items it contains; it knows only how many items it can hold.

One lesson you can learn from this is: Read all of the assignment.

Another is that array processing in Java usually requires us to keep explicit track of how many items are currently stored in the array.

Working With null

We have not learned much about the Java value null yet. Last time, we encountered it when we looked at some of the Java features of methods. In that situation, we saw a method that returned null if it did not have an object to return, but was obligated to do so. The find() must return the String value associated with a given key, but sometimes the database does not contain the key. So it returns null.

At the time, we said only two things about null:

If null is not an object, then we cannot send it messages. That's the source of a problem that several of you have had with the homework. Take a look at this code:

    MemoAssociation[] memos = new MemoAssociation[10];
    memos[0] = new MemoAssociation( "Eugene", "CS 2530");
    memos[1] = new MemoAssociation( "Mike",   "CS 1130");
    memos[2] = new MemoAssociation( "Sam",    "CS 1000");
    for (int i=0; i < memos.length; i++)
      System.out.println( "Has key = 'Eugene'?   " +'
                          memos[i].hasKey("Eugene") );

What is the output?

For the three items in the array, all is good.

    Has key = 'Eugene'?   true
    Has key = 'Eugene'?   false
    Has key = 'Eugene'?   false

When i becomes 3, though, we have a problem:

              at ArrayExample.example03(

Here is the offending code, on Line 43:

    System.out.println( "Has key = 'Eugene'?   " + memos[i].hasKey("Eugene") );

A NullPointerException indicates that we tried to do something with a variable whose value is null. Almost always, it indicates that we have tried to send a message to an object that does not exist.

Where did the null come from in my array example? null is default value for objects, just as 0 is default value for integers. So, the ten slots of the memos array all start as null, and then our code stores three MemoAssociations in the first three slots. The other seven nulls remain.

(Your reading assignment did not make that obvious. I should have told you about this sooner. Sorry.)

How do we fix the problem in all these examples? Keep track of how many items are actually in the array, and use that counter to control our for loop. [More in class.]

Learning to Debug Java Programs

NullPointerExceptions are a common sight for Java programmers, even experienced ones. Be prepared! Fortunately, as we become more experienced Java programmers, we see fewer of them. And we can develop skills for rooting them out quickly when we do encounter them.

The Java compiler and our editors give us a lot of information for debugging code. In the case of a run-time error like the one we saw earlier, the output gave us a lot of information:

    Has key = 'Eugene'?   true
    Has key = 'Eugene'?   false
    Has key = 'Eugene'?   false
              at ArrayExample.example03(


Dr. Java's Interactions window shows us the primary cause of the error. The java program itself gives a stack trace that shows the full hitsory of messages and method calls leading to the error. If we run a program with a main() method, Dr. Java shows us the full stack trace, too:

              at ArrayExample.example03(
              at ArrayExampleDriver.main(
              at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
              at sun.reflect.NativeMethodAccessorImpl.invoke(...
              at sun.reflect.DelegatingMethodAccessorImpl.invoke(...
              at java.lang.reflect.Method.invoke(
              at edu.rice.cs.drjava.model.compiler.JavacCompiler.runCommand...

Notice that running one of our programs may require execution of a lot of code we did not write or execute explicitly. Once you get down to the last line referring to your own code, you can stop reading. Focus your debugging effort on code you wrote. As tempting as it might be to think so, the bug is almost certainly in your code, not the Java library!

(It may be in your professor's code, so be prepared to ask. But you should put some real time into finding the bug in your code first.)

Over the course of the semester, we will learn a few tricks for debugging our code. I'll tabulate a few and put them on the Course Resources page, If you pick up any tricks you'd like to share, send them to me or the course mailing list. I'll post the most useful ones on the resource page, too.

Exercise: Hash House

For reasons we will learn later, it is often necessary for Java objects to respond to the hashCode() message by returning an integer value for the object. (Yes, this is related to the idea of a hash function that we discussed briefly last time.)

Write a hashCode() method for the MemoAssociation class.
In response to a hashCode() message, a MemoAssociation returns the sum of the characters in its key

Huh? Here are some helpful bits of Java:


This is a standard "process all items" loop, which you have surely written many times in your intro sequence. You'll notice that the Java for loops follow the common patterns you learned in another language. The shape of the Java code differs only because the syntax of Java differs from the syntax of Python or Ada.

Notice that I did not implement my solution as:

   private int sum;
   private int characterValue;
   public int hashCode()
      sum = 0;
      for (int i = 0; i < key.length(); i++)
        characterValue = (int) key.charAt( i );
        sum = sum + characterValue;
      return sum;

Remember that an instance variable is part of the identity of an object. Instance vars hold values that the object needs to know over time. They are the object’s long-term memory.

Any value needed only for a short-term calculation, in response to a particular message, can and should be implemented using a temporary variable in the method.

How will we know if your method -- or mine! -- is correct?

Design Issue for Homework 1

  - issues: empty slots in partly-filled array
            is array full?

  - search in partly-filled array

  - if array is full:
    - fail on insert
    - grow: make new, copy all, add new

  - if remove:
    - leave null in slot
      - requires null check on searches
      - requires search to end
    - fill slot
      - move one from end
      - move range from end     ... required if in order

  * design decisions ... 
    - you have choices.
      keep things simple until you feel comfortable.
    - you must satisfy the spec (implement the interface)

Wrap Up

Eugene Wallingford ..... ..... September 4, 2012