Science with the Virtual Observatory |
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/src/basicjava directory, so to set-up, we change
into that directory.
on Linux/MacOS:
cd $NVOSS_HOME/java/src/basicjava |
on Windows:
cd %NVOSS_HOME%\java\src\basicjava |
|
ant distclean. Find and compile the source code file, HelloWorld.java:
javac HelloWorld.java
You will now notice that you have a class called
Hello.class in the current directory.
Run your compiled code:
java HelloWorldTechnically speaking, the
java command will:
main() method. Warning: This exercise will generate errors on purpose.
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!
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.)
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 |
|
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 $CLASSPATHor 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/src/basicjava
on Linux/MacOS, sh:
CLASSPATH=${CLASSPATH}:$NVOSS_HOME/java/src/basicjava
on Windows:
set CLASSPATH=%CLASSPATH%;%NVOSS_HOME%\java\src\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.
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.
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.
If you want to save on some typing, download
FrenchHello.java and save it in
our nvoss/basicjava directory.
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 {
}
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").
Override the getGreeting(String toWho) method.
Cut-and-paste this method from Hello.java and
modify its implementation.
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?
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.
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:
javac) or at
run-time (when you ran java)?
Be sure to fix the resulting error before going onto the next step.
And don't forget to use the -g option with
javac.
Comment-out the line that creates our Hello
object, greeter, in main():
// Hello greeter = new Hello();
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.
Remove the initialization of the private member who:
private String who;
How and why was the outcome of the error
different from step 2?
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++) {
^
Comment out the import statement with the wildcard.
// import java.io.*;
Comment out the throws statement modifying the
sayHello(Writer) method.
public void sayHello(Writer out)
// throws IOException
{
Assignment: Create a new application
that will write Hello's greeting to a file.
Tips:
You don't need to create a sub-class of Hello to
accomplish this one as we did in Exercise 3. You can use
Hello's existing interface from a
main() method.
The FileWriter class from the java.io
package is used to write to files. Consult the
Java
Package API documentation to get details.
For extra credit, you might want to put in some code to check
file existence and/or permission to write. The
File class, also from the java.io
package, handles this.
Remember, this exercise is supposed to be about exceptions, so if you are not handling them, then you're probably doing something wrong.
Stumped? You can peek at HelloToFile.java in the
solutions directory, or you can look
here for a full explanation.
The NVO Summer School is made possible through the support of the National Science Foundation and the National Aeronautics and Space Administration.
![]() |