Java: a Survival Guide -- Exercises

The exercises presented here are companions to the presentation Java: a Survival Guide (PDF, PPT). During this session, we'll be refering to the Java API documentation.

We'll be working all our exercises in the java/dev/basicjava directory, so to set-up, we change into that directory.
on Linux/MacOS:
cd $NVOSS_HOME/java/dev/basicjava
   on Windows:
cd %NVOSS_HOME%\java\dev\basicjava

Exercise 0: Compiling and Running a Simple Java Program

  1. If you ran ant previously, return our directory to its pristine state by typing ant distclean.
  2. Download and save to the current directory HelloWorld.java.

  3. Compile the source code:

    javac HelloWorld.java

    You will now notice that you have a class called Hello.class in the current directory.

  4. Run your compiled code:

    java HelloWorld
    Technically speaking, the java command will:
    1. Start the Java Virtual Machine (JVM)
    2. Load the class file into the JVM
    3. Find and execute the main() method.

Exercise 1: Understanding Packages and the CLASSPATH

Warning: This exercise will generate errors on purpose.

  1. In the same directory, compile our slightly more complex Hello-world program, Hello.java:

    javac -g Hello.java

    Here's a tip: When I compile code by hand (instead of using Ant), I always include the -g flag. This enables debugging mechanisms; in particular, when an exception is thrown, the line number of the source code where the error occurred will be printed. Very helpful!

  2. Now run the application:

    java Hello

    Oops! Did you see this as your output?

    Exception in thread "main" java.lang.NoClassDefFoundError: Hello (wrong name: nvoss/basicjava/Hello)
            at java.lang.ClassLoader.defineClass0(Native Method)
            at java.lang.ClassLoader.defineClass(ClassLoader.java:537)
            ...

    What went wrong? (See slide 18.)

  3. Create a source directory tree for our source code and copy our code into it:

    on Linux/MacOS:
    mkdir -p nvoss/basicjava
    cp Hello.java nvoss/basicjava
    cd nvoss/basicjava 
       on Windows:
    mkdir nvoss\basicjava
    copy Hello.java nvoss\basicjava
    cd nvoss\basicjava 
  4. Now recompile and execute:

    javac -g Hello.java
    java nvoss.basicjava.Hello

    Now what?

    NoClassDefFoundError usually means something is wrong with our CLASSPATH, so let's have a look at it:

    on Linux/MacOS:
    echo $CLASSPATH
    or
    echo $CLASSPATH | sed -e 's/:/\n/g'
       on Windows:
    echo %CLASSPATH% 

    We could fix this problem this problem by adding the full path to our basicjava directory to our classpath...

    on Linux/MacOS, csh:
    setenv CLASSPATH ${CLASSPATH}:$NVOSS_HOME/java/dev/basicjava
    on Linux/MacOS, sh:
    CLASSPATH=${CLASSPATH}:$NVOSS_HOME/java/dev/basicjava
    on Windows:
    set CLASSPATH=%CLASSPATH%;%NVOSS_HOME%\java\dev\basicjava

    However, there is a simpler solution in our case. We see that "." (the current working directory) is one of the directories in the CLASSPATH. Thus, we need only change back into the basicjava directory to execute the application.

    on Linux/MacOS:
    cd ../..
    java nvoss.basicjava.Hello
       on Windows:
    cd ..\..
    java nvoss.basicjava.Hello

    Aaahhh. That's more like it.

Exercise 2: Simple Creation and Manipulation of Objects

One this one, you get to fly solo.

Assignment: Edit Hello.java to say hello to each word given on the command line.

The resulting behavior should look like this:

> java nvoss.basicjava.Hello George Tony Junichiro
Hello George!
Hello Tony!
Hello Junichiro!

Need a co-pilot? Have a look at Hello2.java in the solutions directory.

Exercise 3: Extending a Class

Assignment: Extend the Hello class to print a different salutation.

For example, we can create a class called FrenchHello with the following behavior:

> java nvoss.basicjava.FrenchHello
Allo le monde!

I'll get you started.

  1. If you want to save on some typing, download FrenchHello.java and save it in our nvoss/basicjava directory.

  2. Edit FrenchHello.java to begin the definition of your new class. Start by declaring the class's package to be nvoss.basicjava, and then add the class definition line so that it extends Hello. (This is already done in FrenchHello.java.)

    Our sample looks something like this:

    package nvoss.basicjava;
    
    public class FrenchHello extends Hello {
    
    }       
    
  3. Add constructors.

    We probably want the same interfaces as our parent class, Hello--that is, one constructor where the user can provide the addressee's name and one in which the user provides nothing and a default is used.

    Stubs for these constructors appear in our skeleton:

        public FrenchHello(String toWho) {
    
        }
    
        public FrenchHello() { 
    
        }
    

    Now lets fill them in. In the first constructor, we need to pass the user's input string. To do this, we simply call the "super" constructor with super(toWho). We could do something similar for the second constructor by inserting super() (to call Hello's "no-arg" constructor); however, it would be good to override the Hello's default addressee ("world") with something more...french. We can do this by calling the first constructor inside the second by inserting this("le monde").

  4. Override the getGreeting(String toWho) method.

    Cut-and-paste this method from Hello.java and modify its implementation.

  5. Override the main() method to use our extended class.

    Given that static methods are inherited along with other methods, why do we need to override main() in this case?

  6. Compile and run the new class.

Extra Credit: Use the Hello class print the English translation immediately after the modified greeting(s). Before you start doing a lot of cut-and-pasting, is there a simple way to accomplish this?

Need some more help? You can peek at the FrenchHello.java file in the solutions directory.

Exercise 4: Common errors and exceptions

In this exercise, we'll intentionally break Hello.java in several ways to see what kinds of errors occur. After completing each modification described below, compile and run the modified app, then write down answers for the following questions:

  1. Was the problem detected at compile-time (when you ran javac) or at run-time (when you ran java)?
  2. Was an exception thrown? What the name of the exception?
  3. What line number did the error occur at?

Be sure to fix the resulting error before going onto the next step. And don't forget to use the -g option with javac.

  1. Comment-out the line that creates our Hello object, greeter, in main():

            // Hello greeter = new Hello();
    
  2. Now explicitly set greeter to null:

           Hello greeter = null; // = new Hello();
    

    Note: sometimes variables can get set to null in non-obvious ways at run-time; this step illustrates what can happen in such a case.

  3. Remove the initialization of the private member who:

        private String who;
    
    How and why was the outcome of the error different from step 2?
  4. Make main() over-run the bounds of the argument array when it is passed a list of names. This step assumes that you have completed Exercise 2.

                for(i=0; i <= args.length; i++) {
                            ^
    
  5. Comment out the import statement with the wildcard.

    // import java.io.*;
    
  6. Comment out the throws statement modifying the sayHello(Writer) method.

        public void sayHello(Writer out) 
             // throws IOException
        {
    

Exercise 5: Handling Exceptions

Assignment: Create a new application that will write Hello's greeting to a file.

Tips:

Stumped? You can peek at HelloToFile.java in the solutions directory, or you can look here for a full explanation.