You are on page 1of 118

Chapter 10.

Applications, File Handling and


Exceptions

Context

The purpose of this unit is to explain how Java can be used to create stand-alone
applications suitable for non-trivial, real world tasks. Most real-world applications
manipulate files on the users’ computers, so this unit introduces the subject of how Java
works with files. Relating to files, and in fact almost all non-trivial programs, is the concept
of Java exceptions — the handling of special cases and errors.

Objectives

Having successfully completed this unit you should be able to:

 Explain the difference between applets and applications


 Convert Java applets into applications, and vice versa
 Implement Java programs illustrating the use of files
 Understand and implement Java exception handing techniques

Study Planning

You should expect to spend approximately 9 hours studying this unit. You may find it
convenient to break up your study as follows:

Disk-based Content: 2¼
hours
Application: 3 hours
Set textbook Content: 1 hour
Reflection (On-line discussions, 1 hour
review
questions):
Tutorial Work: 1 hour
Related Coursework: ¼ hour
Extension Work: ½ hour
Equipment/software required

 Sun Java 2 Platform (also known as Java Development Kit 1.3)


 TextPad 4.5
 A Web browser

Reading material & resourses

Core texts (supplied with module material):

1. Java: how to program. H. M. Deitel and P. J. Deitel, 3rd edition,


Prentice-Hall, ISBN: 0-13-012507-5

Online Resources:

1. Frequently-asked questions
2. Additional Source Code Examples
Introduction to Unit 10

This unit presents three related features of Java.

Firstly, the relatively straightforward way that an applet can be converted into an
application is investigated. The reason for doing this is usually when there is a desire to
write a program that uses Java features that are restricted for applets, such as file
handling.

Files and file handling is investigated, mainly concentrating on the most commonly
encountered type of files — text files.

A feature of all robust and well written programs is that they cope appropriately with
incorrect user responses, and situations such as missing files. The last section of this unit
investigates the mechanisms of writing programs that both respond to system generated
exceptions, and also user-defined and generated exceptions.

If you go on from this module and programme in situations where you are developing
large-scale programs, you will be likely to have to write programs that involve all three of
the Java features presented in this unit.

Limitations of applets

 Browsers have varying degrees of Java support


 Stringent security limitations (no file or hardware access)

Although the use of applets has the notional advantage of simplicity for the end user, in
practice this advantage is often not realised because Web browser technology cannot
keep pace with developments in the Java language. In practice it is often the case that
Web browsers lag behind the development of Java by one or two major revisions (for
example, Java version 1.3 is widely available but some Web browsers support only
version 1.1 or Java 1.2).

However, the main problem with distributing software as applets is that the applet is
allowed hardly any interaction with the user’s computer. For example, an applet can
donone of the following :

 read, write, create or delete files on the computer


 open network connections (with a few exceptions)
 start or stop other programs
 interact with other programs
This means that for traditional, stand-alone applications (like a word processor) an applet
would be completely unsatisfactory. What use would a word processor be that could not
save or open documents?

Please note that it has not been said that an applet cannot read or write files — rather,
an applet cannot read or write files on the computer that is running the applet unless it is
the same computer the applet originates from.

Advantages of applets

Applets are easy to distribute to any platform (via the use of Web browsers). The
programmer does not have to maintain the program’s interaction with the GUI to the same
extent as with applications — the browser handles many of the events such as window
closing etc.

Despite the limitations of applets, applet programming is quite popular because it makes
software very easy to distribute using a Web browser. The end user does not have to set
anything up: merely viewing a Web page is sufficient (in principle).

Moreover, the Web browser provides an environment in which the applet can run. The
programmer does not have to worry about how the user starts and stops it, or changes
the size of its screen area.

For some distributed programming applications (for example where the data the user
works on is not held on his or her own computer, but at a remote site) applet programming
can be very effective. For example, a number of banks are providing on-line access for
their customers based on Java applets. Since all the user’s data is held by the bank’s
central computers, there is no need for data to be read or written from the user’s own
computer. So this particular limitation of applets does not present a problem.

So when writing a Java program for distribution, the developers must make a decision to
support an applet or a stand-alone application. The creation of stand-alone applications
presents no particular problem for the Java programmer, as we shall see.

What a GUI application must do

If it has a graphical user interface (GUI) — and most programs do — an application must
do at least these three things that an applet will not usually be concerned with:

 provide a start point for the program


 create and manage the program’s main window
 shut down the program on request from the user
Of course the purpose of developing an application is to be able to do things that an applet
cannot, so the application may have to do other things that applets cannot. This section
is about dealing with the things that an application must do, regardless of its function, if
is to support graphical interaction.

Providing a start point

A Java application starts at the method called ‘ main() ’ in the primary class (often
called the ‘main’ class).

When method main() has finished, the program does not necessarily finish (there may be
‘threads’ running). An application should call System.exit() to finish.

The method main() is formally defined as follows:

public static void main(String args[])

// create the main window here

The Java compiler will be quite fussy that the method is defined exactly like this. If you
are creating a program with a graphical user interface the data passed in the
argument args[] will not usually be of interest. This argument will contain the data
specified by the user when running the program from a command prompt. As a GUI
program will normally be run by clicking on something, there will not be a command line
and args[] will be empty.

The method main() is often defined in a class that does nothing else but provide this
method. Conventionally this class has the same name as the program itself. For example:

class MyWindowApp

public static void main(String args[])

// create the main window here

} // class
Creating the main window

The application must create a main window within which all its output will be confined. It
is usual to set the initial size of the window, but the user may change it. Normally the main
window will be an object of a subclass of Frame.

Why not just create a Frame object?

The program can create a main window simply by creating an object of type Frame . For
example, the following two line will make a window appear:

MainWindow mainWindow = new Frame("My program’s title");

mainWindow.setVisible (true);

The problem with this is that the built in Frame class cannot do anything specific. It
provides a lot of standard functionality, but it won’t do anything useful for a given
application. We create a subclass of Frame to do those things that are specific to this
application. In particular, objects of class Frame will not stop the program when the user
clicks on the ‘close’ button in the corner of the window, which is the usual convention.

So we would normally define a main window as follows:

class MainWindow extends Frame

// MainWindow methods go here

public MainWindow() // constructor

super("My program’s title");

setSize (300, 300);

With this definition inside our main() method for the application we would create the main
window by executing:

MainWindow mainWindow = new MainWindow();

mainWindow.setVisible (true);

Although the class MainWindow does not yet have any functional methods, it must have
a constructor. The constructor in this case simply calls the constructor for Frame, passing
the name of the program as the argument. This name will appear in the caption bar of the
window. It also sets the initial size of the window using setSize() .

Example of creating the main window with subclass of Frame

A simple application using the approach would require 2 source files, MainWindow.java:

import java.awt.*;

class MainWindow extends Frame

// MainWindow methods go here

public MainWindow() // constructor

super("My program’s title");

setSize (300, 300);

} // class

and MyWindowApp.java

class MyWindowApp

public static void main(String args[])

MainWindow mainWindow = new MainWindow();

mainWindow.setVisible (true);

} // class

This application does not handle window events the window will not close when we try to
close the applet or click on top right hand button 'x'. to stop the MyWindowApp from Kawa,
you need to select stop run from the Build pull down menu.
When running this application simple displays an empty Frame window with the title ‘My
program’s title’:

Managing the main window

When the user interacts with the main window, Java sends events. The events can be
received by a WindowListener. The main window itself can be a window listener, or
another class can take this responsibility.

There are seven different events, and the listener must handle all of them, even to ignore
them. WindowListener is an interface, and specifies seven different methods:
windowClosing()

(the most important) which is called when the user clicks on the ‘close’ icon to close the
window. In summary, the others are:

WindowActivated()

The main window has been activated (e.g., raised to the ‘top’ of the display)

WindowDeactivated()

The main window has been deactivated (e.g., a different window has been raised to the
‘top’ of the display)

WindowClosed()

The window has been closed (this is different from windowClosing , which indicates an
intention to close)

WindowDeiconified()

The window has been restored from a icon

WindowIconified()

The window has been shrunk to an icon

WindowOpened()

The window has been displayed for the first time

To make the main window able to manage itself, that is, receive events from the user
interface, it can be defined like this:

class MainWindow extends Frame implements WindowListener

However, MainWindow must now implement all the methods described above, even if
they don’t do anything. To enable the receiving of events, the main window’s constructor
can have the line:

AddWindowListener (this);

For example the constructor of a class MainWindow might look as follows:


class MainWindow extends Frame implements WindowListener

public MainWindow()
{

// In the constructor we set the size and caption of the

// window, and specify ‘this’ as the window listener

super("Do-nothing program");

setSize(300, 300);

addWindowListener (this);

//... other methods

} // class

An example of a method to be invoked when a windowClosing() message is received


would look as follows:
public void windowClosing (WindowEvent e)

// do actions to terminate application

Closing the main window and stopping the program

When the user indicates that the program is to exit, it should shut down gracefully. By
convention there are at least two ways for the user to do this:

from a ‘close’ window icon

from an ‘exit’ menu command.

The program can be terminated (stopped) by the sending of a System.exit() message.


This will work whatever the program was doing at the time. A well-designed program
should tidy up before it does this. In many cases the program should ask the user if it is
okay to close.

For example, if you are editing a document in a word processor and click on the ‘close’
button, and there are some changes made since the last change, the word processor
should ask if you want to save the work first.

If stopping the program is uncomplicated — no files to save, for example — it can simply
call System.exit() from within windowClosing() .
So the windowClosing() method would look as follows:
public void windowClosing (WindowEvent e)

// terminate program

System.exit(0);

Running the program

When testing, the simplest way to run the application is usually to start it from the
command line. For example, if the main() method were defined in the classMyProgram ,
then after compiling the MyProgram.java source file:

Using Kawa, you would select run

or from a command line of DOS you could enter the command :

java MyProgram

Do not enter java MyProgram.java . You want to execute a class (object file), not a source
file.

Example application - Circle


This is an example of an application consitsting of a main window in which six buttons
and a circle are displayed. The buttons provide the user interface for controlling the circle.
TheCircleWindow is a subclass of Frame and implements a WindowListener for
managing the main window, and an ActionListener for handling the button events.

The following is the UML class diagram for this program.


The code is shown below:

import java.awt.*;

import java.awt.event.*;

public class TheCircleWindow extends Frame implements ActionListener,


WindowListener {

private Button grow, shrink, left, right, up, down;

private Circle myCircle;

public static void main (String[] args){

TheCircleWindow C = new TheCircleWindow();

C.setSize(300,300);
C.setVisible(true);

public TheCircleWindow(){

setTitle ("The Circle World");

setLayout(new FlowLayout());

grow = new Button("Grow");

add(grow);

grow.addActionListener(this);

shrink = new Button("Shrink");

add(shrink);

shrink.addActionListener(this);

left = new Button("Left");

add(left);

left.addActionListener(this);

right = new Button("Right");

add(right);

right.addActionListener(this);

up = new Button (" Up ");

add(up);

up.addActionListener(this);

down = new Button("Down");

add(down);

down.addActionListener(this);
myCircle = new Circle();

this.addWindowListener(this);

public void actionPerformed(ActionEvent event){

if (event.getSource() == grow)

myCircle.changeSize(10);

if (event.getSource() == shrink)

myCircle.changeSize(-10);

if (event.getSource() == right)

myCircle.moveRight();

if (event.getSource() == left)

myCircle.moveLeft();

if (event.getSource() == up)

myCircle.moveUp();

if (event.getSource() == down)

myCircle.moveDown();

repaint();

public void windowClosing(WindowEvent event){

System.exit(0);

public void windowIconified(WindowEvent event){

public void windowClosed(WindowEvent event){

public void windowDeiconified(WindowEvent event){


}

public void windowActivated(WindowEvent event){

public void windowDeactivated(WindowEvent event){

public void windowOpened(WindowEvent event){

public void paint(Graphics g){

myCircle.display(g);

}
// The Circle class

class Circle {

private int radius = 100;

private int xCoord = 100, yCoord = 150;

Color colour = Color.red;

public void display(Graphics g){

g.setColor(colour);

g.fillOval(xCoord, yCoord, radius, radius);

public void moveLeft(){

xCoord = xCoord - 10;

public void moveRight(){

xCoord = xCoord + 10;

}
public void moveUp(){

yCoord = yCoord - 10;

public void moveDown(){

yCoord = yCoord + 10;

public void changeSize(int change){

radius = radius + change;

Converting an applet to an application

It is very straightforward to convert an applet to a stand-alone application. Remember that


the ‘ add() ’ method can add any Java user interface element to a window. An applet is
simply an object of Applet class, so we can add() an applet to a Frame very easily.
Suppose we have an applet called ‘ MyApplet’ and we wish it to be inside the main
window of an application. All that needs to be done is to add the following line to the main
window’s constructor:

add(new MyApplet());

Since we already have a do-nothing application ( DoNothing.java ), we can use this to


form the main window for an applet, and therefore convert any applet into an application.
Note that it is not necessary to change the applet at all for this to work.

Converting an application to an applet

The Circle example will be shown as an applet TheCircle.java. There are some deliberate
diferences such as the initial state of the Circle, colour, etc.
The UML diagram is now:

An applet does not need a WindowListener.


The code is as follows:
//<applet code = "TheCircle.class"width = 300 height = 200></applet>

import java.awt.*;
import java.applet.Applet;
import java.awt.event.*;

class Circle {
private int radius = 10;
private int xCoord = 20, yCoord = 50;
private Color colour = Color.blue;

public void display(Graphics g){


g.setColor(colour);
g.fillOval(xCoord, yCoord, radius, radius);
}
public void left(){
xCoord = xCoord - 10;
}
public void right(){
xCoord = xCoord + 10;
}
public void grow(){
radius = radius + 5;
}
public void shrink(){
radius = radius - 5;
}
public void moveUp(){
yCoord = yCoord - 10;
}

public void moveDown(){


yCoord = yCoord + 10;
}
}

public class TheCircle extends Applet implements ActionListener {


private Button grow, shrink, left, right, up, down;
private Circle myCircle;

public void init(){


grow = new Button("Grow");
add(grow);
grow.addActionListener(this);
shrink = new Button("Shrink");
add(shrink);
shrink.addActionListener(this);
left = new Button("Left");
add(left);
left.addActionListener(this);
right = new Button("Right");
add(right);
right.addActionListener(this);
up = new Button (" Up ");
add(up);
up.addActionListener(this);
down = new Button("Down");
add(down);
down.addActionListener(this);

myCircle = new Circle();


}

public void actionPerformed(ActionEvent event){


if (event.getSource() == grow)
myCircle.grow();
if (event.getSource() == shrink)
myCircle.shrink();
if (event.getSource() == right)
myCircle.right();
if (event.getSource() == left)
myCircle.left();
if (event.getSource() == up)
myCircle.moveUp();
if (event.getSource() == down)
myCircle.moveDown();

repaint();

public void paint (Graphics g) {


myCircle.display(g);
}

Java applications — Activities and Exercises

Activity 1 — Writing a ‘do-nothing’ application

Activity 2 — Convert an applet into an application

(no exercises for this topic)

Files — Assigned reading

Read Sections 17.1-17.3 pp 818-825 of Chapter 17 of Deitel and


Deitel

What is a file?

Examples of files include the text files that are your Java source files, documents storing
word processor pages, databases, numerical tables and charts from spreadsheet
applications. Files can store any type of data, in any format. To the computer a file is
simply a heap of bytes.

Note: Any structure in the file is put there by the programmer.


The most important thing that a Java application can do, that an applet cannot, is to read
and write files on the user’s computer. Almost all computer applications manipulate files.
You will probably have realised by now, that any data stored in the variables of a Java
program are lost when the program finishes. The use of files is the simplest way to store
the data that a program works on.

If you use a computer for ordinary applications, then you probably have a mental model
of a ‘file’ already. The problem that many novice programmers face is that their mental
models of files do not correspond at all with the way that the program ‘sees’ a file. User
interfaces like those provided with Microsoft Windows have encouraged us to see files as
documents and folders; but to the programmer a file is simply a heap of bytes.

There is no intrinsic structure to files . If a file has a particular meaning, e.g., it is a word
processor document, it is because the programmer defined it to be that way.

Note also that Microsoft Windows has a convention of using ‘file extensions’ (.txt, .exe,
.html, .java etc.) to represent the contents of files. This is merely a convention . The
content of a file is specified in the program that writes it.

Java’s ‘File’ class

Java’s File class models both files and directories. It manipulates both files and directories
as entities.

Often the first complication that new Java programmers experience when they begin to
write programs that use files is the function of the File class. This class is used to
manipulate files and directories, but only as whole entities. You cannot use the File class
to read or write data . A File object is created like this:

File aFile = new File("filename");

Having created the object we have access to some useful methods, for example:

File.canRead(), File.canWrite()

Return true if the program is allowed to read or write the file

File.createNewFile()

As the name suggests, creates a new file with the specified filename

File.Delete()
Delete the file

File.length()

Returns the number of bytes in the file

The file class is also important because most of the other classes that read and write files
will require the filename to be given as a File object, not as a text string.

Note: all the Java file handling classes are part of the package java.io, so you probably
need to include the line

import java.io.*;

At the top of your program

Example of using File class

Consider a text file called examples.txt containing the following 2 lines of text:

This is a test file

it has 2 lines of text

We can write an application ( FileTest1.java ) to interrogate this file via an object of


class File:

import Java.io.*;

public class FileTest1

public static void main( String args[] )

String fileName = "example.txt";

File f1 = new File( fileName );

System.out.println("properties of file " + fileName );

System.out.println("canRead() : " + f1.canRead() );

System.out.println("canWrite() : " + f1.canWrite() );


System.out.println("length() : " + f1.length() );

} // class

The result of running our application is the following:

If we edit examples.txt to make it contain just the character:

the output of the application is as follows:


You might like to try compiling this application, and changing the contents of
fileexamples.txt to see the length in bytes change (note that the end of line character
also takes up a byte…).

The ‘byte stream’ model of a file


Java byte input streams

The basic input stream is class InputStream. InputStream is an abstract class: it does
not define how to read the data. The real functionality is provided by subclasses
of InputStream .

For file handling, the most important subclass of InputStream is FileInputStream.

This is a class that can read a specified file from beginning to end.

A Java program creates a new FileInputStream like this:

File aFile = new File("readme.txt");

FileInputStream fis = new FileInputStream(aFile);

Note that the FileInputStream needs to be supplied with a file object, not a simple
filename, so we have to create a File object as well. You will often see this code shortened
to:

FileInputStream fis = new FileInputStream(new File("readme.txt"));

The program can read the first byte of data in the file like this:

Byte b = fis.read();

Each new call to the read() method reads the next byte in the file, until the end.

Example of reading bytes from a FileInputStream

Consider a text file example1.txt containing the following:

We can write a program to display the numeric value of each byte in this file. The output
of the file is as follows:
The bytes with values 13 and 10 correspond the characters to carriage return ( <cr> )
and new-line ( <nl> ) respectively (which are how the Windows system indicates a new
line in a text file).

Java actually views this file as a stream of bytes as follows:

‘A’ <cr> <nl> ‘B’ <cr> <nl> ‘C’ end


of
file

The listing of the application to generate this output is as follows:

import java.io.*;

public class FileTest2

public static void main( String args[] )


{

String fileName = "example.txt";

File f1 = new File( fileName );

FileInputStream stream;

int b;

try

stream = new FileInputStream(f1);

for( int i = 0; i < f1.length(); i++)

// get next byte

try

b = stream.read();

// display byte with message on screen

System.out.println("Byte " + i + " = ‘" + b + "‘");

catch (IOException e) {}

catch (FileNotFoundException fileException) {}

} // class

Ignore the ‘try’ and ‘catch’ statements for now — these are related to dealing with
exceptional conditions, such as the file not being found. Exceptions, file related and
otherwise, are covered later in this unit.
This application is given to illustrate how stream , an object of theFileInputStream

Buffered and character input streams

The class FileInputStream is fine if we want to read a file one byte at a time.

One of the most widely-used files structures in the computing industry is the ‘plain text’
file. Here each byte represents a character (letter, symbol, etc) and there are special
characters to indicate the break between lines. This is the format that Windows Notepad
uses, and is accepted by the Java compiler. HTML files are similar, but here some of the
characters have extended meanings.

We can read a plain text file using a FileInputStream . All we have to do is read each
character one byte at a time, and add it to a String. When we detect an end-of-line
character, we process that line. Fortunately we don’t have to do this, as Java provides a
class for it: the BufferedReader .

A BufferedReader provides a method called readLine() . Each time it is called it reads


the next available line from the file into a String object.

Although straightforward in principle, using a BufferedReader has some awkward


complications, as we shall see.

Creating a BufferedReader

 BufferedReader is not a subclass of FileInputStream


 BufferedReader collaborates with an object of class InputStreamReader
 The object of class InputStreamReader collaborates with an object of
classInputStream

Why does it have to be so complicated? There are two reasons. First,


ifBufferedReader were a subclass of FileInputStream it would be good for file handling,
but it would not help with other data that was in stream format (e.g., data from the
keyboard or network). We would have to implement the same code as subclasses of
many different classes. This is inefficient. Second, Java does not see a String as being
comprised of bytes, but of characters. In most programming languages a character and
a byte are the same, but not in Java.

So here’s how we create a BufferedReader that will allow us to read the file ‘readme.txt’
one line at a time:
File aFile = new File ("readme.txt");

FileInputStream fis = new FileInputStream (aFile);

InputStreamReader isr = new InputStreamReader (fis);

BufferedReader br = new BufferedReader(isr);

String aLine = br.readLine();

Note that four different classes are involved in this simple method! This is what happens
when the program executes ‘ br.readLine() ’.

1. The BufferedReader asks the InputStreamReader for the next character.

2. The InputStreamReader asks the FileInputStream for the next byte

3. The FileInputStream gets the byte from the file specified by the File object

4. The InputStreamReader converts the byte to a characters, and passes it along to


the BufferedReader

5. The bufferedReader checks whether the character is an end-of-line indicator. If it is


then the line is complete. Otherwise repeat from step one.

Of course all this complication is hidden from the programmer — the explanation has
been included so that you can see what the four classes do.

Reading a text file a line at a time is such a common method that it is surprising that Java
does not contain a class to automate it. Some proprietary Java development tools include
extended class libraries that have this sort of facility. For example, Microsoft’s Visual
J++ has a class called TextReader that does exactly this job. However, it is simple enough
to implement a TextReader class yourself and use it in any program that requires this
facility.

The process described above can be simplified slightly by the use of the FileReaderclass.

Output byte streams

Writing data to a file is very similar to reading data from a file. To write a file one byte at
a time we create an object of class FileWriter , and call its write() method to write
each byte. There is also a BufferedWriter class than cofunctionality complementary to
the BufferedReader .
Example of interactive programs reading/writing files

The following is an example of writing the content of a TextArea to a file. The


program uses the PrintWriter class which allows you to pass any object as
an argument.

The code can be found in FileDemo.java .

FileDemoReversed.java performs the opposite operation. The user is


expected to supply the name of a file and the content will be displayed in the
TextArea. If you use the same file you have just created the following will be
displayed.
further examples of interactive file handling programs can be found in sections 17.4-17.12
chapter 17 of Deitel & Deitel.

Other file ‘stream’ models

As well as the ‘byte stream’, Java supports other models of a file which are extensions of
the ‘byte stream’ concept.

 Data stream: sees the file of a stream of variable values (e.g., double, int)
 Object stream: sees the file as a stream of objects

The data stream approach is useful for storing the values of Java variables, particularly
arrays, in a file. An object stream is useful for storing the states of objects between uses
of a program.
Non-stream files access

So far we have considered a file as being a ‘stream’ of something (bytes, characters,


objects). This is very useful when a file has to be read or written in its entirety. It is not so
useful when the data must be picked out of the file at widely separated locations.

Java provides a class called RandomAccessFile for this. A random access file models a
file as an array of bytes, rather than a stream of bytes

File handling exceptions

File handling is an area where the programmer needs to take particular care that the
program responds correctly if something unfortunate happens. For example, if we ask a
word processor to open a file that does not exist, it should politely warn us of the problem.
It should not crash, or print a meaningless error message like ‘ null pointer
exception 0030:1023 in module aargh.exe’ ). The reason it responds
appropriately is that the programmer anticipated that the user might make this mistake,
and wrote program code to respond correctly. The programmer must provide program
statements to deal with most or all errors and mis-operations that the program may
encounter.

To simplify and regulate the process, Java uses a mechanism called ‘exception handling’.
We have not covered this subject yet, but in brief it is a technique for specifying what can
go wrong in any particular method. Java uses the statementsthrow , try and catch to
control this process.

For example, it was explained earlier in this unit how to define a BufferedReader , but
this would not work as it standard because the code did not deal with the exceptions that
might arise. When a method specifies that it might generate a particular exception, the
program that uses it must take account of this. The compiler will not proceed otherwise.

So this earlier section of Java should really have written like this:

try

File aFile = new File ("readme.txt");

FileInputStream fis = new FileInputStream (aFile);

InputStreamReader isr = new InputStreamReader (fis);

BufferedReader br = new BufferedReader(isr);


String aLine = br.readLine();

catch (Exception e)

System.out.println ("Helpful error message");

Here the keyword try means that the following section contains methods that are
defined to produce exceptions (Java programmers talk about ‘throwing an exception’).
The section starting with ‘ catch ’ defines what to do if one of these exceptions is actually
generated.

The topic of exceptions is investigated in more detail later this unit.

Files — Activities and Exercises

Activity 3 — Testing the FileDemo programs

Exercise 1 — Using the FileReader class

Exercise 2 — WebMerge example program

Exceptions

Exceptions — Assigned reading

Read sections 14.1-14.4 , 14.6-14.10 pp 699-703, 708-717 of


Chapter 14 of Deitel and Deitel
Introduction to exceptions

The purpose of this section is to introduce the types of exceptions (‘errors’) to which a
computer program is subject, and describe how a Java program can be made to behave
predictably even in the presence of exceptions

It is important for the design and development of usable and robust programs to anticipate
the kinds of errors to which your programs will be subject. Java’s Exception
handling system can be used to write programs that are tolerant of user and system
errors.

Exceptions and errors

The word ‘exception’ has a similar meaning to the word ‘error’, but ‘error’ is very vague in
normal usage. It can mean a specific logical error in a line of program (like adding 2 when
you should have added 3), or an incorrect operation on the part of the user (like opening
a non-existent file). The first of these is simply a mistake on the part of the programmer,
and no particular mechanisms exist to detect such mistakes. Finding errors like this is
part of the normal process of testing and debugging. The second is an adverse input to
the program, which must be detected and corrected by the program when it is running.

In Java, the words exception and error have reasonably well-defined meanings.

In Java, an exception is anything that would cause a program to deviate from its ‘normal’
course of operation. An exception may result from incorrect operation by the user, or
failure of any part of the computer system on which the program is running. An exception
may also arise because the programmer did not anticipate user inputs that are impossible
to process (like asking a calculator to divide something by zero). In Java, some
programming errors are also classified as exceptions, as will be discussed later.

In Java an error usually means a system error . That is, a serious problem resulting from
something beyond the control of the programmer or the user.

Proper handling of exceptions is a mark of professionalism. In practice it is very difficult


to write a program that responds correctly in response to every conceivable exception,
and very expensive. However, if the software is controlling a safety-critical system (e.g.,
air traffic control) then the developers may aim for absolute reliability. In the ordinary
commercial market, however, the programmers must aim for a good compromise
between cost of development and quality of the final product.

User and system errors


Correct response to exceptions and errors

Well designed programs should respond :

 correctly when operated correctly

 appropriately when operated wrongly


 safely to system errors

A program probably cannot produce useful, correct results if it is operated incorrectly


(‘garbage in, garbage out’). It should, however, respond appropriately . An appropriate
response depends somewhat on the application. In most desktop computer applications
the appropriate response is to display a polite message to the user stating what the
problem is. Here is an example. Suppose the user of a word processor tries to save a
document file on a disk in which there is not enough space. The response from the
program could be any of the following (arranged from most appropriate to least
appropriate).

There is not enough free space on the selected disk to save this document.
If you want to continue you should delete some files on this disk or select a
different disk

Out of space on drive C:

Disk full!

Sorry!

ERROR

Java.lang.NullPointerException at MyProgram.writeFile() on line 132

[followed by lines of meaningless debugging information]

The last of these responses probably constitutes a crash . This is probably the result of
the programmer doing nothing at all to deal with the incorrect operation, and the
consequences being detected by something else. The notion of a crash is discussed in
more detail below.

Sometimes computer programs are subject to system errors. Such errors result, for
example, from unplugging a cable to switching the power off without warning. In rare
cases computer equipment has been known to catch fire.

It is impossible to respond in any useful way to most system errors. If the power is
switched off it is impossible to respond at all. However, the system should respondsafely .
By this it is meant that the amount of damage caused by the failure is minimized. For
example, most word processors save the user’s work to disk automatically at regular
intervals. Even if the power is switched off, the user will lose only a limited amount of
work.

What is a ‘crash’?

The term ‘Crash’ is rather vague, even to programmers. Typically a program is said to
have crashed when it has done some or all of the following:

 stopped working completely, as if it had never started


 stops responding to user input
 leaves its data in an unpredictable state
 produces meaningless displays
 requires user intervention to recover normal operation
 leaves the complete system in an unpredictable or inoperable state

The last of these is probably the most annoying for the end user. In a well-designed
computer system it should be impossible for the failure of a single program to compromise
the operation of the system, but it does sometimes happen. Fortunately, it is almost
impossible for a Java program to have such a drastic effect. A Java program can,
however, exhibit all the other symptoms of a crash.

What happens if exceptions are ignored?

If the programmer has not written the program in such a way that it detects and handles
exceptions, usually one of three things will happen:

 The program crashes immediately


 The program continues to work, but behaves strangely and then crashes
 The program continues to work, but produces meaningless results

None of these situations is desirable. The programmer should anticipate exceptions


wherever possible, and write the program in such a way that it responds appropriately

Why exceptions get ignored ?

We have already seen that the programmer should not ignore exceptions. Why would
they get ignored?

There are two main reasons:


 The programmer does not anticipate that a particular method can go wrong
 The programmer delays writing instructions to handle the exception, then forgets
to do it later

File handling in particular is an area where a great many things can go wrong. It can be
very time-consuming (and sometimes difficult) to write instructions that deal correctly with
all the possible exceptions.

Java’s exception handling scheme is designed to make it difficult for the programmer to
forget or ignore exception handling. Whenever an exception can occur, the programmer
is forced to do something about it, even if it is only to write instructions to ignore it.

It is important to realize that good exception handling requires a lot of extra programming.
In many cases, there may be as much or more code concerned with exception handling
than with the normal operation of the program.

Java’s exception handling scheme

In Java, methods ‘throw’ and ‘catch’ exceptions. Exceptions are defined as classes. Many
of the Java built-in classes can ‘throw’ exceptions. The programmer can add new
exceptions if necessary.

To ‘throw’ an exception is to indicate that an exception has occurred. When an exception


is thrown, it must usually be ‘caught’ (but see below for more information).

Exceptions are defined as classes. For example, the exception generated by opening a
file that does not exist is represented as an object the class FileNotFoundException. If we
want to indicate that an attempt has been made to open a non-existent file, then we ‘throw
a FileNotFoundException ’. The mechanism for doing this will be described later.

Catching an exception

The section of code within which an exception may be generated is enclosed in a


try section

Immediately after the try section we define a catch section

Consider this section of Java, that opens a file called ‘readme.txt’ for reading.

File aFile = new File ("readme.txt");

FileInputStream fis = new FileInputStream (aFile);


If we try to compile this code as it stands, we will get an error message from the compiler,
as follows:

Exception java.io.FileNotFoundException must be caught, or it must be


declared in the throws clause of this method.

If you look in the on-line documentation for the class FileInputStream , you will find
that its constructor is defined to throw a FileNotFoundException . The compiler is
telling us that this exception must be handled. We can handle it in one of two ways: by
doing something about it, or by passing it on to the method that called the current one.

This section of Java can be written to process the exception as follows:

try

File aFile = new File ("readme.txt");

FileInputStream fis = new FileInputStream (aFile);

catch (FileNotFoundException e)

System.out.println

("Sorry, the file ‘readme.txt’ does not exist’");

The ‘try’ section encloses the statements that will throw the exception. The ‘catch’ section
defines what happens if an exception is thrown.

Note that each catch must specify the exception which is to be handled.

The try section can be of any length, and there can be as many catch sections as required.
This means that it is possible to write an method in two parts, like this:

try

// main part of method

}
catch (...)

// handle exceptions

catch (...)

// handle exceptions

This structure has the ‘important’ (that is ‘normal method’) part of the method first,
followed by all the error handling code. This makes it easier to follow how the program
works, because the main functions of the method are separated from the exception
handling.

Passing an exception upwards

Suppose we are writing a method that does some file manipulations, but it is not
appropriate for the exceptions to be handled in that method. For example, we might be
writing a general-purpose class that will be used in a number of different programs. The
ways that errors are reported to the user will differ according to the application.

Here is an example. A class has been defined called FileManager() which contains
useful methods for copying, renaming and deleting files. Clearly there is a need for
exception handling here. The method copyFile() might be defined in outline
something like this:

public void copyFile (String sourceFile, String destinationFile)

// more file read and write statements go here...

This method will contain a lot of statements that generate exceptions. Where will they be
handled? A typical scheme is to ‘pass upwards’ the exceptions. This means that the
exceptions are not handled in this method, but in the method that called it. In this case
the method that uses the copyFile() method must handle the exceptions
(using try and catch as before).
The passing upwards of exceptions is indicated like this:

public void copyFile (String sourceFile, String destinationFile)

throws FileNotFoundException

// lots file read and write statements go here...

Here ‘throws’ means that this method can itself throw an exception. If
aFileNotFoundException occurs during the execution of copyFile() , then it is
the method that called copyFile() that must handle it. copyFile() itself will stop as
soon as the exception is detected. This means that if there are a long series of statements,
and an exception occurs in the first one, then the rest of the method will be skipped.

Exception classes

In Java, exceptions are represented as classes and form a hierarchy. The advantage of
this structure is that it allows the programmer to handle groups of exceptions rather than
individual cases. For example, suppose we are writing a section of program that
undertakes a number of file methods (reading, writing, etc). All the classes concerned
with file handling exceptions are subclasses of the class IOException . So if we want to
catch all such exceptions in one ‘catch’ section, we can write:

catch (IOException e)

System.out.println

("Sorry, something went wrong during a file method");

The problem with this approach is that treating all the exceptions as equivalent may not
be what we want. It probably doesn’t help the user very much if the program cannot give
a more detailed explanation of what is wrong.

Note that all exceptions used by the Java standard classes are subclasses of Exception.
So if a program catches an Exception then it guarantees to handle all possible exceptions.
This is sometimes useful when developing a program, but is not normally good practice
because, again, it is difficult to tell the user what has happened.
Defining new exceptions

The standard built-in Java classes define and use exceptions. It is also possible to define
new exceptions to organise exception handling for your own classes. Suppose, for
example, we are writing a class that displays text files for the user to browse. It contains
a method called ‘ openTextFile() ’ that reads a specified text file and displays it. If the user
selects a file that is not a text file, the method cannot continue. We might define this
method like this:

public void openTextFile(String textFileName)

throws NotTextFileException

// Lots of file handling statements here

The line:

throws NotTextFileException

indicates that this method can throw (generate) an exception


called ‘NotTextFileException ’. We have not defined yet what
a NotTextFileException is.

When defining a new exception, we can make it a subclass of Exception, or of one of the
existing subclasses of exception. With this example, NotTextFileException is similar to
the existing file handling exceptions (like FileNotFoundException ) so we probably want
to define it as a subclass of IOException (as the other file handling exceptions are). The
definition will look like this:

class NotTextFileException extends IOException

This is the complete definition; in this case no methods are required.

So we know how to define an exception; how does the program throw it?

Throwing an exception

The previous section explained how to define a new exception,


calledNotTextFileException. This exception was to be thrown by the
methodopenTextFile() if the user tried to open a file that was not a text file. Here is how
the exception is thrown:

throw (new NotTextFileException());

Note that it is a specific object of the class that is thrown, not the class itself. So we use
new to create the exception object, and throw to throw the new exception.

A program can throw any exception, not just the ones it defines. However, this is usually
not useful; the built-in exceptions are thrown by the methods in the built-in classes.

Java run-time exceptions

In Java, a ‘run-time exception’ is one that does not have to be caught by the program.
The compiler will not report an error if the programmer does not handle a run-time
exception. An example of a run-time exception is ArithmeticException . This exception
occurs when the program tries to carry out an arithmetic operation which cannot succeed
(like dividing by zero). The programmer does not have to handle this exception.

What happens if the exception is thrown and the programmer does not handle it? The
program will automatically be stopped, and the name of the exception displayed. This is
a very ugly way for a program to finish, so the programmer may choose to handle the
exception anyway.

Handling a run-time exception is no different from handling a normal exception. Here is


an example of the use of ArithmeticException :

try

int x = 2/0;

catch (ArithmeticException)

// Display a helpful error message here

Run-time exceptions differ from ordinary exceptions in that they are subclasses
ofRuntimeException , rather than of Exception .
Java ‘error’ classes

In Java, the word ‘error’ usually denotes a system error . That is, a problem arising from
hardware or from a logical error in the Java system itself. A typical example of a system
error is not having enough memory to complete a method.

Like run-time exceptions, the program does not have to handle errors. Indeed, Java
standards recommend that the program does not handle these exceptions. The reason
for this is that if the computer or the program is in a state where such an error occurs, it
is probably impossible for the program to do anything useful. For example, if the program
runs out of memory, then it won’t be able to do anything to correct this situation because
it won’t have enough memory to carry out whatever corrections are required.

In Java, errors are subclasses of the Error class.

Exceptions — Activities and Exercises

Activity 4 — Catching an exception

Exercise 3 –Exceptions Summary

Exercise 4 – File handling exceptions

Exercise 5 – Errors and Exceptions

Exercise 6 – User errors

Exercise 7 – Null pointer exceptions

Activities

Activity 1 — Writing a ‘do-nothing’ application

A ‘do-nothing’ application is one that provides the outline of a program, but does not do
anything useful. Write such a program as a stand-alone Java application. The program
should create a main window with the title ‘do-nothing program’. When the user clicks on
the ‘close’ icon, the program should close.
The program should appear something like this:

Discussion/Suggestion solution to Activity 1

Writing a ‘do-nothing’ application

A possible solution is shown in DoNothing.java

Activity 2 — Convert an applet into an application

Convert the ‘calculator’ applet (given in Calculator.java ) into a stand-alone application.


You will not need to change any of the Java in Calulator.java. If you have already compiled
Calculator.java, you can solve this problem by adding exactly one line of Java to
‘DoNothing.java’.

Discussion/Suggestion solution to Activity 2

Convert an applet into an application

A possible solution is shown in CalculatorApp.java Note that to make the program


completely self-contained we have to reproduce the code for the applet Calculator.java
in this program. Normally one would not need to do this — the applet could quite
reasonably remain in a separate file.

Activity 3 — Reading and Writing files

Test the FileDemoReversed.java program by supplying any text file an see how it will be
displayed in the TextArea. As an example you could use the source code file of a program

Discussion/Suggested solution to Activity 3

Reading and Writing files

You have to be careful to make sure that the file you load can be found.
I have used files from my local a:drive.
You can also experiment with creating files either using the FileDemo.java
or otherwise. Discuss any problems with your tutor.

Activity 4 — Catching an exception

A common problem when processing numeric input from users is that they enter real
values, or values with comma’s etc. when, say, an integer is required. So for example a
program might request an age from the user (expecting an integer), and a small child
might enter ‘3.5’ or ‘3 and a half’.

The application below uses a Swing dialogue box to request and get input from the user.
This showInputDialogue() method returns the value entered by the user as
aString , whether we wanted a String , or char , or int or double or whatever. One
convenient way to convert from a String to an int is to use the class
methodparseInt() provided by the String class. This method converts from a String . ,
such as ‘21’ (i.e. character ‘2’ followed by character ‘1’) to the int 21.

When the application is run it first displays a message in the console window
(viaSystem.out.println() ):

Age parsing application

Then the application presents to the user an input dialogue, requesting their age:
Then the application displays the current age (having parsed it to an int), and the age of
the person next birthday. Then the application terminates:

The problem occurs if what the user enters is not a valid integer (say 4.5). Then the
application crashes with the following messages:
The listing of the application is as follows:

import javax.swing.*;

public class Exception1

public static void main( String args[] )

String ageString;

int age;

System.out.println("Age parsing application");

ageString = JOptionPane.showInputDialog(null, "Enter age


(1-100)", "Entry of age", JOptionPane.QUESTION_MESSAGE);

age = Integer.parseInt( ageString );

int ageNextBirthday = (age + 1);


System.out.println("Age now : " + age);

System.out.println("Age next birthday: " + ageNextBirthday);

System.exit(0);

} // class

Find out about parseInt() and the exception it throws when its String is not a valid, and
amend the application to display the following message before terminating if the age
entered is invalid:

sorry - your age entry of ‘<age>‘ is not a valid integer

where <age> is whatever the user entered. So if the user entered ‘4.5’ the message would
be:

sorry - your age entry of ‘4.5’ is not a valid integer

Discussion/Suggested solution to Activity 4

Catching an exception

From the Javadoc html pages it was possible to find details about the exceptions that
might occur when sending String.parseInt() messages:
Therefore we need to catch a NumberFormatException exception, and display a
message to the user indicating that their input could not be processed as a valid integer.

The code that parses the String and displays the output can be changed to the
following:

try

age = Integer.parseInt( ageString );

int ageNextBirthday = (age + 1);

System.out.println("Age now : " + age);

System.out.println("Age next birthday: " + ageNextBirthday);

catch (NumberFormatException n)

System.out.println("sorry - your age entry of ‘" + ageString + "‘ is not a


valid integer");

}
A full listing of the revised code can be found in the file Exception2.java.

Exercises

Exercise 1 — Using the FileReader class

Java defines a class called FileReader which combines the functionality of


aFileInputStream and InputStreamReader . Using this class we can rewrite the Java
code to create a BufferedReader so that is uses only three classes, rather than four. Use
the JDK documentation to find out about the FileReader and change the Java below so
that it uses a FileReader rather than a FileInputStream and anInputStreamReader

Discussion/Suggestion solution to Exercise 1

Using the FileReader class

File aFile = new File ("readme.txt");

FileReader isr = new FileReader (aFile);

BufferedReader br = new BufferedReader(isr);

String aLine = br.readLine();

Exercise 2 — WebMerge example program

Study the example program WebMerge.java and answer the questions in it.

Discussion/Suggestion solution to Exercise 2

WebMerge example program

Answer to embedded question


If canRead() returns false, this means that the specified file cannot be read. There are
various reasons why this might be the case. The mile might not exist, or the program
may not have access rights to it.

Answer to embedded question

The method lastIndexOf() finds the last position of a sequence of characters in a


String. In this case we are looking for .html. Now fred.html.xyz contains the
string ".html" starting at position 4. So the directory name will be the characters from 0
to 4 of the name, that is "fred". So yes, the program will work, and the directory will be
called "fred".

Answer to embedded question

It is possible to create a File object corresponding to a file that does not exist. It has to
be, because the method File.createNewFile() will create a new file, and this would be
unnecessary if the file had to exist already.

Answer to embedded question

The variable directoryName contains the name of the directory where the file will be
written. The variable inputFilename is the name of the input file; the output file will have
the same name but be in a different directory. So the line cthe full name of the new file
from the directory name, the ‘/’ character and the filename.

Answer to embedded question

If the file were very long, then the computer may not have enough memory to hold it. In
this case we would have to process the file in pieces. In practice a modern PC ought to
be able to manage files of a few megabytes in memory without too much trouble.

Answer to embedded question

The method available() returns the number of bytes that are available to read. If this
is zero, then we have read to the end of the file.

Exercise 3 — Exceptions Summary

Complete the table below summarising the difference between exceptions, run-time
exceptions, and errors in Java:
Handled by Subclass of Example
program

Exceptions Exception

Run-time
Optional
exceptions

Errors

Complete the following statements that summarise the concepts explored in the
‘Interfaces’ section of this unit:

The keyword _____ is used to signal that an _________ has occurred.

When an exception has been ______, it must either be dealt with in the _______ ______ or thrown
‘_______’ to the calling method, which must deal with it in its turn.

To deal with an exception inside a ______ a ___/_____ structure is required.

Exceptions are _______, not classes.

___-____ exceptions and errors do not have to be caught, but if they are not the program will _________.

Discussion/Suggestion solution to Exercise 3

Exceptions Summary

Suggested entries for the exception summary table are as follows:

Handled by ont Example


program face="Arial">Subclass
of
Exception
Opening a file that
Exceptions Compulsory
does not exist
Run-time RuntimeException
Division by zero;
Optional
exceptions access to an array
element outside the
bounds of the array
Errors No Error Out of memory

Suggested completed summary statements are as follows:

The keyword throw is used to signal that an exception has occurred.

When an exception has been thrown, it must either be dealt with in the current
method or thrown ‘upwards’ to the calling method, which must deal with it in its turn.

To deal with an exception inside a method a try/catch structure is required.

Exceptions are objects, not classes.

Run-time exceptions and errors do not have to be caught, but if they are not the
program will terminate.

Exercise 4 — File handling exceptions

File handling is traditionally an area where the program has to be able to deal with all
sorts of errors and unexpected results (these are collectively called ‘exceptions’ by Java
programmers) Assuming that a program is well written (and therefore will not fail because
of a trivial error on the part of the programmer), what can go wrong while attempting to
read to data from, or write data to, a file? Some of these errors may be the result of a
mistake on the part of the user, but the program must deal with them nonetheless. Try to
think of at least five possible exceptions.

Discussion/Suggestion solution to Exercise 4

File handling exceptions

Attempting to read a file that does not exist

Attempts to read a file to which the program does not have access rights

Attempting to read or write to a file to which the program does not have
access rights

A file is deleted or moved by another program while being read or written


A file does not contain data in the format the program expects

Attempting to read or write a file to a disk that is damaged in some way

Attempting to read or write a file on a remote machine over a network


connection which fails during the method

Exercise 5 — Errors and exceptions

Although many exceptions are the consequence of problems beyond the control of the
programmer, some errors on the part of the programmer will be detectable in the form of
exceptions. Which of the following errors on the part of a programmer do you think will (1)
always given rise an exception? (2) possibly give rise to an exception or (3) not give rise
to an exception? Assume that x, y and z are integer variables.

Statement written Statement that should have been


written

1 int x = y + 2; int x = y + 4;

2 int x = y / 0; int x = y / o;

3 int x = y/z; int x = y/2;

4 int x = y[-1]; int x = y[z - 1];

5 int x = y[2] int x = y[3];

Discussion/Suggested solution to Exercise 5

Errors and exceptions

1. This will not generate an exception. It is a straightforward logical error on the part of
the programmer. However, the variable ‘x’ now contains the ‘wrong’ value, and it is
possible that an exception will be generated later when this value is used.

2. This will generate an exception. Dividing by zero is impossible with ordinary


numbers.

3. This line may generate an exception. It will do so if ‘z’ is equal to zero.


4. This will generate an exception; a negative array index is never valid.

5. This will not generate an exception; although ‘x’ now contains the ‘wrong’
value.

Exercise 6 — User errors

The use of a graphical user interface limits the likelihood that user errors will occur.
Programs that operate by the user typing commands are far more prone to user errors.
Why is this?

Discussion/Suggested solution to Exercise 6

User errors

1. Graphical user interfaces usually provide the user with a choice of operations. For
example, if the ‘File’ menu provides commands ‘File’, ‘Open’, etc., the user is limited to
these operations. The user does not have the opportunity to ask the program to do
something that is totally meaningless. If you run the Java compiler from the command
line, you could readily type

javac test.html

but test.html is probably an HTML file and will make no sense to the Java compiler. A
Java compiler with a graphical user interface may only allow the user to select files from
a list of files that are known to be Java programs. Thus there is no opportunity for this
kind of error to occur.

2. The user is normally only offered choices that are valid in the current
context. For example, a desktop publishing program may change the facilities
offered to the user depending on whether text or a diagram is being edited.
This prevents the user trying to do something that, although meaningful, is not
appropriate in the current context. For example, a desktop publishing program
may have the facilities to change the font of text, but it would be inappropriate
to change the font of a circle or rectangle. The program will normally not
present the user with a command to change font while editing a circle or
rectangle. This is what is meant by ‘appropriate to the context’.

3. A graphical user interface allows the programmer to restrict the type of data entered
by the user. For example, if the program is expecting a number, the data entry field can
be configured to accept only digits (not letters or symbols) as input. So the error that
might result from the user entering the wrong type of data is prevented. Of course this
does not prevent the user entering meaningless data, it only prevents the user
entering grossly meaningless data.

Exercise 7 — Null pointer exceptions

One of the most important run-time exceptions is the ‘null pointer exception’. Use the Java
documentation to find out what a null pointer exception is, and write a few lines of Java
that will generate such an exception.

Discussion/Suggested solution to Exercise 7

Null pointer exceptions

A null pointer exception occurs when the program tries to use an variable declared to
refer to objects of a particular class, but which at that point in the program does not refer
to any object (probably has not been initialised, or the object it was referring to has been
destroyed). Such an (object) variable is described as having the value ‘null’ in Java, or
the variable is said to be referring to a null object.

Java is actually quite good at preventing this happening.

For example, if we try to compile this piece of Java:

Frame myFrame;

myFrame.setVisible(true);

The compiler will warn me that myFrame is not init. The problem usually occurs when
objects are used as attributes of another class. For example, consider this section of
Java:

class Test

Frame myFrame;

// constructor for class Test

Test()

{
myFrame.setVisible(true);

This will cause a null pointer exception as soon as an object of class Test is created.
This is because the constructor calls myFrame.setVisible() , but myFrame at that point is
a null object: it has not been set to any value.

In this case the compiler is not smart enough to spot that the programmer has made a
mistake. A similar problem arises when passing an object as the argument to a method.
The compiler cannot work out whether the object is initialised or not.

Review Questions

Applications

Review Question 1

What are the main advantages to developing a program as a stand-alone application


rather than an applet?

Discussion of Review Question 1

The stand-alone program does not require another piece of software (like a
Web browser) to support it, so is less dependent on the reliability of the
supporting software. In Java a stand-alone application is allowed to do certain
things that an applet cannot; the most important of these is to read and write
data into files on the user’s computer.

Review Question 2

An applet has to have a graphical user interface, but an application does not. If an
application does have a graphical user interface, what must the programmer provide that
is available automatically to an applet?

Discussion of Review Question 2


Principally the application must have a main window. This forms the interface
between the GUI environment and the program itself. The program must
create the main window, and respond to events that are sent to it. In an applet
all this is handled automatically by the Web browser or applet viewer.

Review Question 3

What usually causes a Frame window to receive a ‘windowClosing’ event?

Discussion of Review Question 3

The user clicks on the ‘close’ icon in the window, or carries out some other
similar action

Review Question 4

What Java class usually forms the base for an application’s main window?

Discussion of Review Question 4

Frame class. If you prefer using Swing classes rather than AWT classes, then
the main window would probably be aJFrame object.

Review Question 5

When the user clicks on the close icon of a Frame window, Java sends a windowClosing
event to the listener for that Frame. Why can it not simply terminate the program, and
save the programmer a bit of work?

Discussion of Review Question 5


In some circumstances the programmer may not want this action to be carried
out automatically. For example, if the user is editing a document and has
made changes that need to be saved, it would be very annoying if the
program terminated immediately the close icon was clicked.

Files

Review Question 6

What is the purpose of the File class in Java?

Discussion of Review Question 6

The File class models a file as a single unit, that is, it allows files to be
created, deleted and tested for various things, but it does not allow any data to
be read or written

Review Question 7

What is the purpose of the InputStreamReader class?

Discussion of Review Question 7

Essentially to convert a stream of bytes into a stream of characters.


Conventionally text files are organized as one byte per character, but Java
uses two bytes per character. The InputStreamReader class converts between
the two formats.

Review Question 8

What is the purpose of the BufferedReader class?


Discussion of Review Question 8

To read a stream of text one line at a time.

Review Question 9

When reading a plain text file one line at a time, why can we not accomplish this using
only a BufferedReader object? Why do we need other classes as well?

Discussion of Review Question 9

BufferedReader reads data from an input stream, not from a file. To


use BufferedReader to read files we need a class (or classes) that mediate between the
file and the input stream. This is so that BufferedReader can be used to read other
streams (e.g., keyboard, network) and not just files

Review Question 10

What classes would we use to write a file containing 1000 integer values (rather than
1000 bytes)

Discussion of Review Question 10

DataOutputStream is the main class here. You will also need


a FileOutputStream because DataOutputStreamwrites to a stream, not a file.

Review Question 11

In this unit it was stated that it requires four different classes to allow a Java program to
read a text file one line at a time. This is because we could not make BufferedReadera
subclass of FileInputStream.

However, if Java allowed multiple inheritance these problems could be overcome, and
we could do this job with only one class. How is this?
Discussion of Review Question 11

We could define a class called (for example) FileLineReader which is a subclass


ofFileInputStream and BufferedReader. If we wanted a class that could read data
from the keyboard a line at a time --rather than a file -- we could define a class
called (for example) KeyboardLineReader which is a subclass
of BufferedReader andKeyboardInputStream. In these cases the two base classes
are providing complementary functionality. The ‘BufferedReader’ base class
provides the mechanism for reading lines, while the other class
(FileInputStream or KeyboardInputStream) provides a mechanism for reading
bytes. This is an example of ‘mix-in’ programming.

Review Question 12

A number of complications arise from the fact that Java uses two bytes of memory to
represent a character, and most other programming languages use a single byte. In fact,
normally a ‘byte’ and a ‘character’ are equivalent. These complications could be
overcome if text files were written such that each character was two bytes and not one
(as Java requires). What would be the implications of this for a Java program?

Discussion of Review Question 12

A Java program would be able to read and write the ‘two-byte character’ text
files, but most other programs would not. If the data was only to be read by
the one program then that’s fine. However, one of the great advantages of the
‘plain text’ file format is that almost all computers understand it. This portability
would be lost if a program invented its own format for plain text files. However,
as time goes by more and more computer systems are starting to use two-
byte characters as the standard. Windows NT, for example, uses the same
UNICODE two-byte format that Java uses. So in the future a two-byte
character may become standard, and programs won’t have to make special
arrangements to convert one to the other.

Exceptions

Review Question 13
What are the main differences between subclasses of RunTimeException and
subclasses of Exception in Java?

Discussion of Review Question 13

Subclasses of RunTimeException do not have to be caught by the program. If


such an object is not caught, it will lead to the program being stopped
automatically and an error message displayed. Subclasses of Exception are
used in cases where the programmer must handle the exception in the
program.

Review Question 14

What is a NullPointerException and how does it arise?

Discussion of Review Question 14

A NullPointerException is thrown if the program tries to interact with an object


that is not initialised. Such an object is called a ‘null’ object because it
effectively has no value. The usual causes of this exception are the
programmer forgetting to initialise and object (using new) or not understanding
the order in which methods are carried out, so that the object appears to be
initialised when it is not.

Review Question 15

What is wrong with this attempt to throw an exception?

Discussion of Review Question 15

The program is trying to throw a class. In fact an exception is an object of the specific
exception class. It should be written like this:

throw (FileNotFoundException);
Review Question 16

Why are Java exceptions organised as a hierarchy of classes, rather than simply as
direct subclasses of the Exception class?

Discussion of Review Question 16

The use of a class hierarchy allows the programmer to group the handling of
different types of exception together. This can make the program easier to
understand and manage. For example, it is quite likely that all the exceptions
that are subclasses of IOException will need to be handled in similar ways, so
they can usefully be handled as a class in some situations.

Review Question 17

If a programs throws an exception upwards, that is, ‘out of’ a method, where is it
‘caught’?

Discussion of Review Question 17

If an exception is passed upwards, it must be caught by the method that


called the throwing method. Of course, this method can itself pass the
exception upwards if the program so chooses.

Discussion Topics

There are many new concepts in this unit. If you want to discuss with your colleagues or
make comments about the concepts to them, use the on-line facilities.

Discussion Topic 1 – Slow commercial uptake of Java

Java is probably the most widely-taught programming language in the World today. At
any one time at least a million people are studying Java programming. However, at the
time of writing very little commercial software is being developed in Java. This is in spite
of the fact that almost all of the most widely used pieces of software currently in use could
have been developed in Java, and their potential market would have been greater (owing
to Java’s portability).

What reasons might there be for the relatively slow uptake of Java in
the commercialsector?

Do you think that the current developments in Java (like the use of ‘just-in-time’
compilers and native code compilers) will make any difference to this?

Contribution for Discussion Topic 1 – Slow commercial uptake of Java

Until there is a rise in e-commerce few commercial software systems will involve applet
programming. Therefore applets, which form one of the strengths of Java over other
languages, currently act as a motivation for commercial companies to use Java.

Companies invest resources (time, money, training) in their software systems and
software staff. Large systems are designed to be extensible and to be used for many
years, or even tens of years. Therefore even though a new system being written today
might be written in Java, most software work is on existing systems written in older
languages such as C, C++ and Visual Basic.

Also, due to the performance limitations of real-time interpretation, Java programs


execute slower (sometimes many times slower) that native-compiled programs written in
other programming languages.

Just-in-time and native code compilers can, to some extent, improve the performance
limitations of Java. Although, like many object-oriented languages, features such as
dynamic binding (required to support polymorphism) will always carry a performance
overhead, since it means that some statements can never be compiled as efficiently as
for non-dynamic programming languages.

Discussion Topic 2 — Limitations due to applet security restrictions

One of the most important limitations of Java applets is that they are not able to interact
with the user’s computer to any great extent. This greatly limits the usefulness of applets.

What is it about the way that applets are distributed that makes these security
restrictions important?

How could the security restrictions be relaxed without risking adverse


consequences for the users?
Contribution for Discussion Topic 2 — Limitations due to applet security
restrictions

Applets are programs that users download from the internet and run on their local
computers. Were applets allowed to access the files and memory of the local computer,
the potential for malicious (e.g. viruses) and accidental (i.e. poorly written) software to
delete files and corrupt memory would be enormous.

However, these restrictions mean that applets are very limited in certain areas,
such as file handling.

There is no real way to relax such restrictions without risking problems. It would
be possible to safely use applets with file access facilities, for example, if a user
had, say, 2 computers, only one of which was connected to the internet. Then
the internet computer could be used to run applets and programs from non-
trusted sources, with physical separation from important files on the other
computer.

If software is coming from a trusted source, there is no need to restrict oneself to applets,
since a trusted source can be trusted to provide applications (with all their file handling
etc. features) that will not damage the user’s system.

Discussion Topic 3 — Complexity of ways of reading files

In this unit we have described how a Java program could read a text file one line at a time
— this required four classes. We have also described how a text file can be read as if it
were an array of bytes, where any byte can be read at any position — this requires only
one class: RandomAccessFile.

The job done by RandomAccessFile seems on the surface to be more complicated.

Why do we need four classes to read a text file one line at a time, but only one
class to read it like a byte array?

Contribution for Discussion Topic 3 — Complexity of ways of reading files

Java does not treat files as a special case for input of data. Files are treated as a sub-
category of byte streams, which might be input from a mouse, keyboard etc.
The extra classes are required to process the byte stream data in terms of
representations meaningful for files (such as characters, not bytes, and
recognising end-of-line characters etc.).

While for some files, such as a graphics image, a file can be treated in some random
fashion, many files are sequential, and therefore separators (like end-of-line) needs to be
read in sequence and processed appropriately.

Reflection on Learning Experience

In your Learning Journal write up your experience of your learning on this unit. Say what
you thought was good or bad, what you had difficulty understanding, and how you
resolved your problems.

Additional Content

Debugging technique — every class to have a main() method

A technique often used by Java developers working on large software projects is to write
a main() method for every class they write. Each main() method creates one or more
instance objects of the class, sends the object(s) some message(s) and displays the
changing state of the object(s).

In this way each individual class can be tested in isolation. For large software systems
this can help reduce bugs, or mean that they are found earlier, since it can be very difficult
debugging a system with many objects from many class.

Although for the programs you are developing for this module you probably do not need
to test each class in isolation (since it almost as easy to debug programs containing only
2 or 3 classes), an example is given here to illustrate this technique.

(Note - this is only appropriate for non-abstract classes).

Consider a simple applet to draw 2 triangles in its window. This applet makes use of a
class MyTriangle.

Let’s assume the output we want from the applet is as follows:


However, the output from the applet we have written is as follows:

The writer of our applet has made the mistake of forgetting that the origin of Java graphics
is the top left (i.e. the smaller the Y co-ordinate the higher up the screen a point is). The
writer of this applet can test that their MyTriangle class works in isolation as follows:
import java.awt.*;

class MyTriangle

// variables

public int top;

public int bottom;

public int left;

public int right;

// constructor method MyTriangle()

public MyTriangle(int newX, int newY, int height, int width)

left = newX;

right = (newX + width);


bottom = newY;

top = (newY + height);

// draw() method

public void draw( Graphics g )

g.drawLine( left, bottom, right, bottom);

g.drawLine( right, bottom, getMiddleX(), top);

g.drawLine(getMiddleX(), top, left, bottom);

// getMiddleX() - attribute that is calculated

public int getMiddleX()

return (int) ( (left + right) / 2 );

// main() method for debugging

public static void main( String args[] )

MyTriangle t = new MyTriangle(50, 50, 20, 10);

System.out.println( "------ test of MyTriangle -------");

System.out.println( "top = " + t.top );

System.out.println( "bottom = " + t.bottom );

System.out.println( "left = " + t.left );

System.out.println( "right = " + t.right );

System.out.println( "getMiddleX() = " + t.getMiddleX() );

} // class

We can run the main method of the MyTriangle class using the java command:
Had the programmer used such a method, they might have remembered that for Java
graphics the bottom of the triangle has a larger Y value than the top, which explains why
the triangle is draw with the point to the top of the screen. Even if they cannot remember
that, at least they now know the values of the variables forming arguments for
thedrawLine() messages and so on.

By the way, the code of an applet to produce such triangles is as follows:

import java.applet.Applet;

import java.awt.*;

public class TriangleApplet extends Applet

// variables

MyTriangle t1 = new MyTriangle(50,50,20,10);

MyTriangle t2 = new MyTriangle(100,50,50,40);


public void paint( Graphics g )

t1.draw( g );

t2.draw( g );

} // class

Which main() method is executed?

So if there are 2 (or more classes) and each has a main() method, how does Java decide
which main() method to execute?

The answer is that Java will execute the main method in the class youprovide
to the run-time interpreter.

So to run the main() method in MyTriangle, enter:

if there are several applications that have a main method, such as in client/server
applications. We will first run the application that is being used, then the second
application. The client program will attempt to access a server - use a server, therefore
the server program will run first.

Additional Activities

Additional Activity 1 — Loan example program

Compile and run the program Loan.java

Study the listing of this program and answer the questions in it.

Discussion/Suggested solution to Additional Activity 1

Loan example program


Answer to embedded question

If we throw a NegativeNotAllowedException at the point indicated, the next line to be


executed is:

resultLabel.setText(e.toString());

in method actionPerformed(). It is not the first line of the following ‘catch’ block,
because this only
catches NumberFormatExceptions. The NegativeNotAllowedException is thrown out of
the method getFieldValue(), and picked up by:

catch (Exception e)

in actionPerformed().

Remember that if we catch Exception objects, then we catch all subclasses of


Exception.

Answer to embedded question

The line indicated is inside a catch block that catches NumberFormatExceptions. The only
method that is called in the preceding try block is parseDouble(), so the exception must
come from there. If you look up parseDouble() in the on-line documentation, you will see
that it can indeed throw this exception.

Answer to embedded question

Because we are catching Exceptions (not its subclasses), then this section will be
executed if any exception is thrown by a statement in the preceding try block, or was
thrown upwards by any of the methods called inside the try block. The only method
called inside the try is getFieldValue(), so a line inside getFieldValue() must have
been executed immediately before this point. You will see that getFieldValue() can
throw for different
exceptions: EmptyNumberFieldException, NotANumberException , NegativeNotAllowedExc
eption, andZeroNotAllowedException. The lines that throw these exceptions are the
ones that caused:

catch (Exception e)

to be activated.

Additional Review Questions


The following reflective review questions are optional — however you may find they help
the consolidation of your knowledge of Java exception handling.

Reflective Question 1

In C and C++, there is no standard technique for handling exceptions. Different


programmers have used different methods as they saw fit. For example, one widely-
used technique is for each method to return a number, where the number indicates the
type of exception encountered. Another is to provide a class with an attribute that
indicates whether the last method was successful or not. Java provides a standardised
exception handling scheme, and all programmers are encouraged to use it. What
advantages does the Java exception scheme have over the C++ schemes?

Discussion of Reflective Question 1

First, the use of a standard exception handling scheme makes it easier to


combine classes written by different people or as part of different programs.
The programmer does not have to worry about finding out what method for
handling exceptions (if any) has been employed. Secondly, the Java scheme
forces the programmer to handle exceptions that require handling. The C/C++
schemes generally do not. This means that if a programmer is using code
written by someone else, he or she could easily overlook the handling of
exceptions that it might generate. Thirdly, the Java scheme is extensible. This
means that a programmer can create exceptions that are subclasses of built-
in extensions, or define entirely new ones, without compromising the
uniformity of the scheme.

Reflective Question 2

Most of the Java classes concerned with handling files use the standard Java exception
handling scheme. However, the ‘File’ class uses a different scheme (as well). Use the
Java documentation to find out what it is and how it works. What implications does this
have for the programmer when using this class?

Discussion of Reflective question 2


The methods in the File class mostly return a boolean value to indicate
whether they were successful or not. Normally ‘true’ means the method
completed successfully, while ‘false’ indicates that it did not. The problems
with this scheme are (1) the exact cause of the problem is difficult to define.
For example, when a file there are a number of reasons why this might not
succeed (access rights, a file with that name already exists, etc). (2) the
programmer may neglect to handle the problems that arise during these
methods, because the compiler does not insist that the boolean return value is
checked.

Reflective Question 3

If a method passes an exception upwards (that is, declares it as being thrown out of the
method), then the method that called the throwing method must itself catch the
exception. If this method in its turn throws the exception upwards, and all other methods
do the same, eventually we will reach the ‘top’ of the calling chain, and there will be
nowhere to ‘throw’ the exception. What will happen to the program then? Should the
compiler allow the programmer to define such a sequence of throws and, if so, what
happens when the exception reaches the ‘top’?

Discussion of Reflective Question 3

In practice and exception can be ‘thrown’ ‘out of the program’. For example, in a Java
application with a ‘main()’ method like this:

public static void main (String args[])

throws FileNotFoundException

//… some statements here

throw (new FileNotFoundException());

the FileNotFoundException will be thrown out of the program. The standard behaviour
when this happens is to terminate the program with an error message. Java did not
have to be organised like this, but ‘main’ is a method like other methods. No method
within the program calls main(), so the compiler does not have the opportunity to check
whether the thrown exception is caught anywhere. To change this behaviour would
mean that ‘main()’ has to be treated differently to other methods.
Optional Discussion topics

If you wish to study Java exceptions in more detail you may wish to reflect upon the
following 3 optional discussion topics.

Topic 1 — Why treat arithmetic and file not found exceptions differently?

In Java, FileNotFoundException is a subclass of Exception, which means that the


program must catch that exception and do something about it.
However,ArithmeticException is a subclass of RuntimeException , which means that the
program need not handle it. It could be argued that there is no reason
forArithmeticException to be treated any differently from FileNotFoundExceptions .

What reasons might there be for the Java developers’ imposing this distinction?

Do you think the decision was a sensible one?

Topic 2 — Level of monitoring of user input

A Java program should check that the data entered by the user is basically
sound. For example, if asked to enter a person’s age, it is probably incorrect
to enter ‘Fred Bloggs’. This is probably a mistake on the part of the user. On
the other hand, if the user enters ‘200’ for a person’s age this is probably a
mistake as well, but it is much harder for the programmer to detect. To what
extent should the programmer anticipate these kinds of user error?

What are the consequences of the following?

(a) very strict monitoring of the user’s input

(b) very little monitoring of the user’s input

Topic 3 — Throw objects or classes of exceptions?

Why does a Java program throw objects of exception classes, rather than classes
themselves?
Answer this question in two ways:

from a technical point of view

from a philosophical point of view.

End of Unit Review

You should work through this set of review questions. When you have
completed the questions you will be able to obtain the answers for future
reference.

Your performance with these questions will not affect your grade for the
module, but may be monitored so that your tutor can be alerted if you are
having difficulty.

Please contact your tutor if you feel you have not done as well as you
expected.
Now complete the end of unit review questions online.

Listing of DoNothing.java
/*

DoNothing.java

A stand-alone Java program that does nothing! This can be used as the outline

for a ‘real’ Java application

Kevin Boone, September 1999

*/

import java.awt.*;

import java.awt.event.*;

/*

MainWindow

This class defines the main window for the application. It is

defined to implement WindowListener so that it can receive


window events from the user interface

*/

class MainWindow extends Frame implements WindowListener

public MainWindow()

// In the constructor we set the size and caption of


// the

// window, and specify ‘this’ as the window listener

super("Do-nothing program");

setSize(300, 300);

addWindowListener (this);

// These methods are specified by the WindowListener


// interface so

// we must include them. However, they don’t do anything


// in this

// do-nothing program

public void windowClosed (WindowEvent e) {}

public void windowOpened (WindowEvent e) {}

public void windowDeiconified (WindowEvent e) {}

public void windowIconified (WindowEvent e) {}

public void windowDeactivated (WindowEvent e) {}

public void windowActivated (WindowEvent e) {}

/*

windowClosing

This method is called in response to a windowClosing event. It should

simply exit the program

*/

public void windowClosing (WindowEvent e)

System.exit(0);
}

} // class

/////////////////////////////////////////////////////////////////////

/*

DoNothing

This is the program’s primary class. All it does is supply a

‘main’ method which creates a new main window

*/

public class DoNothing

public static void main (String args[])

MainWindow mainWindow = new MainWindow();

mainWindow.setVisible(true);

Listing of CalculatorApp.java
/*

CalculatorApp.java

A stand-alone Java `Calculator’ program based on the Calculator

applet defined in Calculator.java. All this program does is

embed the applet in a Frame.

Kevin Boone, September 1999

*/

import java.applet.Applet;

import java.awt.*;

import java.awt.event.*;

/*

MainWindow
This class defines the main window for the application. It is

defined to implement WindowListener so that it can receive

window events from the user interface

*/

class MainWindow extends Frame implements WindowListener

public MainWindow()

// In the constructor we set the size and caption of the

// window, and specify `this’ as the window listener

super("Calculator");

setSize(300, 300);

addWindowListener (this);

add (new Calculator());

// These methods are specified by the WindowListener interface so

// we must include them. However, they don’t do anything in this

// program

public void windowClosed (WindowEvent e) {}

public void windowOpened (WindowEvent e) {}

public void windowDeiconified (WindowEvent e) {}

public void windowIconified (WindowEvent e) {}

public void windowDeactivated (WindowEvent e) {}

public void windowActivated (WindowEvent e) {}

/*

windowClosing

This method is called in response to a windowClosing event. It should

simply exit the program

*/

public void windowClosing (WindowEvent e)


{

System.exit(0);

} // class

////////////////////////////////////////////////////////////////////////

class Calculator extends Applet implements ActionListener, KeyListener

/*==============================================================================

Variables of Calculator class

==============================================================================*/

// MAX_INPUT_LENGTH is a constant indicating how large the number


// entered by

// the user can be. A Java `double’ can store a value with a
//precision of

// about 17 digits. Therefore there is no point in allowing the


// user to

// enter numbers any bigger than this.

final int MAX_INPUT_LENGTH = 17;

/*

Display modes

The variable `displayMode’ can take one of three values. For ease of reading

I have defined three constants to represent these values. It doesn’t matter

at all what the values of these constants are (I have used 0, 1 and 2), as

long as they are all different.

The displayMode variable indicates what is currently being displayed. It

will either be the number being entered by the user (INPUT_MODE), the

result of the last calculation (RESULT_MODE) or an error message

(ERROR_MODE). This variable is very important to the correct function of

the program. For example, if the user types a digit when the program is

in INPUT_MODE, the program should append the digit to the number

currently in the display. If in RESULT_MODE or ERROR_MODE, the display

should be cleared and the new digit put at the start. In fact,
many of the methods in this class behave differently according to the

value of displayMode

*/

// QUESTION: why have I defined constants for these values? In the program

// I write `if (displayMode == ERROR_MODE)’; why don’t I just write

// `if (displayMode == 2)’ ?

final int INPUT_MODE = 0;

final int RESULT_MODE = 1;

final int ERROR_MODE = 2;

int displayMode;

// displayLabel is the area of the applet in which all display will be


//shown.

// I have used a Java `Label’ object for this.

Label displayLabel;

// clearOnNextDigit is set to `true’ whenever an operator (`+’, `-’,


// etc) is

// typed. This causes the next digit entered to be the start of a new number.

boolean clearOnNextDigit;

// lastNumber is the number that was entered by the user before the
// last operator.

// for example, if the user type `2’ followed by `+’, then lastNumber
//will be

// set to `2’

double lastNumber;

// lastOperator is the operator last typed by the user. If the user


//types a

// `+’ sign (or clicks on the `+’ button), then lastOperator is set to

// ‘+’. This variable’s value is set to zero to indicate that no


//operator

// has been typed yet

char lastOperator;

/*==============================================================================

Calculator constructor

This operator (as with all constructors) is executed when the new object
is created. In this case we create all the buttons (and the panels that

contain them), then reset the calculator

The layout of buttons in this Applet is quite complex. We have three groups

of buttons, one for digits, one for operators and one for `controls’

(`=‘, `AC’ and `C’). I’m not sure `controls’ is the right word here, but

I couldn’t think of a better one. So we create three `Panel’ objects

to contain each group of buttons. A Panel is a blank screen area whose

job is simply to hold other objects. Associated with each Panel is a

layout manager. The job of the layout manager is to group the buttons in

the right order. For example, the button panel has a grid of buttons, with

four rows of three buttons like this:

7 8 9

4 5 6

1 2 3

. 0 +/-

So we set the layout manager for this panel to a new GridLayout object.

When we create the new GridLayout we specify `new GridLayout(4, 3)’

which means `create a new GridLayout with four rows of three columns’.

Having created the panels, we add the buttons. Finally we add all the

panels into a single panel (called `buttonPanel’) and add this to the

applet. We also add the display area.

==============================================================================*/

public Calculator()

super();

setLayout (new BorderLayout());

Panel buttonPanel = new Panel();

Panel numberPanel = new Panel();

numberPanel.setLayout(new GridLayout(4, 3));

addButtonToPanel (numberPanel, new Button("7"), Color.blue);


addButtonToPanel (numberPanel, new Button("8"), Color.blue);

addButtonToPanel (numberPanel, new Button("9"), Color.blue);

addButtonToPanel (numberPanel, new Button("4"), Color.blue);

addButtonToPanel (numberPanel, new Button("5"), Color.blue);

addButtonToPanel (numberPanel, new Button("6"), Color.blue);

addButtonToPanel (numberPanel, new Button("1"), Color.blue);

addButtonToPanel (numberPanel, new Button("2"), Color.blue);

addButtonToPanel (numberPanel, new Button("3"), Color.blue);

addButtonToPanel (numberPanel, new Button("."), Color.blue);

addButtonToPanel (numberPanel, new Button("0"), Color.blue);

addButtonToPanel (numberPanel, new Button("+/-"), Color.blue);

buttonPanel.add(numberPanel);

Panel operatorPanel = new Panel();

operatorPanel.setLayout(new GridLayout(4, 1));

addButtonToPanel (operatorPanel, new Button("/"), Color.green);

addButtonToPanel (operatorPanel, new Button("*"), Color.green);

addButtonToPanel (operatorPanel, new Button("-"), Color.green);

addButtonToPanel (operatorPanel, new Button("+"), Color.green);

buttonPanel.add(operatorPanel);

Panel controlPanel = new Panel();

controlPanel.setLayout(new GridLayout(4, 1));

addButtonToPanel (controlPanel, new Button("AC"), Color.cyan);

addButtonToPanel (controlPanel, new Button("C"), Color.cyan);

addButtonToPanel (controlPanel, new Button("="), Color.cyan);

buttonPanel.add(controlPanel);

displayLabel = new Label("");

displayLabel.setAlignment(Label.CENTER);

// QUESTION: what does `North’ mean here?

add(displayLabel, "North");

displayResult(0);
add(buttonPanel);

addKeyListener(this);

requestFocus();

// clearAll sets the variables of the Calculator object to

// initial values (this is the method that is called

// when the user clicks on the `AC’ button

clearAll();

/*==============================================================================

setDisplayString

This method sets the text in the display area to the specified string.

This hardly needs to be a method at all, as it is so simple. However,

it is called many many other methods, and using a method for this

function would make it much easier to modify the program if we chose a

different way to display data. Otherwise, a large number of lines would

have to be modified.

==============================================================================*/

void setDisplayString(String s)

displayLabel.setText(s);

/*==============================================================================

getDisplayString

This method gets the text currently in the display area. See the note for

`getDisplayString’ above for details.

==============================================================================*/

String getDisplayString ()

return displayLabel.getText();

}
/*==============================================================================

clearAll

Sets the state of the calculator to the `just switched on’ state, that is,

`0’ in the display, ready to input digits, and the last operator equal to

zero (that is, there is no last operator). This method is called by the

constructor to initialize the Calculator, and whenever the user

clicks on `AC’

==============================================================================*/

void clearAll()

setDisplayString("0");

lastOperator = 0;

lastNumber = 0;

displayMode = INPUT_MODE;

clearOnNextDigit = true;

/*==============================================================================

clearLastEntry

Clears the number currently in the display. This is called when the user

clicks on the `C’ button.

==============================================================================*/

void clearLastEntry()

setDisplayString("0");

clearOnNextDigit = true;

displayMode = INPUT_MODE;

/*==============================================================================

displayResult

Displays the specified number in the display area, and sets the variables to
indicate that a result is being displayed. Specifically this method sets

`clearOnNextDigit’ to `true’. This means that as soon as the user types

a digit, the display will be cleared to make space for a new number.

==============================================================================*/

void displayResult(double result)

setDisplayString(Double.toString(result));

lastNumber = result;

displayMode = RESULT_MODE;

clearOnNextDigit = true;

/*==============================================================================

displayError

Displays the specified error message in the display area, and sets the

variables to indicate that an error message is being displayed. Specifically

this method sets `clearOnNextDigit’ to `true’. This means that as soon

as the user types a digit, the display will be cleared to make space

for a new number.

The displayMode is set to ERROR_MODE to indicate that the display contains an

error message and not a number. This is important because the user might

press a button that modifies the current number (like `+/-’). Clearly

we can’t change the sign of an error message (or take its square root, etc).

==============================================================================*/

void displayError(String errorMessage)

setDisplayString(errorMessage);

lastNumber = 0;

displayMode = ERROR_MODE;

clearOnNextDigit = true;

}
/*==============================================================================

addButtonToPanel

This is a `convenience function’, that is, it exists simply to reduce the

number of lines in the program (and therefore make it more convenient for the

programmer to manage). This method is called by the constructor to add

a new button to the display. It sets the buttons colour, and sets the

key listener and action listener to the appropriate methods (this has

to be done for every button, as we can’t predict which button will have

the input focus at any given time).

==============================================================================*/

void addButtonToPanel(Panel panel, Button button, Color backgroundColour)

panel.add(button);

button.setBackground(backgroundColour);

button.addKeyListener(this);

button.addActionListener(this);

/*==============================================================================

actionPerformed

This method is called whenever the user clicks a button. This happens

because the method `addButtonToPanel’ calls `addActionListener’ for

every button. All this method does is pass on the text on the button to

`processButton’

==============================================================================*/

public void actionPerformed (ActionEvent e)

processButton(e.getActionCommand());

/*==============================================================================

processButton
This method takes action according to the user’s input. It is called from

two other methods: actionPerformed (when user clicks a button) and

keyPressed (when the user presses a key on the keyboard). This method

examines the text on the button (the argument `command’) and calls the

appropriate method to process it.

==============================================================================*/

void processButton(String command)

if (command.equals("0")) addDigit(0);

if (command.equals("1")) addDigit(1);

if (command.equals("2")) addDigit(2);

if (command.equals("3")) addDigit(3);

if (command.equals("4")) addDigit(4);

if (command.equals("5")) addDigit(5);

if (command.equals("6")) addDigit(6);

if (command.equals("7")) addDigit(7);

if (command.equals("8")) addDigit(8);

if (command.equals("9")) addDigit(9);

if (command.equals(".")) addDecimalPoint();

if (command.equals("*")) processOperator(‘*’);

if(command.equals("-")) processOperator(‘-’);

if (command.equals("/")) processOperator(‘/’);

if (command.equals("+")) processOperator(‘+’);

if (command.equals("=")) processEquals();

if (command.equals("+/-")) processSignChange();

if (command.equals("AC")) clearAll();

if (command.equals("C")) clearLastEntry();

/*==============================================================================

getNumberInDisplay
Returns a double value indicating the number in the display. This method

should never be called if the display does not contain a number. When an

error message is being displayed, the value of `displayMode’ is ERROR_MODE,

so this can be used to test whether the display contains a number.

This method is only necessary to make it easier in future if we decide to

represent data on the display in a different way (i.e., to use a different

object rather than `Label’)

==============================================================================*/

double getNumberInDisplay()

String input = displayLabel.getText();

return Double.parseDouble(input);

/*==============================================================================

processLastOperator

Carries out the arithmetic method specified by the last operator, the last

number and the number in the display.

If the operator causes an error condition (i.e., the user tries to divide

something by zero), this method can throw an execption.

==============================================================================*/

// QUESTION: if the user clicks on the buttons `2’, `+’ and `3’, what values

// will found in the variables `lastOperator’ and `lastNumber’, and the

// variable `numberInDisplay’?

double processLastOperator() throws DivideByZeroException

double result = 0;

double numberInDisplay = getNumberInDisplay();

switch (lastOperator)

case ‘*’:
result = lastNumber * numberInDisplay;

break;

case ‘+’:

result = lastNumber + numberInDisplay;

break;

case ‘-’:

result = lastNumber - numberInDisplay;

break;

case ‘/’:

if (numberInDisplay == 0)

throw (new DivideByZeroException());

result = lastNumber / numberInDisplay;

break;

return result;

/*==============================================================================

processOperator

Processes the operator most recently typed. All we do is evalute the

_last_ operator typed (not this one), and store this current variable

is `lastOperator’ so it will get processed when the user types another

operator, or `=‘.

==============================================================================*/

void processOperator(char op)

if (displayMode != ERROR_MODE)

double numberInDisplay = getNumberInDisplay();

if (lastOperator != 0)

{
try

double result = processLastOperator();

displayResult(result);

lastNumber = result;

catch (DivideByZeroException e)

displayError("Division by zero!");

else

lastNumber = numberInDisplay;

clearOnNextDigit = true;

lastOperator = op;

/*==============================================================================

processEquals

Deals with the user clicking the `=‘ button. This method finishes the

most recent calculator. If the displayMode is `ERROR_MODE’ (that is, the

display contains an error message) this method should not do anything.

==============================================================================*/

void processEquals()

if (displayMode != ERROR_MODE)
{

try

double result = processLastOperator();

displayResult(result);

catch (DivideByZeroException e)

displayError("Division by zero!");

lastOperator = 0;

/*==============================================================================

processSignChange

This method is called when the user clicks on the `+/-’ (sign change)

button. If the number in the display is negative it is converted to positive.

If the number in the display is positive it is converted to negative. If

the number in the display is zero, nothing happens (as `-0’ is meaningless).

This method behaves slightly differently depending on what mode the

display is in. If the user is currently entering a number, then it looks

at the _string_ in the display. If it is displaying a result it looks at

the _number_ in the display.

==============================================================================*/

// QUESTION: Why is this? Why does this method have to behave differently

// depending on whether a result or a new number is in the display? Hint: it

// is quite a subtle problem. The program would work correctly most of the

// time if we always treated the display as a number.

void processSignChange()

{
if (displayMode == INPUT_MODE)

String input = getDisplayString();

if (input.length() > 0)

if (input.indexOf("-") == 0)

setDisplayString(input.substring(1));

else

setDisplayString("-" + input);

else if (displayMode == RESULT_MODE)

double numberInDisplay = getNumberInDisplay();

if (numberInDisplay != 0)

displayResult(-numberInDisplay);

// If displayMode is `ERROR_MODE’ then this method should have no

// effect (because you can’t change the sign of an error message!)

/*==============================================================================

addDigit

This method is called when the user clicks a digit button, or types a

digit key. If the number currently being entered is less than 17 digits long,

then it adds the new digit to the end of the display.

==============================================================================*/

void addDigit(int digit)

// QUESTION: what are the next two lines for?

if (clearOnNextDigit)
setDisplayString("");

// We have to be careful to prevent the user entering ugly numbers

// like `000’. If the number in the display is `0’, and the user

// clicks on `0’, this display is not changed.

String inputString = getDisplayString();

if ((!inputString.equals("0") || digit > 0) && inputString.length() < MAX_INPUT_LENGTH)

setDisplayString(inputString + digit);

displayMode = INPUT_MODE;

clearOnNextDigit = false;

/*==============================================================================

addDecimalPoint

Called when the user clicks on the decimal point button. Puts a decimal

point on the end of the number currently being entered. If the number

already contains a decimal point, this method should do nothing

(that is, it should be impossible to enter a number like `1.2.3’

==============================================================================*/

void addDecimalPoint()

displayMode = INPUT_MODE;

if (clearOnNextDigit)

setDisplayString("");

String inputString = getDisplayString();

// If the input string already contains a decimal point, don’t

// do anything to it.

if (inputString.indexOf(".") < 0)

setDisplayString(new String(inputString + "."));

}
/*==============================================================================

keyPressed

This method is called when the user presses a key, when any button has the

input focus. This happens because the method `addButtonToPanel’ calls

`addKeyboardListener’ for each button that it knows about. However,

this method does nothing in this program, as keyboard input is handled

in the method `keyTyped’. Because this applet is defined to `implement

KeyEventHandler’ we have to provide this method, even if it does

nothing.

==============================================================================*/

public void keyPressed(KeyEvent e)

/*==============================================================================

keyReleased

Called automatically whenever the user presses and then releases a key. See

note for `keyPressed’ for details

==============================================================================*/

public void keyReleased(KeyEvent e)

/*==============================================================================

keyTyped

This method is called when the user presses a key, and then releases it

when any button has the input focus. This happens because the method

`addButtonToPanel’ calls `addKeyboardListener’ for each button thait knows

about.

This method converts the key press to the text of the corresponding button,

then passes it to processButton to process. For example, if the user

presses `enter’, this should have the same effect as clicking `=‘. So this
method calls `processButton’ with the text `=‘. If the user

presses `escape’ this should be treated the same as the `C’ button. All other

keys are treated as digits. If the user presses a letter rather than

a digit, it will still be passed to `processButton’, but processButton

will ignore it.

==============================================================================*/

public void keyTyped(KeyEvent e)

String command;

char keyChar = e.getKeyChar();

if (keyChar == KeyEvent.VK_ENTER)

command = new String("=");

else if (keyChar == KeyEvent.VK_ESCAPE)

command = new String("C");

else

/// QUESTION: what do these next two lines do?

byte bytes[] = {(byte)keyChar};

command = new String(bytes);

processButton(command);

} // class

/*==============================================================================

DivideByZeroException class

This class is used to indicate that the user has tried to divide a number

by zero (which is, of course, impossible. The Calculator applet should

respond by displaying an error message


The issue of exception handling is covered in more detail later in the

module; don’t worry if it doesn’t make much sense at the moment.

==============================================================================*/

class DivideByZeroException extends Exception

DivideByZeroException()

super("Divide by zero");

/*

CalculatorApp

This is the program’s primary class. All it does is supply a

`main’ method which creates a new main window

*/

public class CalculatorApp

public static void main (String args[])

MainWindow mainWindow = new MainWindow();

mainWindow.setVisible(true);

Listing of Loan.java
/*=======================================

Loan.java
This applet calculates the time it would take to repay a loan of money, when

interest is being charged. For example, if I borrow £1 million, and I pay

back £100,000 every year, how long will it take to pay off the whole loan?

If we can answer this question, it is very easy to answer another important

question: how much do I pay in total, including interest?

This applet calculate both these figures, from the user’s figures for

amount borrowed, interest rate and repayment amount. It doesn’t matter

what units of currency are used, as long as you are consistent (i.e.,

the repayment amount and the amount borrowed are in the same currency).

The interest rate should be entered as a percentage.

The programs’s display looks like this:

<img src=loan.gif>

<p>

(If you aren’t looking at the HTML version of this file, you won’t see

the picture)

The user should enter the appropriate figures, then click on `Calculate’

to get the results.

This is a good program for demonstrating Java’s exception handling

mechanisms, as there’s any number of things that can go wrong in this

program. For example:

1. The user may not fill all the data entry fields in

2. The user may enter values which are not numbers at all (e.g., text)

3. The user may enter values which are valid numbers, but are nonetheless

invalid in the context of this application (e.g., repayments of zero)

4. The values may all be sensible, but it is still impossible to get

a sensible result. This will happen if the amount of the repayment

is less than the interest on the loan (then the loan will never be

repayed)

A good program will deal correctly with all these problems, and produce

sensible guidance to the user in each case. It is never acceptable in


modern practice for a program to say `INVALID DATA’ and shut down!

You will notice that in this application approximately half the code

is concerned with checking and handling errors. But the good thing about the

exception throwing scheme is that the `normal’ program code and the

`error’ program code is largely separate. In this program, the exception

classes are all defined after the main part of the program

Please note that I am not an accountant, so I can’t be sure that my

repayment calculations are correct!

Kevin Boone, July 1999

==============================================================================*/

import java.applet.Applet;

import java.awt.*;

import java.awt.event.*;

/*==============================================================================

Loan class

Defines a sub-type of applet that implements a loan calculator

==============================================================================*/

public class Loan extends Applet implements ActionListener

/*==============================================================================

Attributes of Loan class

==============================================================================*/

// We store the objects that correspond to data entry fields as attributes,

// as when the user starts a calculation we will need to refer to them

// to get the data out

TextField amountBorrowedField;

TextField interestRateField;

TextField repaymentField;

// The result label is that part of the display where the result will be

// displayed
Label resultLabel;

/*==============================================================================

Loan constructor

This method (as with all constructors) is executed when the new object

is created.

The applet’s display area has three main parts; from top to bottom these

are: the result display, the data entry area, and the `calculate’

button. The data entry area has three text areas and the corresponding

labels. This part is organized as a grid of 3 rows and 2 columns.

The main display is organized as a BorderLayout. The data entry area

will go in the centre of this area, the result area at the top

(`North’) and the calculate button at the bottom (`South’).

==============================================================================*/

public Loan()

super();

Panel entryPanel = new Panel();

entryPanel.setLayout (new GridLayout(3, 2));

Label l = new Label ("Amount borrowed:");

l.setAlignment (Label.RIGHT);

entryPanel.add(l);

amountBorrowedField = new TextField();

entryPanel.add(amountBorrowedField);

l = new Label ("Interest rate (%):");

l.setAlignment (Label.RIGHT);

entryPanel.add(l);

interestRateField = new TextField();

entryPanel.add(interestRateField);

l = new Label ("Repayment:");

l.setAlignment (Label.RIGHT);
entryPanel.add(l);

repaymentField = new TextField();

entryPanel.add(repaymentField);

setLayout(new BorderLayout());

add(entryPanel, "Center");

resultLabel = new Label("?");

resultLabel.setAlignment(Label.CENTER);

add(resultLabel, "North");

Button calculateButton = new Button("Calculate");

calculateButton.addActionListener(this);

add(calculateButton , "South");

/*==============================================================================

getFieldValue

This method attempts to get a numerical value from a specified data entry

field. If this cannot be accomplished, for any reason, it throws an exception

to indicate the reason. The caller of this method is responsible for

dealing with the exception if one arrives.

This method has three arguments. The first, `field’ is the data entry

field itself. This will have been created in the constructor with a

call to `new TextField()’. The second is the name of the field. This name will

be saved in the exception if anything goes wrong, so that the exception can

display an error message indicating where the error occured. Finally

`zeroAllowed’ is `true’ if it is meaningful for the data entry field to have

`zero’ as its value. In this application, the interest rate can meaningfully

be zero, but none of the other fields can

==============================================================================*/

double getFieldValue (TextField field, String fieldName, boolean zeroAllowed)

throws EmptyNumberFieldException,

NotANumberException,
NegativeNotAllowedException,

ZeroNotAllowedException

// First get the text value out of the data entry fieinto a

// String.

String stringValue = field.getText();

// Is the data entry field empty? If so, throw an

// EmptyNumberFieldExceptino. Note that the name of the field is

// passed to the exception’s constructor, so that it can be stored

// and used in error messages

if (stringValue.equals(""))

throw (new EmptyNumberFieldException(fieldName));

try

// Now try to convert the string to a double value.

// If this fails (e.g., if the data is not a number), then

// a NumberFormatException will be thown. We will catch

// that exception, and convert it to a NotANumberException.

// The main reason for doing this is that the built-in

// NumberFormatException displays a very ugly and unhelpful

// error messages, which we can improve upon easily.

double value = Double.parseDouble(stringValue);

// If the value is negative, throw and NegativeNotAllowedException

/// QUESTION: if we do throw a NegativeNotAllowedException, what is

/// the _next_ line of program that will be executed?

if (value < 0) throw (new NegativeNotAllowedException(fieldName));

// If the value is zero, and it is not allowed to be, throw a

// zeroNotAllowedException.

if (value == 0.0 && !zeroAllowed) throw (new ZeroNotAllowedException(fieldName));


return value;

catch(NumberFormatException e)

/// QUESTION: what line of program was executed immediately

/// before this one?

throw (new NotANumberException(fieldName, stringValue));

/*==============================================================================

calculateNumberOfRepayments

This method calculates the number of repayments, given the specified

amount, repayment and interest rate. Note that the final repayment may

not be of the full amount, as by this point there may be less money owing than

the size of the repayment.

This method can throw a `NeverRepayException’ if it detects that the

amount of the repayment is not large enough to pay the loan at all

==============================================================================*/

public int calculateNumberOfRepayments (double amountBorrowed, double interestRate,

double repayment)

throws NeverRepayException

int repayments = 0;

double sumOutstanding = amountBorrowed;

while (sumOutstanding > 0)

// Add the interest to the remaining balance

double newSumOutstanding = sumOutstanding +

sumOutstanding * interestRate / 100.0;


// Now subtract the repayment

newSumOutstanding = newSumOutstanding - repayment;

// See if the amount has gone down; if not, the

// loan will never be repayed

if (newSumOutstanding >= sumOutstanding)

throw (new NeverRepayException());

// For each repayment, add one to the number of repayments

repayments++;

// So the new balance becomes the input to the next cycle, and

// so on, until the whole sum is repayed.

sumOutstanding = newSumOutstanding;

return repayments;

/*==============================================================================

actionPerformed

This method is called whenever the user clicks a button. Since there is

only one button, and no menus, we can assume that when this method is

called, it is because the user has clicked `calculate’ and wants to calculate

a result

==============================================================================*/

public void actionPerformed (ActionEvent actionEvent)

//RepaymentCalculator = new RepaymentCalculator();

try

double amountBorrowed = getFieldValue (amountBorrowedField, "Amount", false);

double interestRate = getFieldValue (interestRateField, "Interest rate", true);

double repayment = getFieldValue (repaymentField, "Repayment", false);

// If we get this far, the values for amount borrowed, interest rate,
// and repayment amount have been entered, and they are basically

// sensible. So now we can try to calculate the repayment time

// and repayment amount. Of course, this can still go wrong,

// as the amount of repayment may not be sufficient to pay

// the loan however long it is repayed over

int numberOfRepayments = calculateNumberOfRepayments

(amountBorrowed, interestRate, repayment);

double totalRepayment = numberOfRepayments * repayment;

resultLabel.setText ("" + numberOfRepayments + " repayments, repaying "

+ totalRepayment + " in total");

catch (Exception e)

/// QUESTION: there are four lines of prgram that could have been

/// executed before this one. What are they?

resultLabel.setText(e.toString());

/// QUESTION: this program can generate two `type’ of exception:

/// NeverRepayedException, and all the sub-classes of

/// BadValueEnteredException. As these are all subclasses of

/// Exception, the line of program above will `catch’ all of

/// them. However, I may want to treat these two `types’ of

/// exception differently. How could I change this piece of

/// the program slightly to make that possible (hint: we

/// only need to add a few lines)

} // class

/*==============================================================================
This is the end of the `Loan’ class. We now define all the classes that

are used for exception handling

In general each of these classes only has two methods: a constructor and

a method `toString’. By convention the `toString’ method is used to

supply an error message. So when the program catches an exception, it calls

the exception’s toString() method to generate an error message. The

constructor is used to set values for any of the data that will be stored in

the exception, usually for inclusion in the error message.

==============================================================================*/

/*==============================================================================

NeverRepayException

This exception is thrown by calculateNumberOfRepayments when it detects that

the amount of the repayment is not large enought to pay off the loan in

any length of time

==============================================================================*/

class NeverRepayException extends Exception

// constructor

NeverRepayException()

super("NeverRepayException");

// toString

// Displays the error message appropriate for this exception

public String toString()

return new String("Repayment is not large enough; loan never repayed");

} // class
/*==============================================================================

BadValueEnteredException

This is the base class for all the exceptions that are concerned with the

user entering invalid data values. Note that this is an abstract class; this

exception can never be thrown. The program must created one of the subclasses

of this class and throw that instead. This class is used for grouping the

sub-classes in a coherent way

==============================================================================*/

/// QUESTION: why does this class have two constructors?

abstract class BadValueEnteredException extends Exception

String fieldName;

String fieldValue;

// constructor

BadValueEnteredException(String _fieldName)

super("Bad number value entered");

fieldName = _fieldName;

// constructor

BadValueEnteredException(String _fieldName, String _fieldValue)

super("Bad number value entered");

fieldName = _fieldName;

fieldValue = _fieldValue;

} // class

/*==============================================================================

EmptyNumberFieldException
This exception is thrown if the user leaves a data entry field blank.

==============================================================================*/

class EmptyNumberFieldException extends BadValueEnteredException

// constructor

EmptyNumberFieldException(String fieldName)

super(fieldName);

// toString

// Displays the error message appropriate for this exception

public String toString()

return new String("No value entered for `" + fieldName + "‘");

} // class

/*==============================================================================

ZeroNotAllowedException

This exception is thrown when the user enters a value that is zero, and zero

is not a meaningful entry. For example, is meaningless to make a repayment

of `0’, or to borrow `0’. Note, however, that `0’ is a credible value for the

interest rate

==============================================================================*/

class ZeroNotAllowedException extends BadValueEnteredException

// constructor

ZeroNotAllowedException(String fieldName)

super(fieldName);
}

// toString

// Displays the error message appropriate for this exception

public String toString()

return new String("`" + fieldName + "‘ cannot be zero");

} // class

/*==============================================================================

NegativeNotAllowedException

This exception is thrown when the user enters a value that is negative

In this program, it is not meaningful for any field to have a negative value

==============================================================================*/

class NegativeNotAllowedException extends BadValueEnteredException

// constructor

NegativeNotAllowedException(String fieldName)

super(fieldName);

// toString

// Displays the error message appropriate for this exception

public String toString()

return new String("`" + fieldName + "‘ cannot be negative");

} // class

/*==============================================================================
NotANumberException

==============================================================================*/

class NotANumberException extends BadValueEnteredException

// constructor

NotANumberException(String fieldName, String fieldValue)

super(fieldName, fieldValue);

// toString

// Displays the error message appropriate for this exception

public String toString()

return new String("Value entered for `"

+ fieldName + "‘ (" + fieldValue + ") is not a number");

} // class

Listing of WebMerge.java
/*

WebMerge.java

This is an example of a complete, simple Java application, that may even be

useful. Its purpose is to merge a set of HTML (World-Wide Web documents)

so that a consistent style is applied to all of them.

This program does not have a graphical user interface; it is so simple that

it does not need one. It is designed to be run from the command prompt, by

typing a command something like

java WebMerge mysite.html page1.html page2.html page3.html...

When used this way, the file `mysite.html’ will be treated as the `template’

file. This file will form the background for all the other files. Somewhere
in this should be the string `%%CONTENT%%’. This string will be replaced

by each of the other web pages `page1.html’, `page2.html’,... In the process

a new set of file will be written, in a directory whose name is the same

as the template file. So the example above will write a new set of files

called `page1.html’ etc, in a directory called `mysite’.

If the specified pages have their own specifications of background colour, or

background image, this information is removed, and replaced with whatever

was specified in the template. In other words, the program looks for the

`body’ section of each HTML file and extracts it.

This program demonstrates two simple methods for managing data files in

Java, both using the `FileInputStream’ and `FileOutputStream’ classes.

In the operation `readFile’, the data file is read into a string one

character at a time. In `writeFile’ a whole block of data is written

in one go. Note that FileInputStream and FileOutputStream allow only

these simple operations on files, that is, reading and writing fixed

numbers of bytes of data. For more sophisticated file processing, one

might prefer to use classes like DataInputStream.

Kevin Boone, June 1999

*/

import java.io.*;

public class WebMerge

public static void main (String args[])

// `args’ is an array of strings that corresponds to the information the user

// specified on the command line. `args[0]’ is the first item on the

// command line, `args[1]’ is the second, and so on. In this program the

// user must specify at least two things: the template file and one file

// to process. So args.length must be at least 2 to continue.

if (args.length < 2)
{

System.err.println

("You are using this program incorrectly. You must specify the");

System.err.println

("template HTML file and the input HTML files on the command line");

System.exit(-1);

// In Java, a File object represents the name of a file or directory. When we need

// read or write a file, the FileInputStream and FileOutputStream classes will

// expect to be given a File object that represents the file to process

File templateFile = new File(args[0]);

/// QUESTION: what does it mean if `canRead’ returns the value `false’?

if (!templateFile.canRead())

// This file can’t be read: no point to carrying on

System.err.println("Can’t read template file `" + templateFile + "‘");

System.exit(-1);

// The name for the new directory is given by the filename of the template file,

// with the `.html’ suffix stripped off. So we will inspect the filename to

// check that it ends in .html, and if it does make the directory name

int htmlSuffixPosition = templateFile.toString().lastIndexOf(".html");

if (htmlSuffixPosition < 0)

// The name of the template file does not end in `.html’

System.err.println("Filename `" + templateFile + "‘ does not end in `.html’");

System.exit(-1);

/// QUESTION: what would happen if the user specied a filename like `fred.html.xyz’?

/// Would the program work, and what would the new directory end up being called?
String directoryName = new String

(templateFile.toString().substring(0, htmlSuffixPosition));

// If the directory has been created already, we don’t need to do anything (but

// warn the user). If it hasn’t, create it now

// Note that Java uses the same class `File’ to represent the name of either

// at file, or a directory.

/// QUESTION: is it possible to construct a new File object so that it’s name

/// corresponds to a file that does not exist?

File directory = new File(directoryName);

if (directory.isDirectory())

System.out.println("Directory `" + directoryName + "‘ already exists");

else

// Create the directory

if (directory.mkdir())

System.out.println("`" + directoryName + "‘ created");

else

// The name of the template file does not end in `.html’

System.err.println("Directory `" + directoryName

+ "‘ did not exist and could not be created");

System.exit(-1);

// As we will use the data in the template many times (if the user specifies many

// files on the command line), we will read the data from that file into a

// String at this stage, and then work with the String. This means we only

// have to read the template file once


String templateString = readFile(templateFile);

// So now we will process the user-specified files, one at a time. The operation

// `processFile’ will be called to do this

for (int i = 1; i < args.length; i++)

String inputFilename = new String(args[i]);

/// QUESTION: what does the line below do?

String outputFilename = new String(directoryName + "/" + inputFilename);

processFile (templateString, inputFilename, outputFilename);

/*

processFile

This operation takes the template file and one input file, and merges the

two into a new file.

Parameters:

templateString a String containing the text of the template file

inputFilename the HTML file to read

outputFilename the new file to write

*/

public static void processFile (String templateString, String inputFilename,

String outputFilename)

System.out.println ("processing file `" + inputFilename

+ "‘ to file `" + outputFilename + "‘");

File inputFile = new File(inputFilename);

File outputFile = new File(outputFilename);

if (!inputFile.canRead())

{
// This file can’t be read: no point to carrying on

System.err.println("Can’t read input file `"

+ inputFilename + "‘");

return;

// Get the text of the input file into a string for processing

/// QUESTION: suppose the input file were several megabyte long.

/// Do you think that reading the whole file into a string would

/// be sensible?

StrininputString = readFile(inputFile);

// Later we will want to write the new file to disk. Before we try

// this, we need to ensure that the file can be written. So if

// there is already a file with the same name, check that it

// can be written

if (outputFile.exists() && !outputFile.canWrite())

// This file can’t be written: no point to carrying on

System.err.println("Can’t write output file `"

+ outputFilename + "‘");

return;

// At this point, we have the input file in a String called `inputString’

// and we think the output file can probably be written. Now we

// must extract the `body’ of the Web page from inputString.

// The `body’ is between the HTML tags `body’ and `/body’. If these

// tags can’t be found in the file, then take the whole file as

// input.

int bodyTagPos = inputString.indexOf ("<body");

if (bodyTagPos < 0) bodyTagPos = inputString.indexOf ("<BODY");

if (bodyTagPos >= 0)
{

inputString = inputString.substring (bodyTagPos + 1);

bodyTagPos = inputString.indexOf(">");

if (bodyTagPos >= 0) inputString = inputString.substring (bodyTagPos + 1);

bodyTagPos = inputString.indexOf ("</body");

if (bodyTagPos < 0) bodyTagPos = inputString.indexOf ("</BODY");

if (bodyTagPos >= 0) inputString = inputString.substring (0, bodyTagPos);

// So now, `inputString’ contains the `body’ of the Web page. Now we look for

// the tag `%%CONTENT%%’ in the template, and replace this tag with the

// complete Web page body.

int templateTagPos = templateString.indexOf ("%%CONTENT%%");

if (templateTagPos < 0)

System.err.println("The template file does not contain the text");

System.err.println("`%%CONTENT%%’, so the Web page can’t be merged in");

return;

// Make a new string that contains the template data up to `%%CONTNENT%%’, plus

// the `body’ of the input file, plus the remainer of the template file

templateString = templateString.substring(0, templateTagPos)

+ inputString

+ templateString.substring(templateTagPos + 11);

// Write this file to disk, and the job’s done.

if (!writeFile (outputFile, templateString))

System.err.println("Can’t write file `" + outputFilename + "‘");

/*

readFile
This operation reads a file and returns its contents as a string.

If there is any problem, it stop the program. This is very ugly,

but adequate for this simple program. The caller of this

operation should check that the file is readble before calling.

Paramters:

file The file object that contains the name of the file to read

Returns:

A string whose characters correspond to the bytes in the file

*/

public static String readFile(File file)

String s = new String("");

try

/// QUESTION: what does the operation `available()’ do?

FileInputStream inputStream = new FileInputStream(file.toString());

while (inputStream.available() > 0)

s = s + (char)inputStream.read();

catch (FileNotFoundException e)

System.err.println(e.toString());

System.exit(-1);

catch (IOException e)

System.err.println(e.toString());

System.exit(-1);
}

return s;

/*

writeFile

This operation writes the specified string of text to the specified

file. It returns a `true’ or `false’ value to indicate whether

the operation was successful or not

Paramters:

file The file object that contains the name of the file to read

text A string containing the text to write to the file

Returns:

The value `true’ if the file was written successfully, or false

otherwise

*/

public static boolean writeFile(File file, String text)

try

FileOutputStream outputStream = new FileOutputStream(file.toString());

byte textBytes[] = text.getBytes();

outputStream.write(textBytes, 0, textBytes.length);

catch (IOException e)

return false;

return true;

}
Listing of Exception2.java
import javax.swing.*;

public class Exception2

public static void main( String args[] )

String ageString;

int age;

System.out.println("Age parsing application");

ageString = JOptionPane.showInputDialog(null, "Enter age (1-100)", "Entry of age",

JOptionPane.QUESTION_MESSAGE);

try

age = Integer.parseInt( ageString );

int ageNextBirthday = (age + 1);

System.out.println("Age now : " + age);

System.out.println("Age next birthday: " + ageNextBirthday);

catch (NumberFormatException n)

System.out.println("sorry - your age entry of ‘" + ageString + "‘ is not

a valid integer");

System.exit(0);

} // class

You might also like