Structure of a java program
Java is a more object oriented language than C++. All code is in a class. There is no free-standing main as there is in C++.
Typically, each class is defined in a separate file. The file name must be the same as the name of the class defined in it, with a .java suffix.
This file is called HelloWorld.java
public class HelloWorld
{
public static void main(String args[])
{
System.out.println("Hello World!");
}
}
It defines a class called HelloWorld (Note that java is case
sensitive). This class has only one member function, The line System.out.println("Hello World!"); displays Hello World! on the terminal. The keyword System defines the user's system. This is a class and it has a member out, which maps to standard output. out has a method called println which displays some material and appends a newline.
Everything else should be self-explanatory.
The java compiler is javac. Here is how you
compile this
javac HelloWorld.java
If the compile is successful, nothing is displayed, but when you
get the prompt back, a new file will have been created called
HelloWorld.class
This is written in Java Byte Code.
Java programs are not directly executed.
To execute a class, you have to invoke the Java Virtual Machine (JVM)
with the java command.
java HelloWorld
The Java Development Kit 1.5.0 (JDK) which includes the compiler and the run time environment is available on the CS department systems. You may need to add /usr/java/bin to your path.
Exercise 1: To make sure that everything is working properly, compile and run this. It might be a good learning exercise to type this in yourself using your favorite text editor, but if you are lazy, You can download the source file here
The basic operators and expressions of java are essentially identical to C++; Statements must end in semi-colons, curly braces denote blocks, the syntax of for statements, while statements etc is identical; java supports exactly the same arithmetic and conditional operators as C++, arrays use square brackets, functions (actually methods) are defined and called using the same syntax as C++, and so on.
These are the primitive data types.
boolean (values are true or false)
byte (8 bits)
char (16 bits)
double (64 bits)
float (32 bits)
int (32 bits)
long (64 bits)
short (16 bits)
The only new thing here is the distinction between a char and a byte. C and C++ use the ASCII character set in which a char is 8 bits. Java's native character set is unicode using UTF-16 encoding, in which a character is represented by 16 bits. Thus a char is different from a byte.
Java has a huge set of predefined classes (the latest version 5.0 (aka 1.5) has more than 3000 classes), and most production level java programs make heavy use of these. For example, there is a String class. This has eleven constructors and too many member functions to count. Here is the on-line help page for the String class
If you are new to Java, take a moment to study the on-line help page for this class. This will give you a flavor of the richness of Java predefined classes.
Java classes are pointers, and this means that you need to allocate memory for them. This is done with the new operator, and the syntax is the same as in C++. In general, you do not need to free up memory because java has a separate thread that does garbage collection. Arrays also have to be allocated.
Here is an example. It includes two source files, both in the
same directory. Student.java defines a class Student
This class has a constructor, which takes a String as an
argument, and has several get and set functions. The file
Classlist.java creates an array of Students, fills in values
for two of them, and then displays some output.
Student.java
public class Student
{
String name;
double gpa;
Student(String n) {
name = n;
}
void setGpa(double g)
{
gpa=g;
}
double getGpa()
{
return gpa;
}
String getName()
{
return name;
}
}
Classlist.java
public class Classlist
{
public static void main(String args[])
{
Student classlist[] = new Student[10];
classlist[0]=new Student(new String("Suzy"));
classlist[0].setGpa(3.71);
classlist[1]=new Student(new String("Bozo"));
classlist[1].setGpa(2.04);
int i;
for(i=0;i<2;i++) {
System.out.println("Student " + classlist[i].getName() +
" has a gpa of " + classlist[i].getGpa());
}
}
}
Note that when you compile Classlist.java, the other file Student.java is automatically compiled as well if necessary.
Packages
Java classes are included in directories, which are called
packages. Many common classes, such as String are
in the package java.lang which is automatically
included when your class is compiled. Other classes need to
be explicitly included with the import statement.
For example, there is a random number generator class called
Random which is included in the java.util package. If your
program is going to access this, you must include this statement
at the top of your file
import java.util.Random;
If your program uses a number of classes in the same package, you
can use the asterisk as a wildcard to include them all.
import java.util.*;
You can create your own packages. In the example above, the two classes Student and Classlist were both in the current directory. To put the class Student in a package called MyPackage, do the following:
Exception Handling
An exception is an error condition. Many class constructors and methods may throw an exception. Examples include trying to open a file for reading which does not exist, or overwriting array bounds. It is important that your program catch the exception; otherwise the process terminates. Here is the skeleton for this:
try
{
// stuff that could cause exceptions
}
catch (exception1)
{
// what to do if exception1 occurs
}
catch (exception2)
{
// what to do if exception2 occurs
}
finally
{
// things to do even if exceptions occur
}
There are two kinds of exceptions, checked and unchecked. The compiler
forces you to handle the former. You must tell the compiler what you
will do if it occurs. The latter should be checked, but is not
enforced. Checked errors are those that could occur no matter how
careful programmer is. (Trying to open a file which is not there)
while the latter are generally the programmer's fault (ArrayBounds
exception).
Java defines a base class Exception and numerous derived exception types. You can define your own Exception classes as well.
What to do if an exception occurs depends on your program; but often you want to display your own error message along with a standard error message explaining what happened. If you print an Exception, it will display an error message which is sometimes helpful.
For example, suppose you want to pass an integer as an argument to a program. Arguments to main are always passed in as character Strings. There is a function Integer.parseInt which takes a string of digits as an argument and returns the integer value of the string (like the atoi() function in C). The documentation for this method indicates that it throws a NumberFormatException if the string cannot be parsed into an integer.
Here is some code to demonstrate how you would catch such an exception.
int n;
try {
n = Integer.parseInt(args[0]);
}
catch (NumberFormatException e) {
System.err.println("Bad Argument" + e);
n = 0;
}
....
If the argument to the program is valid, the catch block would be skipped during execution. If it is an invalid string, the catch block would be executed.
Files and Streams
The package java.io has a rich set of classes for input and output. In order to read or write, a program has to attach a stream to a file, socket or other I/O device..
There are two abstract classes for characters (e.g. reading from or writing to a text file) Reader and Writer. The Reader class has a method int read(char[] cbuf) which read characters into a character array, exactly like the read system call in Unix. Note that it cannot overwrite the array bounds. If the size of the character array cbuf is 100, (you can get this value with the cbuf.length method) read will not read more than 100 bytes. However, it could read fewer than 100 bytes; the return value is the number of bytes actually read. There are other forms of the read function as well. The read method will return -1 when it reaches the end of the file.
The Writer class has several write member functions, including void write(char cbuf[]) which writes cbuf.length characters, and void write(char cbuf, int offset, int len) which writes len characters from cbuf starting at offset.
These are abstract classes, and are not used directly; a Java program will use a class derived from these. Examples include FileWriter (derived from the class OutputStreamWriter which is in turn derived from the class Writer) which is used to write to text files. This has a constructor FileWriter(String filename) which can be used to open a file for writing, creating it if necessary.
Reading and Writing are generally buffered, and there is a derived class BufferedWriter. One of its constructors takes a FileWriter as an argument.
There are corresponding classes FileReader and BufferedReader
Exercise 2: Write a java program TextFileCopy.java, which takes two file names as arguments. The first should be an already existing text file. Your program should create a BufferedReader from a FileReader created from the file whose name is the first argument to the program. It should also create a BufferedWriter from a FileWriter, the name of which is the second argument. It should then copy the contents of the first file into the second. When you are done, close the BufferedReader and the BufferedWriter with the close function. Note that the constructor for FileReader and FileWriter will throw an IOException which you will have to catch.
There are two abstract base classes for reading bytes (typically binary data) InputStream and OutputStream. These also have read and write functions similar to those of Reader and Writer except that they act on arrays of bytes, not chars.
These also have numerous derived classes
FileInputStream (for byte based input from a file)
FileOutputStream (for byte based output to a file)
BufferedInputStream
BufferedOutputStream
A third category of I/O stream is the PrintStream. A representative method here is void println( ... ). This function takes primitive data types or some classes (such as Strings) as arguments, concatenated together with the + operator. Each is converted to a string of characters and printed. System.out and System.err are instances of PrintStreams (corresponding the standard output and standard error).
What C programmers call standard input is System.in in Java.
This is an instance of an InputStream. If you want to read specific
data types, you have to convert this to a
Scanner (to use this you have to import the package
java.util). Here is the constructor
Scanner input =
new Scanner(System.in);
A Scanner is more or less equivalent
to the scanf() function in C or cin in C++. It has
a huge number of functions to allow a program to read an individual
data type, and it automatically performs the conversion from a char
string to the type.. For example, the following statement reads an
integer into n.
n = input.nextInt();
This is equivalent
to the C statement scanf("%d",&n) or the C++ statement
cin << n;. You will have to look at the online manual for a
complete list of these methods.
The scanner class was introduced in java version 5.0.
Here is
the Sun Microsystems Java Tutorial