Java Way 11
Java Way 11
All Rights Reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by
any means, electronic, mechanical, photocopying, recording, scanning or otherwise, except under the terms of the Copyright,
Designs and Patents Act 1988 or under the terms of a licence issued by the Copyright Licensing Agency Ltd, 90 Tottenham Court
Road, London, UK W1P OLP, without the permission in writing of the Publisher with the exception of any material supplied
specifically for the purpose of being entered and executed on a computer system for exclusive use by the purchaser of the
publication.
Neither the authors nor John Wiley & Sons, Ltd accept any responsibility or liability for loss or damage occasioned to any person
or property through using the material, instructions, methods or ideas contained herein, or acting or refraining from acting as a
result of such use. The authors and publisher expressly disclaim all implied warranties, including merchantability or fitness for
any particular purpose. There will be no duty on the authors or publisher to correct any errors or defects in the software.
Designations used by companies to distinguish their products are often claimed as trademarks. In all instances where John Wiley
& Sons, Ltd is aware of a claim, the product names appear in capital or all capital letters. Readers, however, should contact the
appropriate companies for more complete information regarding trademarks and registration.
A catalogue record for this book is available from the British Library
1 Introduction 1
1.1 Preliminaries for Reading This Book 2
1.2 Contemplating a Computer 3
1.3 Java Applications and Java Applets 5
1.4 JavaScript and JSP 6
1.5 How This Book is Structured 7
1.6 A Small Example Program 9
1.7 Examples of Applets 15
1.8 New Concepts in This Chapter 17
1.9 Review Problems 19
1.10 Programming Problems 20
2 Variables, Data Types, and Expressions 21
2.1 Example 22
2.2 Data and Variables 22
2.3 Algorithms, Programming Errors, and Test Data 26
2.4 Statements, Blocks, and Names 28
2.5 Variables and Constants 30
2.6 Data Types 34
2.7 Assignments and Arithmetical Expressions 40
2.8 Type Conversion 43
2.9 Calculations for Our Renovation Project 45
2.10 New Concepts in This Chapter 47
2.11 Review Problems 49
2.12 Programming Problems 49
3 Using Ready-Made Classes 51
3.1 Objects as Models of Reality 52
3.2 Using Ready-Made Classes 55
3.3 The Random Class 60
3.4 The String Class 63
3.5 Organizing Classes in Packages 70
3.6 Class Methods and Class Constants in the Java Library 71
3.7 Reading Data from the User 73
3.8 New Concepts in This Chapter 77
3.9 Review Problems 79
3.10 Programming Problems 79
4 Constructing Your Own Classes 81
4.1 Creating Classes 82
4.2 Programming a Class 85
4.3 Access Modifiers - Private and Public 91
Contents
16 Threads 499
16.1 Threads in Processes 500
16.2 Dividing Time Between Threads 502
16.3 Example of Threads in Use 503
16.4 Thread States 507
16.5 Communication Between Threads 508
16.6 Locks and Synchronization 510
16.7 More Control: wait(), notify(), and notifyAll() 515
16.8 Peeking at the Threads with JDB 519
16.9 New Concepts in This Chapter 521
16.10 Review Problems 522
16.11 Programming Problem 522
Appendices
A Using Java SDK and WinEdit 699
A.1 SDK 699
A.2 Running Applets 703
A.3 WinEdit 703
B Keywords 705
C Number Systems 707
D The Unicode Character Set 711
E HTML and Applets 713
F Exceptions to the Code Standard 717
References 719
Index 721
This textbook was designed for higher education in technological fields where Java
and object-orientation form the basis of programming education. This book covers
both basic and more advanced programming.
The book assumes a general familiarity with computers, operating systems, and
the most common tools (such as, for example, word processors and browsers).
Readers should be familiar with concepts like "file" and "directory" and know the
difference between internal memory (RAM) and storage (for example, the hard
disk).
A foundation in object-orientation
When using Java as an educational language, it makes sense for readers to deal with
object-oriented ways of thinking as soon as possible. To a large extent, modern
programming consists of using ready-made components and classes. It's possible
to make a Java program that draws geometric figures, displays images, and plays
sound files without using anything more complicated than sequential control
structure. We believe that graphics and graphical user interfaces will motivate
further study into both object-orientation and programming in general, more so
than difficult control structures and textual user interfaces.
Readers will be introduced to the Java API for the first time in chapter 3. We'll
introduce the standard JOptionPane class which makes it possible to create
programs with primitive graphical user interfaces. We'll also use the Random and
String classes. This will teach readers to use ready-made classes and at the same
time provide a general introduction to object-oriented ways of thinking.
Once readers have used ready-made classes, we believe they will want to find out
what these classes look like inside. We devote quite a bit of space to creating our
own classes, a broad and comprehensive topic. In chapter 4, the readers will get to
create their own applets with simple geometrical figures where they can control the
shape, colors, and fonts themselves.
With this as a foundation, more classes follow to demonstrate the need for
selection and loop control structures.
Preface
Software
The software necessary for writing Java programs can be downloaded free from the
Internet. This book builds on the Java 2 SDK. The SDK is available on Sun's Web
pages (http://java.sun.com/). This book explains how the package is used. In
addition, you'll need a good editor. Alternatively, you can use an integrated
development environment, for example JBuilder Foundation, which you can get
from Borland's pages on the Internet (http://www.borland.com/jbuilder/).
To develop dynamic Web pages with JavaServer Pages (chapter 21), the reader
needs a web server. The book gives instructions on installation and use of a free
web server, LiteWebServer from http://www.gefionsoftware.com/.
Teaching aids
The book includes several teaching aids: every chapter starts with the chapter's
learning goals and ends with a list of the new concepts introduced, review
problems, and more involved programming problems. In addition, most
subchapters end with shorter problems, where the reader is encouraged to actively
work with the material that was just covered.
The book's Internet page (see above) includes a set of overheads that go with
each chapter. The overheads are based primarily on the book, but also contain
some examples and figures not found in the book.
Preface
Intermediate topics
This part of the book will prepare readers to make comprehensive programs with
graphical user interfaces. This requires extensive use of the Java API and a thorough
understanding of the concepts in an object-oriented system (such as associations
and generalizations, for example).
Arrays of reference types are essentially different in their structure and behavior
from arrays of primitive data types. Therefore, we've chosen to treat these in a
separate chapter along with the ArrayList class, which is a class that hides
reference arrays with dynamic lengths. For many practical purposes, this class is
better suited than an ordinary array of reference type. Chapter 10 also covers classes
with prepared sort-and-search methods including classes that make it possible to
take a country's character sets into consideration.
Chapter 10 introduces further relationships between objects in the form of
associations. We emphasize a demonstration of the transition from class diagram
to program code.
Chapter 11 deals with communication between programs and data files. The
chapter covers both text and binary transfers as well as direct access to a file.
Serialization is a simple, but very useful technique that we'll cover here.
Chapter 12 deals with some of the more important topics in object-orientation,
namely inheritance and polymorphism. Modeling is important here. Readers will
learn the difference between association and generalization. It's important to
thoroughly understand the conceptual apparatus to program inheritance correctly.
With a solid foundation in object-oriented programming, readers should now
be in a position to understand the event model used to program graphical user
interfaces in Java. Chapters 1315 cover this topic. The most common graphical
components are covered and emphasis is placed on distinguishing the classes that
describe the problem to be solved from the classes that describe the user interface.
Readers will create both applets and applications.
comments. Engineer Simon Thoresen wrote answers for well over 30 programming
problems. The solutions for many of the most complicated problems present
material that supplements the contents of the book.
We would especially like to thank the three lecturers who dared to believe that
this would become instructional material that they could use during the 1999/2000
school year: Assistent Professor Bjorn Klefstad, Associate Professor Jan H. Nilsen,
and Lecturer Grethe Sandstrak. Along with approximately 100 students, they
worked with preliminary and unfinished course materialstheir experiences were
very helpful to us.
The chapter on JavaServer Pages is not a part of the Norwegian edition, and
Assistant Professor Tomas Holt has contributed to this chapter with tips and
comments in an indispensable way.
Translator Tara F. Chace did an excellent job in translating all the text from
Norwegian into English during a very short period. Thanks to her!
Else Lervik
and
Vegard B. Havdal
reduction
Compile and run a small program you have entered into the computer
The sun was probably shining in San Francisco on the 23rd of May 1995, when the
head of research at Sun Microsystems, John Gage, and perhaps the Internet1
world's biggest celebrity, Netscape founder Marc Andreessen, officially presented
the programming language Java and associated technology.
It was no wonder that Gage was one of the two men on the stage, as the language
in question first saw the light of day during a research project at Sun named Green.
Andreessen had been part of the small group of students who made the first
graphical browser for the WWW (Web), Mosaic. This program, and its successor
Netscape, had revolutionized the computing world during the early 1990s. The
new cooperation between Netscape and Sun would let small programs written in
Java make Web pages interactive and more alive. These plans received a lot of
attention, and there were plenty of ideas about programming toasters over the
Web, and more.
Even today, Java is strongly associated with the Internet, and many people think
the language is exclusively for use on the Web. This is absolutely wrong. Java is a
complete programming language, with its own distinctive features, and more and
less typical fields of use.
1. If these words are new to you, there is a glossary of terms in section 1.8 of this chapter.
1 Introduction
Java is a young programming language. Six or seven years is not long. As a result,
computing professionals or students need to keep up with the continuing
evolution of Java and its associated programs. Writing computer programs in a
language that's undergoing constant refinement may seem like an impossible task,
but in the case of Java, it is not. This is thanks to the language's design and
philosophy. In this book, we hope to give you a basis for understanding this.
2. Keep in mind that Windows Explorer is often configured to hide the suffix of registered file types,
displaying a graphical icon instead. You can check this by looking at View, Options: Hide extensions
for known file types. We recommend not hiding the file extensions, to give you better control and
avoid confusion when several files have the same prefix.
1.2 Contemplating a Computer
we will start working with Java through a console window, you will have to learn
basic textual navigation. We will try to make this easy as we go along. If you need
to read more about this, do a Web search for "MS-DOS commands" or an
equivalent phrase. Or look at the book's Web pages on http://www.tisip.no/Java-
ThellmlWay/, where we have links to some primers.
When it comes to the physical construction of the computer, we have already
mentioned that there is usually a hard disk inside where files are arranged in
directories. Furthermore, it is good to know that there is a central "brain" called the
microprocessor and that the computer has internal memory that is often called RAM,
Random Access Memory. Another name for the microprocessor is CPU, Central
Processing Unit. It would be hard to avoid these terms in a book on programming.
The hard disk is an example of secondary memory. Even if we turn the computer
off, our data and programs will still be intact on the hard disk. All the contents of
the aforementioned internal memory disappear when the power is turned off. The
internal memory is used by the microprocessor to store the running programs, and
their data.
We have published additional information and numbered examples on the
Web. Hence we are assuming that the reader is familiar with using the Internet, at
least browsing a page on the Web and changing the basic configuration of the Web
browser. Try to go to http://www. tisip. no/JavaTheUmlWay/ and see if you can find
your way around.
layer and a window system. The program that implements the console layer in MS-
DOS is called command.com. When we type the command dir in MS-DOS, we
imagine a number of operations being executed in the kernel.
is done, it is run, and it is allowed to communicate actively with the user of the
browser. Instead of retrieving a "dead" HTML file, we now have a small computer
program, and it is the responsibility of the browser in our own living room to
arrange for this program to start and run. Web and applets are good examples of
distributed systems. In a computer network context, with several computers
interconnected, we always try to distribute the amount of work in a reasonable way
between the different computers. When a Web page has 1000 hits in a short period
of time and this page contains some applets, all 1000 clients will all fetch the
applets, and start to run them. This is work that the Web servers would have to do
otherwise, and it could easily have become much too big a task to keep track of all
the information for all the browsers. But this server serves Java applets to the
browsers, saying, "You can do this work yourselves, here is the program."
The other main type of programs are what we call applications. This is
something more traditional; an application consists of program files that altogether
make up a computer program. It is not linked to the Web. In this case, the entire
program is run on the computer we are working on. There are no necessary network
implications. We may also bring the program files home from the office with us
and run the program there. But there are important differences between Java
applications and traditional programs in the form of exe-files. For example, Java
program files are not named archive.exe and cannot be run by typing their name or
double-clicking on them. They have suffix class and require a separate program to
be run. But we will look into this later.
Another very important attribute of programs written in Java is that they are not
tied to a particular brand of computer. We say that the language is architecture neu-
tral or platform independent. This means that you can write a program on your
Windows NT Workstation at work and run it. Then you can bring it home to your
Macintosh or Linux PC and run the same program. If we think back to applets, we
see that this is clearly a prerequisite for applets to work as they were intended. There
are several types of computers used to navigate the Web and if they are all going to
be able to use the applets, which is more or less the situation today, the applet
cannot be written in a way that is usable for only one type of computer. For
example: if a language allows the programmer to write something that is particular
to one specific computer's internal memory layout, that language is not
architecture neutral.
So what does this have to do with Java? The answer is almost nothing, except for
the name. At times, the program code in JavaScript is reminiscent of Java, but it is
something completely different. You will be introduced to JavaScript in Chapter 21.
JSP, or Java Server Pages, is another Java-related technology for advanced Web
applications. You will learn more about that in Chapter 21 also.
Java Core
When we wish to describe parts of the ready-to-use program libraries included with
Java, the API, we do that in a box marked API Reference. Here is an example:
API Reference
Type faces
We have used different type faces for various parts of the text The aim of this is to
make it easy to read. The text in the book is printed in Giovanni. If we include
words of program code inside a paragraph, like int age = 0;, we use a typewriter
face, Courier. We do the same when including examples of program-user
interaction in the console, for instance how to compile and run a program:
When we refer to file names in the text, like autoexec.bat or javac.exe, we use italics.
References
Instead of including them verbatim in the text several times, we have collected our
references to literature and Web pages in a list in Appendix G. A reference to a Web
page in this list from the text itself looks like this: [URL Java book] and a reference
to a book looks like this: [Larman 2000]. The exact addresses and details are
included in the list of references.
Coding standards
When we write computer programs, the appearance of the program code adheres to
a particular style. This has to do with indentations, upper and lower case letters, etc.
The point of this is keeping the code tidy and easy to read. Sun has published a
standard for this, which we use to a large extent. You can find it on [URL Coding
standard] . We recommend sticking to this standard for the appearance of your code
and most of the code in this book does. There are a few things we do differently to
enhance readability. These exceptions of ours are summarized in Appendix F.
Figures
In the book you will learn about a standard for modeling program systems called
UML, Unified Modeling Language. This refers to various types of diagrams used
mainly in the design phase of a program system. Figures that are UML are marked
as such in the captions.
Program Listing 1 .1
r
* PrintText.java VBH 2000828
* Prints text several times
*
V
class PrintText {
public static void main(String[] args) {
System.out.println("Our first program...");
for (int i = 0 ; i<10 ; i++) System.out.println(" About to leam Java!");
Program listing 1.1 details a small Java program, or if you like, a (very) small
application. Let's look at the first lines. There is text in English there, and you might
guess that this is for humans, not computers. The lines between / * and * / are com-
ments. Comments are essential in all programming. The point is to explain and
elaborate on aspects of the program. This is for another person who has to read the
program at a later stage, make corrections, or put it to use. But it can also be useful
to you if you need to change something in a program you wrote several years ago.
It is universally regarded as very important to write comments for difficult and
complicated pieces of the code, but it is not uncommon to fail to do so, especially
in an educational context. We think this is because the usefulness of comments is
not apparent in the short term.
Comments make computer programs useful in the long run as well, for instance
when other developers have to work with them. It is important to acquire the habit
of commenting your code well.
The first comment line in the example shows the name of the file where we have
stored this program, PrintText.java. In other words, we imagine that we have typed
this into a text file with Notepad, for instance, and saved it as PrintText.java. The files
do not contain images or headers, and are by no means similar, for example, to a
doc file that Word uses. Text files are widely used, but tend to be less familiar to
Windows users. The ini configuration files in Windows are text files. E-mail and the
majority of all services on the Internet are also based on the same type of text
coding. In all programming languages, the program code itself is also stored in
plain text. A text file is a text file, computer type (almost) notwithstanding, and this
has been the case for a few years. But in Windows 95/98 and MS-DOS there are
complications, since ASCII (a common character set, see the new concepts in
section 1.8) with certain modifications is often being used here.
We mentioned that one may write, save and edit these files using Notepad in
Windows, but this is very far from being a satisfactory tool. We want more
1.6 A Small Example Program
functionality, like having several files open for editing at the same time. One might
use Word and always save as plain text, but this is needlessly cumbersome. So we
suggest using a program named WinEdit. It is a handy text editing tool, or editor, a
short introduction to which is given in Appendix A.
Back to the example program. We had stated that the file in which the program
is stored is called PrintText.java. It is not a coincidence that the first actual code line
in the program is class PrintText. In this case, class denotes the start of
our program. It is true that a program is always a class in Java, but the reverse is not
true. A class can be other things besides a program. Notice the brackets, { and }.
They are used in Java to mark blocks. Blocks are groups of code lines that belong
together and that we need to delimit. If you look closely at the example, there are
two such blocks here, one inside the other. The outer block is the class
PrintText, where we see class PrintText and its block. The next block is
the method main. It is named by public static void main (String []
args) and the brackets. To summarize, you are looking at one class with one
method. In other programming languages, methods are called subroutines or
functions.
So what does this program actually do? A computer program is a way for a
computer to solve a problem. In this example, this solution is what is inside the
main () method. This is always where a Java application starts. The program prints
the following text in the console window:
This is done with something called a loop, which we will come back to later. We
print "Our first program..." once and "About to learn Java!" ten times. We won't
describe in detail what causes this to happen right now, but we will mention that
the words System. out. print In handle the printing of one sentence.
How we run a program
Our little program has been saved in the file PrintText.java. The computer can't run
this directly from the Java source code. We need to translate it into a type of code
that the computer understands. This is the process referred to as compilation, even
1 Introduction
though the actual details differ a bit from language to language. The compiler is the
program that handles this translation.
It has been most common for PCs that the compiler translates from source code
into machine code. The machine code is the language the microprocessor uses. It is
practically unreadable to humans and that is certainly one of the reasons we have
programming languages like Java. Compiling into machine code can be illustrated
as in Figure 1.2. In this example, a file written in the language Pascal, with file name
HelloWorld.pas, is to be compiled.
We have indicated the machine code with the digits 0 and 1. Data made up of only
these digits is called binary data and this is how the microprocessor "thinks". But we
don't. The finished machine code is stored in the file HelloWorid.com and it can be
started by double clicking on it. Today, an exe file is more common than com, but
an exe file is not necessarily machine code.
In Java it is a slightly different story. Instead of creating a completely self-
contained file of machine code, the compiler produces byte code, stored in a class
file. This class file can't run by itself. Another program, known as the interpreter, is
required to run it. We have illustrated this in Figure 1.3.
In Figure 1.3 we have illustrated the contents of the class file with random
characters. It is not legible to us either.
The outcome of all this is that we need two programs to run a Java program we have
written: a compiler to create the class file, and an interpreter to run it. Sometimes,
the interpreter is also called a compiler, because in the process of running the
program it translates it into machine code internally. A Just-In-Time Compiler is an
interpreter. But in this book, "Java compiler" means the program that translates
from source code into byte code, unless we say otherwise.
Note that the file with the source code has the suffix .Java and the file with the byte
code (which we call the class file) always has the suffix .class. This is mandatory.
But why this middle stage in the form of the class files? The most important answer
lies in what we said earlier about architecture neutral languages. A class file can be
used on all types of computers that support Java, i.e. all types of computers for
which a Java interpreter is available. Only when the interpreter starts to run the class
file will machine-specific issues start to play a role at all. Anything pertaining to a
type of computer (say a Macintosh) is the concern of the interpreter alone. Ideally,
the class files will work everywhere. If you have a class file program and an
interpreter, you are ready to run that program. This is where the slogan "Write once,
run everywhere" comes from.
The interpreter is also refered to as JVM, Java Virtual Machine. This is an abstract,
theoretical model for a computer that will run Java and the interpreter program
implements this model.
Another attribute of the class files is their small size: they are usually significantly
smaller that the file with the source code. This makes them quicker to transmit
through a network, like applets on the Web.
In this book, we are working with the compiler and interpreter that are included
in Sun's freely distributed package Java Development Kit, or JDK. Newer JDK
releases are called SDK (Software Development Kit). Short and sweet, the Java
compiler is called javac, Java Compile, and the interpreter is called Java. The
installation and use of these programs are outlined in Appendix A. Henceforth we
assume you have installed SDK, and we will now show a brief example of typing,
compiling and running a program on a PC.
1. First, type the code in Program Listing 1.1 in your favourite text editor, for
instance WinEdit.
2. Then save the file in the directory on your hard drive you wish to store Java files
on: let's use c:\javaprograms. The file may, but is not required to, be saved as
PrintText.java, because PrintText is the name of the class containing the
method main ( ) .3
3. If you are using Notepad, you need to make sure the file wasn't named PrintText.java.txt. Notepad
insists on naming all text files .txt, which is completely wrong. You might quote the file name when
saving.
1 Introduction
3. Then you start an MS-DOS window and go to the program directory with the
following command:
c:\windows> cd c:\javaprograms
c: \ javaprograms>
4. Then compile by typing the following text. If it works out fine, you will get the
prompt back and it will look as if nothing happened.
c:\j avaprograms> javac PrintText.Java
c:\javaprograms>
If, on the other hand, you get an error message, you have to recheck the source
code for typos. Another common mistake is to spell the name of the file wrong.
5. If you didn't get any errors, you can start the program this way and look at its
output:
c:\javaprograms> java PrintText
Our first program...
About to learn Java!
About to learn Java!
About to learn Java!
About to learn Java!
About to learn Java!
About to learn Java!
About to learn Java!
About to learn Java!
About to learn Java!
About to learn Java!
c : \javaprograms>
Notice that it is incorrect to type
c : \javaprograms> Java PrintText. class (Mistake!)
even though it is the class file that is to be started.
The example showed a rather optimistic course of events. It is far more common
to get some sort of error message from the compiler, indicating a mistake in the
source code. After some corrections and new mistakes in the source code, you will
eventually get it right, but errors may also arise during the execution of the
program. This is all in a day's work for a computer programmer, and you have to
get used to a certain amount of hassle getting things to work. Fortunately, there are
techniques and tools to simplify things as much as possible.
Other tools for working with Java
We use SDK from Sun. This is the most official development tool for Java. We have
seen that it consists of simple programs which we basically need to start by hand by
giving textual commands. Many people prefer to work in this way, but many others
1.7 Examples of Applets
will prefer menus and buttons for compiling and running. Luckily there are
products that provide this.
With text editing tools like WinEdit, we can compile and run programs from
menus, in addition to editing text. These menu choices automatically run javac and
Java for us, making WinEdit into a sort of shell around the SDK. Every now and
then, problems arise in the communication between the editing tool and SDK, for
instance with particular types of Java programs. It will then be very useful to go to
a console window (like the MS-DOS prompt) and do the compiling by hand. So we
recommend learning to use the SDK from the console as an auxiliary solution.
Another category are tools specializing in keeping track of the programmer's
files graphically, creating graphical user interfaces with powerful tools, and of
course compiling and running. Examples of such products are Borland JBuilder
and IBM VisualAge. In our opinion it is still always useful to know how to use the
console tools. That gives the programmer full control over the development
process and all the associated file types.
In the tool Microsoft Visual J++, changes to the language itself have been added,
but not in conformance with Sun's official Java standards. This has been very
controversial and we will not cover these extensions in this book.
The address reveals that it is an HTML document. Applets must lie within HTML
files, or to be precise, the reference to the applet's class file must lie within a HTML
file. So where there is an applet, there is always an accompanying HTML document.
When you load this address, you will get a small document, and the applet runs
inside a rectangular area on the page. This applet is very simple: it only prints a text
with a circle around it. Figure 1.4 shows a piece of the browser, where the applet is
running.
So what is so interesting here? The text and the circle you see are created by the
little applet running in your browser. It is not a part of the static document you
fetched from www.tisip.no. This is the reason why you probably need to wait a while
for something to happen with the applet, compared to the rest of the document. A
small program has to run. In this example, there is certainly no need for an applet.
We could have included the text and the circle in the HTML document, because it
is static. But the applet could have moved and received input from you, the user
Our second example does just that: [URL Color Applet]. Here you are presented
with the option of choosing the applet's background color from a menu. It is in fact
a tiny graphical user interface. This applet is active: it communicates with you by
itself, after being completely downloaded from the Web server. Figure 1.5 shows
how this might look in your browser, although we cannot show the colors.
The applet in Figure 1.5 could not have been made in HTML, as it is not static. Small
and graphical, it could have been written in JavaScript, but that would have given
us serious limitations if we wanted to expand its functionality, and speed decreases
significantly as the size of the little "system" increases.
1.8 New Concepts in This Chapter
Your browser does not support Java applets. This means that the browser
program hasn't been provided with this functionality. Netscape 4.0 and Internet
Explorer 3.0 and newer should support certain versions of Java. Your solution is
to download a newer browser.
Your browser has the Java applet functionality disabled. In your configuration
menu (Options, Preferences or the like) you may switch off running applets
encountered on the Web. The solution to this problem is obvious: enable applet
support in the browser.
Your browser does not support applets written in the version of Java this applet
is written in. This usually implies that you are using an older browser. Published
applets tend to be written in the newest version of Java commonly supported at
that time. The solution is to get a newer browser and perhaps an additional
module for Java support.
You may run across other problems, but these three are very common.
API Application Programming Interface. A standard program library that comes with the
Java software. See also chapter 8.
applet A Java program that's executed inside a Web browser. It is part of a Web document.
application A standalone program meant to run by itself, not needing a browser, for example.
architecture neutral A key element in Java. Nothing in the language ties a program to a particular type
of computer.
ASCII American Standard Code for Information Interchange. A commonly used character
set. See also text file.
browser A program for viewing pages ("surfing") on the Web. Examples: Internet Explorer and
Netscape Navigator.
1 Introduction
client A program or a computer that asks for services from a server, usually over a network.
compiler A program that accepts source code as input and produces, for example, machine code
or byte code.
compiling The process of translating source code into machine code or byte code.
directory The files on a computer are arranged in directories. The directories are organized like a
tree, with directories under others.
distributed system Consists of several programs running on several computers and communicating with
each other.
file An amount of information that serves a purpose to the computer. Often stored on a
hard disk.
HTML Hypertext Markup Language. The formatting language for Web documents.
interactive A situation where a continuous dialogue takes place between human and computer.
JVM Java Virtual Machine. The theoretical model for a computer, which the Java interpreter
realizes.
method A named part of the source code which we use whenever needed. See also chapters 3
and 4.
object orientation (OO) A way to design computer programs. An example of a principle is: Everything that has
to do with a certain thing in the program is gathered in a certain module. An object
oriented language is a language in which this principle is a key point
operating system (OS) The program that administers the hardware so that the user can use it easily. Also
keeps track of the different programs running on the computer. The most widely used
operating systems today are Windows 98 and NT.
process A more general term for a program running on a computer. We often start several
processes when we start a program by double-clicking on it. See also chapter 16.
programming language A set of rules for instructions to a computer. A programming language is a whole lot
more exactly defined than German, for example.
The text which constitutes a program. The source code is to be found on one or more
text files.
text file File containing only plain text. The standard for plain text in Europe is ISO 8859-1, or
latin-1. 8 bits per character are used. The Unicode character system, which lava uses, is
larger, with 16 bits per character. The characters in ISO 8859-1 match Unicode. ASCII
is an older character set with regional variants. The standard part of ASCII is part of
ISO 8859-1.
Unicode A newer and larger character system than ASCII. See also text file.
UNIX Common name for a large class of operating systems. It is widely used for large,
heavy applications.
URL Uniform Resource Locator. An address on the Web, like http://www.tisip.no/ eller/tp://
ftp.gnu.org/.
user interface The part of a program visible to the user. The user interface may be graphical. In that
case, the user will use buttons and windows. If it's textual, the user communicates
with the computer using written commands.
Web (WWW, World A service on the Internet where different documents are presented. They usually
Wide Web) contain links to other documents, that can be navigated between using a mouse.
Windows Explorer The program in Windows that we use to explore disks, diskettes and more. It allows us
to move and copy files, etc.
Assignment, casting
Write programs that perform mathematical calculations and print the results to
the console
This chapter will cover a number of fundamental language elements in Java. There
are equivalent language elements in just about every programming language.
We'll start by introducing an example that we will work with as we proceed
through the book, a program that calculates what it will cost to fix up a
condominium.
In order for the computer to be able to perform these calculations, it needs quite
a bit of information about the condominium. We will look at how to input this
information into a program. We will also look at how to write the program so that
it does the calculations for us and displays the results on the screen.
2 Variables, Data Types, and Expressions
2.1 Example
You just bought an old condominium that you're going to renovate. You've
decided that the bathroom, kitchen, and the electrical installations are fine.
However, you want to replace the flooring in a couple of the rooms and paint and
wallpaper some of them.
You need to perform a number of calculations:
How many square meters of parquet flooring, or other flooring, will you need
for a floor?
What will the renovation cost for each individual wall, each individual room,
and the entire renovation project?
We will work quite a bit with this example over the course of this book. We'll
start with a very simple program that calculates the area of a wall, and we'll end up
with a program with a graphical user interface that will be a useful tool in planning
a renovation (see Figure 15.8). Between these two extremes, we will write smaller
programs that can be used to calculate, for example, how many rolls of wallpaper
we need to cover a wall.
This book is about object-oriented programming. That means that we always
start by finding the objects that are going to be modeled. These can be walls, floors,
wallpaper, etc. The purpose of the program will be to perform certain tasks using
these objectsfor example, estimating the number of liters of paint we will need for
a wall.
In this chapter, we'll look at how to solve minor, individual problems without
thinking so much about the objects.
2. What data needs to be input in order for the program to be able to calculate these
results? This is data that the program's user will use the keyboard to input. The
program reads this data. We call it input data.
Answer: The formula for the area of a rectangle is the length times the height.
Thus the input data is the length and height, measured in meters.
3. What happens between the data being input and the results printing out?
Answer: The program calculates the area based on the formula provided.
The program that solves this little problem will communicate with the user via
the screen and keyboard. When we put this into a larger context, we will be able to
say instead that the surface object performs services for a so-called client object,
which in turn communicates with a user interface object. In an object-oriented
program we will have to ask ourselves these three questions for every single object:
What do we expect the object to tell us, and what does it need to know about itself
to be able to tell us this? What formulas and problem-solving methods does the
object need to know? These questions show that an object in a program has very
different characteristics from an object in reality. More about this in chapter 3.
The following sketch of a textual user interface in the console window is
sufficient for our simple problem:
What the user types is indicated in italic. The user can calculate the area of
several walls by running the program several times.
Actually, it's very difficult to do something as basic as inputting two numbers
into Java. Therefore we start by inputting the length and height directly into the
program (see Program Listing 2.1). Now the user interface is even simpler than
shown above. Only the result prints out. Look at the end of the program listing.
You'll find "Example Run". By enclosing this in / * and */, the compiler regards this
as a comment. Most of the program listings in this book that contain complete
programs with a textual user interface show example program runs at the end.
If the user wants to calculate the area of several walls, she has to open the
program in an editor and edit the length and height each time. Then she has to
compile and run it again.
class WallCalculations {
public static void main(String args) {
double length = 5.0;
double height = 2.3;
double area = length * height;
System.out.println("The area of the wall is " + area + " square meters.');
/* Example Run:
The area of the wall is 11.5 square meters.
V
Get the program from [URL Java book], compile it, and run it.
The lines of code are performed in the order they are listed. This is called
sequential execution.
We remember from section 1.6 that the program does what is in the main ( )
method. The program sets aside room for data in the computer's internal memory.
For example:
double length = 5.0;
Storage spaces like this are called variables. Each variable can contain only one data
value. The program fills the variables with reasonable contents immediately after
they're formed. Here, the variable length receives the value 5.0.
All the variables in the program are outlined in Figure 2.1.
Once length and height are created and have each received their values, the
area is calculated. The result of the multiplication is placed in the variable named
area:
double area = length * height;
Finally, the results of the calculations are printed:
System.out.println(The area of the wall is " + area + " square meters.");
We're familiar with Systern. out .print In () from chapter 1. Inside the
parentheses we indicate what will be printed on the screen. If we are going to print
out several things, we use + to link them together. Text that is going to be printed
exactly as it is is placed in double quotes. Text without double quotes can be the
name of a variable, such as area. That means that the program will get the
contents of the variable and print that on the screen. In this example, the printout
looks like this:
Figure 2.1 The variables in the program that calculate the area of a wall
2.2 Data and Variables
/* Example Run:
Length: 5.8 m
Height: 2.4 m
The area of the wall is 13.92 square meters.
V
2 Variables, Data Types, and Expressions
By using /* and */. All text between /* and */ is ignored by the compiler.
There can easily be several lines of text between / * and * /.
smaller, and there's rarely a need for algorithms on multiple levels. An algorithm's
rules are "ordered" by definition. That means that they have to be carried out in a
specific order. Usage instructions and cake recipes are familiar examples of
algorithms. The program in the previous example builds on the following
algorithm:
1. Read the length and height.
2. Calculate the area using the stated formula.
3. Output the area.
We say that a program that goes through the compiler without error messages
has no syntax errors. The program's syntax is correct. That means that we have
combined words and punctuation in the program in such a way that the compiler
can translate it to a series of byte code instructions.
Errors can arise when you run the program. There may be errors that stop the
program from running, or it may be that the program doesn't solve the problem
that it was intended to solve. The reason for this might be that the algorithm is
programmed wrong, or that the algorithm is wrong. Errors of this type are called
logical errors (the expression semantic errors is also used, "semantic" meaning "of or
relating to meaning"). The compiler doesn't help us find logical errors. We can find
logical errors by running a carefully thought-out set of test data through the
program.
A test data set is a set of input and output data values whose purpose is to detect
logical errors in the program. Test data of course has to be realistic data, but it's also
important to choose data that will test the program's outer limits. A program for
organizing books in a library has to work for zero books and for 200,000 books (or
whatever the upper limit is). In this case, realistic data will be somewhere between
these two outer limits.
We set up the test data for our program as shown in Table 2.1.
Table 2.1 Test data set for a program that calculates the area of a wall
Data Set No. Length Height Expected
Results
1 0.0 0.0 0.0 no wall
2 100 10 1000 a large wall
3 2.3 4.5 10.35 a "normal"
wall
-2.5 3 error message
2 Variables, Data Types, and Expressions
If we run the program with data set number 4, it will calculate that the area is -7.5.
We don't get any message that negative length is meaningless. That's because the
program doesn't check that the input data is correct before the calculations are
performed. Program Listing 2.3 demonstrates how we can do this. We use the
language elements if and else: if a condition is satisfied (here: both height and
length are greater than zero), then we will calculate the area; if not, then we will send
a message to the user. This is covered thoroughly in chapter 5. Until then, we'll get
by without checking the input data.
We've seen the need for test data. There are also other ways to find logical errors
in a program. Inspections are used a great deal. Briefly, this is when other people
formally go through the code. The benefit to this, over testing, is that this type of
debugging can take place early on in the development process. The earlier an error
is detected, the cheaper it will be to fix.
/* Example Run:
The length and/or the height has a non-positive value.
V
Problem
Test the program above with the test data set in table 2.1.
Java Core
Name
A name (or identifier) can consist of letters,2 digits, the underscore character __, and
$. The first character cannot be a digit. Names cannot include spaces. Upper- and
lower-case letters are distinct characters. There are no limits on the number of
characters in the name.
Examples of different valid names: number, Number,
numberOfChildren, student21.
Naming conventions
In addition to the rules, there are also some recommended guidelines for names.
These guidelines primarily come from [URL Coding standard] with our adapt-
ations, which are described in Appendix F. We'll discuss these recommendations as
they become relevant. For the time being, the following suggestion is important:
Because the Unicode character set is used in Java, it is possible to have other letters than a to z in
names. This is often practical to non-English programmers. But be aware of using such letters in class
names if you are working in a mixed Windows/MS-DOS environment, because a class name will
correspond to a filename. And the special letters do not necessarily have the same codes in Windows
as in MS-DOS.
2 Variables. Data Types, and Expressions
Many development environments require the file where we save a Java program
to have the same name as the class that contains main ( ) . Upper- and lower-case
letters also have to be consistent. The file always has to have a java extension at the
end. Thus, the program in Program Listing 2.1 is in a file named WallCak-
ulations.java, while the program in Program Listing 2.2 is in the file WallCa-
Iculations2.java.
Problems
1. Which of the following words are permissible in Java?
To day #hit
TheBookOfMary The_bike_of_Eve
NUMBER _Number34
l00Number History###
2. Study the following program:
class Conversion {
public static void main(StringQ args) {
final double factor = 4.2;
double numberOfCalories = 500;
double numberOfKJoules = numberOfCalories * factor;
System.out.printlnCThe number of kj is " + numberOfKJoules);
Type the program in and run it. Answer the following questions:
(a) What keywords are used? (Use the list in Appendix B.)
(b) What variables are defined? Draw a figure similar to the one in Figure 2.1.
Java Core
There's a new data type in the example in the Java Core box. The int data type
means that the variable's content will be interpreted as an integer.
Also notice that the syntax is written in italics. Text written this way is a
description of what the syntax rules require. For example:
dataType variableName = initialValue;
2 Variables, Data Types, and Expressions
The word "dataType" has to be replaced with a valid data type, while
"variableName" has to be a valid name, and "initialValue" a value permissible for
the data type. The punctuation marks shown in the syntax description always have
to be included.
In some circumstances, we want the contents of a variable to be constant. We
can, for example, have a variable with the name upperLimit. Here we set the
content to 30, and that cannot be changed by the program. We declare a named
constant this way:
final int upperLimit = 30;
Now if the program tries to change the content of the variable upperLimit, the
compiler will send an error message.
final is a modifierin other words, a keyword that modifies the original
meaning of what follows it.3 In this case, upperLimit becomes a variable with a
constant content.
Why should we declare a name for the number 30? Can't we just use the number
30 when we need it? There are several reasons to give the number a name:
In a formula, the name upperLimit will tell the reader a good deal more than
the number 30.
If the limit changes, we only have to change the number 30 in one place-
namely, where the variable upperLimit is declared.
For decimals, we're assured of using the same number of decimal places
everywhere, not 3.14 in one place and 3.14159 in another.
If we have large numbers or numbers with a lot of decimal places, it's easier and
safer to write the name than the number.
We call the number 30 and other constants that come up in the program
anonymous constants or literals. In Program Listing 2.1 we have the following literals:
5.0
2.3
"The area of the wall is"
" square meters"
The following modifiers exist: public, protected, private, final, static, transient,
volatile, abstract, synchronized, native. We cover most of them in this book (see the
index at the end of the book).
2.5 Variables and Constants
Java Core
If a name is composed of more than one word, every new word should start with
a capital letter. For example: numberOf CitiesInBelgium.
Problems
The following statements are given:
final int numberOfYears = 35
double Amount = 40,95;
final aConstant = 789.6;
DOUBLE number =15.7;
Amount = Amont * 100;
1. Insert these statements into a program and run it. You will get several compile-
time errors. Try to explain them. Correct the errors so that the program compiles.
2. Which of the names are inconsistent with the naming conventions used in this
book?
2 Variables, Data Types, and Expressions
The range indicates the maximum and minimum numbers that can be stored
in a variable of this type. The int data type describes the set of all integers
from -2,147,483,648 to +2,147,483,647. We say that the range for int is
[-2,147,483,648, +2,147,483,647]. We need four bytes to store a value of this data
type. The bigger the range, the more room it requires. There's room for more
combinations of zeros and ones in an 8-byte variable than in a 4-byte variable.
An integer literal has the type int if it's not followed by the letter L. If it is, then
it's type is long. We could also use a lower-case 1, but since those are easy to
confuse with the digit 1, we avoid doing so. Examples of long type literals:
-123456789L
223372036854775808L
90000I // we used a lower-case I heredifficult to read
An integer literal that starts with the digit 0 is interpreted according to the base 8
system. This very thing has been the cause of many "inexplicable" errors. If the
literal starts with the characters Ox or OX, it's interpreted according to the base 16
system. You can confirm this by inserting the following bit of code into a program
and running it:
System.out.println("Printing 056 gives " + 056); // value 46
System.out.println("Printing OxOOe6 gives " + OxOOe6); // value 230
We don't get an error message if the result of an integer calculation doesn't have
room in the integer variable we're trying to store the result in. The only thing that
happens is that the answer is wrong. Therefore, we have to be careful not to perform
calculations where this can occur.
If we try to divide an integer by 0, on the other hand, we get an error message
and the program stops.
4. Also called floating point numbers, which tells us something about how decimal numerals are
represented internally in the computer, without going into any more detail about that here.
2 Variables. Data Types, and Expressions
The range for double is approximately [10-308,10+308]. Notice that the range
is divided in two, from a large negative numerical value to a small negative
numerical value, and then from a small positive numerical value to a large positive
numerical value. In addition, there is the number 0.0. This type of variable takes up
8 bytes (64 bits).
Decimal calculations never give 100% accurate results. We work with an
approximate number of significant digits. Certain types of calculations are
significantly less accurate. We'll look at this more closely in Chapter 5.
Variables of the data type float can also be used to store decimal numerals.
The range, number of significant digits, and storage requirements for float and
double are shown in Table 2.3.
A decimal numeral literal will be of the type double, if it's not followed by the
letter F (or f). For example: 3 . 5F
Remember from the last section that when you divide an integer by 0 you get an
error message and the program stops. This is not the case if at least one of the
operands is a decimal numeral.
From math, we know that 0/0 is an indeterminate expression. If we ask a Java
program to calculate this, and the operands are decimal numerals, we get the value
NaN. This means "not a number."
Dividing by the decimal numeral 0.0 gives the value Infinity. This also
agrees with what we know from math.
The following lines:
System.out.println("Zero divided by zero:" + 0.0 / 0.0);
System.out.println("Division by zero:" + 10.0 / 0.0);
gives the output:
Zero divided by zero: NaN
Division by zero: Infinity
Despite getting results from dividing by 0, we should be careful with this. These
results won't be of any use in further calculations.
When you run the programs in this book, you will probably be irritated that
decimal numerals are frequently output with an unnecessarily large number of
decimal places. Getting outputs with a specific number of decimal places requires
the use of classes and several lines of programming code. We'll cover this in Section
8.3.
A data type for boolean values
Little by little, we'll see that we often need variables that can store a boolean value
(true or false). This type of variable contains the value true or the value false.
The data type is called boolean. Examples:
boolean allWallsArePainted = false;
allWallsArePainted = true; // now all the walls are finished
7'
'#'
A literal of this type is enclosed in single quotes.
A variable of the char type takes up two bytes.
Because it is not possible to store anything but numbers in the computer, every
character has its own number. There are many numbering systems. Most
programming languages use the ASCII character set. This character set is defined so
that each character uses one byte of memory. That means that it can only contain
256 different values. Of these, only the values 0 to 127 are standardized. The other
values vary from platform to platform and from country to country. This is, of
course, unfortunate in a world that's becoming ever more international. Therefore,
Java uses the Unicode character set.5 With two bytes per character at its disposal,
it's possible to store 65,536 different characters. The characters with numbers from
0-127 correspond to the characters with the same numbers in ASCII. Appendix D
shows the standardized portion of the ASCII character set.
Also note that the digit characters have their own values. The digit character '5',
for example, has the number 53.
We can speculate in which way we should write the character '. We don't write
three single quotes. Instead, we use a backslash followed by two single quotes, like
5. Currently, Windows NT and several UNIX variants use the Unicode character set. More information
about Unicode at [URL Unicode].
2 Variables. Data Types, and Expressions
this ' \ ' '. There are a number of other characters that we have to write the same
way. For example, ' \n' denotes a newline. See table 2.4.
Table 2.4 Special characters written with a backslash before the character
Name Character
double quote, after the backslash: double quote and single ' \ '
quote
single quote, after the backslash: two single quotes '\ ' '
Even if we can use the + operator to concatenate, or link together, strings and
numbers, we can't use the - operator to cut strings. The program excerpt above gives
the following output:
We have 17 groups
Trondheim Bergen
The following statement prints three words with newlines between them:
System.out.println("Line1" + "\n" + "Line2" + "\n" + "Line3");
We use single quotes when we make literals of the char type. Examples: ' a ' ' '
,7,
We use double quotes when we make string literals. Examples: " hi
"this was a little complicated"
Problems
1. What data type do the following literals belong to?
12.45
"Hello!"
T"
V
12345L
0456
true
3.245e-5
2. We need to store some merchandise information. What data type should we use
to represent the following?
(a) Price
(b) Quantity of merchandise measured in kilograms
(c) Quantity of merchandise measured in number
(d) Color code (a letter)
(e) Bar code
(f) Name
3. What is output if the following statements are inserted into a program and it's
run?
String firstName = "Ann";
String middleName = "Isabelle";
String lastName = "Adams";
2 Variables. Data Types, and Expressions
Dividing integers results in integer division (in other words, the result will be the
quotient except for the remainder of the division):
5 / 2 = 2-5 / 2 = -2
1/3 = 0-17-3 = 0
2 / 3 * 5 = 0-57-2 = 2
2 * 5 / 3 = 30 75 = 0
Note that the left side of the assignment operator always has to be the name of a
variable.
The assignment operation has the lowest priority of all the operators, and it is
interpreted from right to left.
Because the assignment character is an operator, the assignment will be an
expression with a specific value. The value of the expression is equal to the contents
of the variable on the left side of the assignment character after the assignment is
completed.
The value of the expression number2 = 4 is 4. For example, this makes it
possible for us to write:
numberl = number2 = 4
First number2 is set to equal 4, and the value of the expression number2 = 4
calculates to 4. Then numberl = 4 is carried out.
Problems
We have the following variables with integer contents: a is equal to 10; b is equal
to 5; c is equal to 3; d is equal to 2. And we have the following variables where the
contents are to be interpreted as decimal numerals: p is equal to 2.8; q is equal to
3.3. These variables are used in problems 1-3 below.
1. Draw out the variables the way it was done in Figure 2.1.
2. Which of the following statements is legal?
5 = 5;
b = b + c;
d = d;
10 = b*2;
b = a:2;
p:=q;
3. What is the value of each of the following expressions?
c + d *a
a*b/c+a
c %d
d %c
p %q
q %p
c %d %a + b/c
a = b = 16
4. Compose expressions for the following formulas:
b2 - 4ac
x2 + y2 + z2
x3
(a - b) (a + b)
2.8 Type Conversion
a + b
c + d
double d1 = 3.2;
double d2 = 3.9;
double d3 = 4.0;
double d4 = 4.5;
int p = (int) (d1 + 0.5);
int q = (int) (d2 + 0.5);
int r = (int) (d3 + 0.5);
int s = (int) (d4 + 0.5);
System.out.println(p + "" +
The output here will be 3 4 4 5.
Java Core
Note that Java only considers a single (partial) expression at a time. For example:
double result = 3.7 + 3/4;
The division is performed first as an integer division, then the addition is carried
out. The result will be 3.7. If we don't want the integer division, we have to cast:
double result = 3.7 + (double) 3 / 4;
The roll of wallpaper is 54 cm wide and 12.5 meters long. A roll of wallpaper
costs $10.
The paint covers 10m 2 per liter. Three coats are recommended. The paint costs
$8 per liter.
In the program, these numbers will be input data. Output data will be the
number of rolls of wallpaper and number of liters of paint that are necessary for the
wall, and the price for them.
2 Variables. Data Types, and Expressions
algorithm A limited and ordered set of well-defined rules for solving a problem.
assign To calculate an expression and then store the result in a variable. Uses the operator =.
bit "Binary digit." One of the digits 0 or 1 when they are used in the base 2 system.
byte 8 bits.
casting Asking the program to convert from one data type to another data type. May give the
wrong result because the range of the second data type may be too small to contain the
value.
data type A data type describes a set of values. It also determines which operations we can perform
on these values.
declare Introduce a name to the compiler, and tell what it's a name for.
final Modifier that's used, among other things, to declare a named constant.
floating point Decimal numerals stored on the computer with respect to a representation form called the
numbers floating-point system.
header Comment lines located at the top of a file. In this book they contain the file name, the
comment author's initials, the date of the most recent version of the file, and often also a
description of the file's contents. In larger programming systems, header comments often
contain more comprehensive information.
Infinity The result of dividing by 0.0 and other calculations with decimal numerals that give result
values that are too large.
initialize Give a value to a variable when it is declared.
input data Data that the program reads, for example, from the keyboard.
inspection Letting someone other than the author read the source code in a formal manner to find
logical errors.
integer division The result that when two integers are divided by each other, the remainder from the
division is deleted, e.g. 5/3 = 1.
keyword Word with predefined significance, cannot be used in any way other than that specified in
the syntax of the language.
literal See anonymous constant.
2 Variables. Data Types, and Expressions
statement Instruction to the computer; ends with a semicolon. In some contexts, a block is
considered a statement.
string An object that contains a text; the object is an instance of the String class.
String Predefined type (class) for handling texts.
syntax Rules that we have to follow when setting up a program so that the compiler will
understand what we mean.
syntax error Error that the compiler discovers; our program doesn't follow the syntax rules.
test data set A set of input and output data values whose purpose is to detect errors in the program.
These values are often more "extreme" than realistic data.
text string The same as "string."
type See data type.
unary operator An operator that only requires one operand.
variable A storage location that can contain a value of a given data type.
2.11 Review Problems
Problem 3
Write a program that inputs a number of seconds and calculates how many hours,
minutes, and seconds this is (hint: use integer division). Set up a test data set and
test the program.
Learning goals for this chapter
After completing this chapter, you will understand the following concepts:
Object, the difference between objects in reality and in a program
Attribute, message, operation, class, client, server, encapsulation
Method, constructor, parameter, argument, client program. Class constants and
class methods. Package and import
You will be able to:
Draw a class diagram based on an informal description of the class
Use methods in the JOptionPane class to communicate with the user
Use the most important methods in the String class
There are several systematic ways to solve programming problems. Previously, one
would approach a problem like this by focusing on an algorithmic abstraction. One
started by setting up an algorithm at a very high level of abstraction. For example:
input data - perform computations - print results. Then one took each step of this
algorithm separately and added further detail, often on many levels depending on
the complexity of the problem. It wasn't uncommon that one would discover at a
low level that the problem was one that had been solved before. Isolating program
bits that solved specific problems became, and still is, of great use in program
development. Libraries of routines, for example, for mathematical computations,
graphics, and handling large quantities of data in archives (databases) are
common. Of course, even if the data is important, there is no clear connection in
these libraries between the data and the algorithms that do things to the data.
Many people believe that one of the reasons it's so difficult to create large and
complex systems lies in this method of approach. Data and algorithms should be
viewed in context. Software libraries should not consist merely of handling
routines for data, but of a type of modules where these routines are indissolubly
linked to the data they can handle. These types of modules are called classes. We
can have classes that describe students, that describe cars or books.
3 Using Ready-Made Classes
Very soon we will study the three examples named earlier in more detail. First,
however, we need to look at the concepts of client, server, message, and operation.
Client and server are roles that objects play.1 Objects collaborate when a client
object requests a service by sending a message to a server object. The server carries
out an operation as a reaction to the message. The server can send responses back
to the client.
In Figure 3.1 we see Greta and her car. Greta sends messages to the car: start,
speed up, brake, stop, etc. Greta is a client object; the car is a server object. As a
reaction to the message, the car performs the right operation: start, speed up, brake,
stop, etc.
client
Figure 3.1 The object Greta plays the role of client, while the car object plays the role of
server
Especially in this example, it's relatively easy to imagine some of the knowledge
that must lie in the server object. A driver is used to the car having the responsibility
for how the operations of starting, driving, etc. will be performed. He needs to
know very little about the complicated processes that take place in reality. In
addition to knowledge of the operations, the model also requires that the car object
have knowledge of the license plate number, make, and model. In the real world,
this information is part of the car's surroundings, but since it is part of
characterizing the car object, we say that the object itself will have this knowledge.
Let's look at example number two: Of course a student has knowledge of her
student ID number, address, and how she will respond to the questions in the
1. In chapter 1, the concepts of client and server were used in a very specific context. There we were
discussing computers as Web servers and Web clients. The program we are running on a computer
determines the role the computer plays.
3 Using Ready-Made Classes
exam. In the real world she is responsible for updating the information and taking
the initiative to sign up for the class. In a way, she is both client and server. She
sends messages to herself. It's possible to allow a single object to be both client and
server, but usually two different objects play these roles. In an object-oriented
model, the client will send the message "take the exam" to the student object. A
client will also be able to send the message "this is your grade" to the student object.
In the third example, we will model something as abstract as a meeting. What
will a meeting object be responsible for? A meeting is characterized by a location, a
start and end time, participants, etc. A client should be able to send, for example,
the following messages to a meeting object: start the meeting, move the meeting,
change the timetable for the meeting.
An object has a state. The state for an object is "a condition or situation during
the life of an object during which it satisfies some condition, performs some
activity or waits for some event."2 The student can sit in the exam room and wait
for the tests to be given out. When the exams are passed out, she changes over to a
new state.
An attribute is a named quality with a defined range of values. In the student
example, the student ID number and address are attributes. The values for these
attributes could, for example, be "1234567" and "56 University Ave." The "student
ID number" attribute always consists of seven digits. The range of values is
therefore all seven-digit integers. The "address" attribute can be defined as a text, or
it can be one of a more precisely specified number of addresses.
An object has an identity. All real objects can be distinguished from each other.
The same is true of our model objects. We distinguish the object with student ID
number 1234567 from all other objects.
An object has a behavior. The object is capable of performing a number of tasks.
Anne can change her address, and she can go to a lecture. An object's behavior is
given as a quantity of operations that the object can perform.
Encapsulation is an important characteristic of objects. Information about how
an object solves tasks is hidden inside the object. The client object doesn't need to
know how the server object solves the task, just that it can be solved. A client object
only relates to the behavior that is defined for the server object. Thus, the client can
only send a limited selection of messages to the server object. Whoever constructs
the object gets to decide which services the object will offer.
A class is a description of a quantity of objects that have the same attributes and
same behavior in common.
It's common to illustrate a class using a class diagram. This is a standard notation
that is a part of Unified Modeling Language (UML).3 UML is independent of the pro-
gramming language. We will, of course, be programming in Java, but other pro-
2. [Rumbaugh, Jacobson, Booch 1999, p. 433]
3. The main UML reference is [Rumbaugh, Jacobson, Booch 1999). This is a reference work. The same
three people have also written a more practically oriented user guide: [Booch, Rumbaugh, Jacobson
1999).
3.2 Using Ready-Made Classes
gramming languages can also be used where a UML model is the basis. Figure 3.2
shows an excerpt of the diagram for the class Car. The names in the class diagram
are chosen such that we can use them in a program later. The first letter in a class
name is usually a capital.
attributes
operations
Problems
1. In the text above, you find an informal description of the classes Student and
Meeting. Draw class diagrams.
2. Make a description of an object that models a microwave oven. Draw a class
diagram with attributes and operations. Set up some states that the oven can be
in.
4. We are using the words parameter and argument the way they are used in the Java Language
Specification [Gosling, Joy, Steele 1996] and in UML (Rumbaugh, Jacobson, Booch 1999). In other
literature you may find the expressions actual and formal parameters, or actual and formal
arguments. The "actual" is what we call an argument. The "formal" is what we call a parameter.
3.2 Using Ready-Made Classes
theCarOfGreta
\
reference name , reserved word to instantiate an object
arguments
class name
Figure 3.3 The reference theCarOfGreta refers to an instance of the Car class
3 Using Ready-Made Classes
In the beginning:
The car objects have one reference each
theCarOfGreta theCarOfAnne
Java Core
What does it mean that the argument type has to agree with the parameter type? The
type doesn't need to be the same. It's enough that the argument can automatically
be converted to the parameter type. Example: the method
void increasePrice(double increase)
will accept the following calls:
aMerch.increasePrice(20); // argument type is int, automatically converted into double
aMerch.increasePrice(12.50); // argument type is double, no conversion
Other number types that are less than double are also accepted as arguments (see
section 2.8).
Problems
1. Sketch out figures that correspond to Figure 3.3 when the following statements
are executed. Explain which things are references, which are objects, and which
are variables of primitive data types.
3 Using Ready-Made Classes
We can imagine having a machine that comes up with these kinds of numbers
for us. Every time we want a new number, we send a message to this machine (see
Figure 3.5).
/* Example Run:
Here you have four random numbers in the range [0..99]: 76 20 94 16
*/
Below you'll find the book's first API reference. These references describe classes
that come with the Java compiler. The descriptions are not complete but contain
the most important constructors and methods.
API Reference
This method returns the next decimal numeral uniformly distributed in the interval
[0.0..1.0>.
public int nextlnt()
public long nextLong()
These methods return the next integer, uniformly distributed over all possible
integers, positive and negative. The next Int ( ) method draws the number from
the interval for the data type int, while nextLong ( ) draws from the interval for
the data type long.
public int nextlnt(int n)
This method returns the next integer, uniformly distributed in the interval [O..n-l].
Problems
1. Write a program that creates and outputs the following pseudo-random
numbers:
(a) Three integers selected from the entire numerical range for the data type
long
(b) Three integers in the interval [0..1000]
(c) Two decimal numerals in the interval [0.0..1.0
(d) Two integers in the interval [-500..500]
(e) Two decimal numerals in the interval [0.0..100.0>
Hint for e): Multiply the results from nextlnt () and nextDouble ( )
respectively by a suitable factor.
Run the program several times, with and without a specific seed value.
2. We can output the random number without storing it in a variable:
System.out.println("A random number:" + randomGen.nextlnt());
Study Program Listing 1.1 where the statement "About to learn Java!" is printed
10 times. Try to make a program that writes, for example, 20 random numbers
under each other.
The String class is special because we can create instances of the class without
using the word new. The statements above can also be written in the following
manner:
String city = new String("Trondheim");
String text = new String("Here are four words");
We have two references as shown in Figure 3.6.
Thus, Figure 3.3 doesn't tell the whole truth. The object that theCarOfGreta
refers to contains two references of its own (see Figure 3.7).
text
theCarOfGreta
Figure 3.7 theCarOfGreta refers to an object that contains two references of its own
The String class provides dose to 50 methods. We will look at the simplest of
these. Program Listing 3.2 shows examples of some of these methods in use. Study
the program code and the output. There are several things to take note of:
There are methods for converting from lower to upper case and vice versa. These
methods also work for special letters outside the English/American a-z alphabet,
such as the German 6 and u, when run on Windows. If you write to the MS-DOS
window, it will look as though the methods aren't working for these letters, but
that's because of the character set that MS-DOS uses.
None of the methods change the contents of the object. The toUpperCase ( )
and toLowerCase ( ) methods create new instances of the String class and
return references to them.
3.4 The String Class
The short form for creating instances of the String class is used a lot. Example:
String name = "John";
However, it's important to remember that this is exactly the same as if we had
written:
String name = new String("John");
Figure 3.8 shows the room that is set aside by the machine's internal memory
when running the program. We have:
Four variables of reference types. These contain references to instances of the
String class: text, noTrailingOrLeadingSpaces, upper, lower.
Four instances of the String class.
Three variables of primitive data types: initial and secondLetter are of
the char data type, while noOf Chars is of the int data type.
Program Listing 3.2
/*
* TestString.java E.L 2001-05-21
*/
class TestString {
public static void main(String[] args) {
String text = "Anne Smith";
String noTrailingOrLeadingSpaces = text.trim();
String result = "Spaces removed:" + noTrailingOrLeadingSpaces;
String upper = text.toUpperCase();
result = result + "\nOnly upper case letters: " + upper;
String lower = text.toLowerCase();
result = result + "\nOnly lower case letters: " + lower;
char initial = text.charAt(0);
result = result + "\nlnitial letter:" + initial;
char secondLetter = text.charAt(l);
result = result + "\nSecond letter:" + secondLetter;
int noOfChars = text.length();
result = result + "\nThe length of the string:" + noOfChars;
System.out.println(result);
3 Using Ready-Made Classes
/* Example Run:
Spaces removed: Anne Smith
Only upper case letters: ANNE SMITH
Only lower case letters: anne smith
Initial letter: A
Second letter: n
The length of the string: 10
no TrailingOrLeadingSpaces
noOfChars
upper
arme
lower
Figure 3.8 Room reserved in the memory in connection with the string handling in Listing
3.2
API Reference
Methods:
This method returns the character in the position stated (the index). The positions
are numbered from 0 on.
public int indexOf(int character)
public int indexOf(int character, int fromlndex)
public int indexOf(String substring)
public int indexOf(String substring, int fromlndex)
These methods are used to search for an individual character or a substring in the
string. The data type for the character parameter is int. Nevertheless, you can
send in a regular character (the data type char) as argument. The methods return
the position for the character or position at the beginning of the substring. If the
character or substring doesn't exist, the methods return -1. The first position in the
string has the number 0. Two of the methods take fromlndex as their argument.
This makes it possible to start the search in a position (index) other than 0. If
fromlndex is less than 0, the search starts at the beginning of the string. If
fromlndex is greater than or equal to the string's length, -1 is returned.
public int lastlndexOf(int character)
public int lastlndexOf(int character, int fromlndex)
public int lastlndexOf(String substring)
public int lastlndexOf(String substring, int fromlndex)
These methods correspond to the methods named indexOf ( ), but here the
search is done backwards.
public int length()
This method returns the number of characters the string consists of, including all
blank spaces.
public String substring(int beginlndex)
public String substring(int beginlndex, int endlndex)
These methods return a part of the string. The first method returns the whole string
starting from beginIndex, while the second one returns the string starting from
the position beginIndex up to and including the position (endIndex - 1).
Invalid argument values (example: endIndex greater than the length of the
string) give an IndexOutOfBoundsException message.
public String replace(char oldChar, char newChar)
This method returns a string where all occurrences of a specific character (first
parameter) are replaced with another character (second parameter).
public String toLowerCase()
public String tollpperCase()
These methods return strings that are equal to the original string, but where all
letters are lower- or upper-case respectively. These methods work for letters outside
the English/American alphabet, too.
public String trim()
3 Using Ready-Made Classes
This method returns a string that is equal to the original string, but where blank
spaces in the beginning and end of the string have been removed. Blank spaces in
the middle of the string are retained. Blank spaces don't just mean the character' ',
but also a number of other invisible characters, such as, for example, carriage
returns and tabs.
Program Listing 3.3 shows the search methods described above in use. The
program creates the string "This is a testing text with many e ' s "
and then undertakes a number of searches in it. All the different forms of the
methods indexOf ( ), lastIndexOf ( ) and substring ( ) are tested. Study
the source code and the output.
/* Finding substrings */
String partOfText = text.substring(10);
System.out.println("From position 10: " + partOfText);
partOfText = text.substring(7, 14);
System. out.println("From position 7 including position 13: " + partOfText);
/* Replacing all e's with a's */
String newText = text.replace('e', 'a');
System. out.println("The new text with a's instead of e's: " + newText);
System. out.println("None of all these operations has changed the original text:
+ text);
/* Example Run:
Testing the text: This is a testing text with many e's
This text's length is: 36
The positions are numbered from 0, and up to and including 35
The first e is at the position: 11
The next e is at the position: 19
The first occurrence of "text" is at the position: 18
The next occurrence of "text" is at the position: -1
The last e is at the position: 33
The last but one e is at the position: 19
The last occurrence of "text" is at the position: 18
The last occurrence but one of "text" is at the position: -1
From position 10: testing text with many e's
From position 7 including position 13: a test
The new text with a's instead of e's: This is a tasting taxt with many a's
None of all these operations has changed the original text: This is a testing text with
many e's
*/
Problems
1. The following declarations are stated:
final String continent = new String("Europe");
String country = "Spain";
String city = new String("Madrid");
char regLetter = 'E';
Create a sketch corresponding to Figure 3.8. Write a description of the figure.
Use the words variable, reference, primitive data type, reference type, and object
in your text.
2. What is output when the following code bit is run?
String song = new String("Yesterday");
song = song.toLowerCase();
3 Using Ready-Made Classes
name of the subdirectory where the classes that belong to the package are located.7
The package name is a part of the class name.
For the classes that come with the compiler, we need to use the complete class
name for all classes that don't belong to the package java . lang. Package names
that consist of several words denote that we have several subdirectories before we
find the class.
The Random class belongs to the java . util package. The complete name of
the class is java.util.Random. The first part of Program Listing 3.1 looks like
this:
import java.util.Random;
class TestRandom {
public static void main(String[] args) {
Note that an asterisk in an import declaration can only replace class names. It
cannot replace package names. In other words, we can't write, for example
import java.*.*; // not allowed!
7. This is the most common. Certain development environments organize the packages in a database.
That won't be covered in this book.
3 Using Ready-Made Classes
programming. The methods are called instance methods, because we always call
them in connection with an instance of a class.
At the same time, a library should also provide a few methods of a more general
nature, which can be used without being linked to a specific object. These types of
methods are called class methods, and examples are methods for mathematical
computations (square root, sine, cosine, etc.) as well as methods for sorting and
searching.
In a class description, a class method is marked with the modifier static, and
in the java . lang. Math class, we find the following methods, among others:
public static double sqrt(double number)
public static double sin(double number)
We call a class method by putting the class name before the method call.
For example:
double sqRoot = Math.sqrt(15678); // finding the square root of 15678
In Program Listing 3.1, we composed a Random object that we then sent messages
to. In the Java library, we also find a class method that creates a random number.
The random () method in the java. lang. Math class generates a pseudo-
random number in the interval [0.0..1.0>.
Very shortly we will need to use class methods when inputting data from the
user. All data, even numbers, are input as strings. If we want to use the numbers in
computations in the program, we have to convert them from strings to numbers. In
order to understand the necessity of this conversion, we have to take a detailed look
at how characters and numbers are stored in the internal memory. For the time
being we'll have to make do with stating the fact that they are stored in different
ways, and for that reason, the conversion is necessary.
Class methods have been created for this conversion. The methods are called
parselnt ( ) and parseDouble ( ). They belong to the Integer and
Double classes respectively, which are both part of the java, lang package.
Therefore, we can use the methods without setting up the classes in an import
declaration.
The following little code bit creates two strings and then converts them to
numbers:
String textl = "2345";
String text2 = "45.3";
int number1 = Integer.parselnt(text1); // interpreting text1 as integer
double number2 = Double.parseDouble(text2); // interpreting text2 as decimal numeral
System.out.println(number1 + " " + number2);
As expected, the output is:
2345 4 5 . 3
Of course, it can happen that it's not possible to convert the string to a number. For
example, text2 above cannot be converted to an integer. Then the program stops
with an error message.
3.7 Reading Data from the User
The Java library also contains many constants. Each constant is common for all
the objects the class describes. Therefore, it is declared as a class constant. In the API
reference a class constant may look like this:
public static final double PI // this is 3.141592....
and is used like this:
double circumference = Math.PI * 2 * radius;
The most familiar example of a class method, however, isn't part of the Java library.
It's our own main ( ) method. When we start a program with the Java interpreter,
it will look for main ( ) in the class we declare. The method is started without any
instances of the class being made.
Note that we still can't handle the case where the user pushes down the "Cancel"
button, or where he closes the window by clicking in the upper right corner.
3 Using Ready-Made Classes
In order for a program that uses dialogs this way to stop in the usual fashion, we
have to insert the statement
System.exit(0);
at the end of it.
/* Example Run:
Length: 5.8 m
Height: 2.4 m
The area of the wall is 13.92 square meters.
V
3.7 Reading Data from the User
API Reference
These methods let the user enter a text that is returned to the client.
The methods have several parameters in common:
parent will be null as long as the dialog box doesn't belong to an ordinary
window in a graphical user interface.
message is the text that is written in the dialog. Even if the parameter type is
Object, it works well with String as an argument.8
t itle is the text that appears at the top of the title line in the dialog.
messageType determines the icon on the left in the box and can be one of the
following class constants: ERROR_MESSAGE, INFORMATION_MESSAGE,
WARNING_MESSAGE, QUESTION_MESSAGE or PLAIN_MESSAGE (no
icon).
If we use one of the methods where the message type is not going to be stated,
we get a default icon.
icon represents an image. The parameter type is Icon. The argument can be of
the type Image I con,9 which is well suited when we have the image in a file.
This argument overrides the argument for messageType.
The methods return null if the user hits the Cancel button or closes the dialog
by clicking in the upper right corner.
Problems
1. Write statements that input an integer, a decimal numeral, and a text. Use the
simplest of the showInputDialog ( ) methods. Sketch how you think the
dialog boxes will look.
8. Because the parameter type is Object, the argument can be an instance of any class whatsoever. It
can be a GUI component (chapter 13), or it can be an instance of the Imagelcon class. In other
cases, the object's toString ( ) method is used (see chapter 10).
9. Icon is an interface (see chapter 10). The argument can be of any class whatsoever that implements
this interface.
3.8 New Concepts in This Chapter
Brief Explanation
argument The value the client sends with a method or a constructor. The term "actual argument" is
also used.
attribute Information that an object is responsible for knowing about itself, a named property with
a defined range of values,
class A description of a set of objects with the same attributes and behavior.
class constant A variable in a class, with the modifiers static final and a given value. The constant
is common for all instances of the class, and it may be accessed even if no instances of the
class exist.
class diagram Graphical presentation of one or more classes, and the connection between them, with
respect to UML For the time being, our class diagrams will only consist of individual
classes.
class method A method declared with the modifier static. Outside the class the method is invoked
by qualifying it with the class name.
client A role that an object can play. The role entails the object requesting another object (the
server) for a service, or asking another object a question. Also used as short form for
"client program", see this.
client program A program that sends messages to one or more objects. The term is often used about the
method main ( ).
encapsulation Information about data representation and how operations are performed are hidden
inside the object. The client deals with the object's interface.
identity Objects have identity because they model things in the real world that are identifiable,
implement To program the classes (see chapter 4). Also used about creating programs in general.
import Keyword to say that the program uses classes that belong to a named package. The
alternative is to write the complete class name (including the package name) every time it
is referred to the class.
instance Synonym for object. [Booch, Rumbaugh, Jacobson 1999, p. 185] says : "Instance and
object are largely synonymous. [...] From common usage, the concrete manifestation of a
class is called an object. Objects are instances of classes, so it's excruciatingly proper to
say that all objects are instances, although some instances are not objects (for example,
an instance of an association is really not an object, it's just an instance, also known as a
link). Only power modelers will really care about this subtle distinction."
3 Using Ready-Made Classes
instance method Represents an operation. Often just called "method" if there's no danger of
misunderstandings. Outside the class the method is invoked by qualifying it with the
name of an instance of the class.
instantiate Synonym for the process of creating an object. The dictionary says: "to represent (an
abstraction) by a concrete instance <heroes instantiate ideals W. J. Bennett>" [URL
Merriam-Webster]
interface A description of the messages that can be sent to an object. The description of a method
contains return type, method name, and parameter list.
message An instruction or a question that the client object sends to the server object. Data is sent
along as (actual) arguments.
method Declarations of operations at the program code level.
parameter Describes a value that a client can send together with a message or a constructor. The
description includes the data type and a descriptive name. The term "formal parameter"
is also used.
reference type A data type that is described using a class declaration,
return type The data type for the return value from a method.
return value The data value that a method sends back to the client. It will be the server's response to a
query from the client.
server A role that an object can play. The role entails the object answering a question or
performing a task following instructions from another object (the client).
state "A condition or situation during the life of an object during which it satisfies some
condition, performs some activity or waits for some event." (Rumbaugh, Jacobson,
Booch 1999, p. 433]
UML Unified Modeling Languagea modeling language.
unnamed package Classes that are in files that don't contain the package statement belong to the
unnamed package.
3.9 Review Problems
Overloading names
Start with an informal description of a class, and program it with class constants,
instance variables, constructors and instance methods
Program applets for simple graphics (circles, rectangles and lines, colors and
different fonts)
Now that you have some experience using ready-made classes, this chapter will
focus on how you can program your own classes.
4 Constructing Your Own Classes
We will start by looking at how we find out what objects will be formed and then
how we construct the classes.
This chapter contains many coding details and offers several examples of
programmed classes. Some of the classes are applets that draw simple graphics on
the screen.
Several people can cooperate on a program. When they are each working on
their own parts, they can work independently from each other.
The building blocks can be tested and modified independently. We can program
one class at a time and test it before we go on to the next. During the course of
the development process, we will probably discover smarter ways to solve earlier
problems. If we don't alter the interface for the class, we can change the
implementation as often as we want, without affecting the other classes.
If we create the building blocks carefully, we can make some of them general
enough that they can be used later on. We have already seen several examples of
uses for ready-made classes. Gradually, we will build up our own library of
classes.
Classes make it possible to maintain perspective over the entire program and make
it feasible to create larger programs. Experienced developers put much effort and
consideration into selecting classes and distributing responsibilities between
classes. Classes maintain information about attributes and operations. The more
you manage to keep a class distinct from all the other classes, the better.
Before we can create our own classes, we have to develop an understanding of what
part of reality we want to model as classes. A class will be a description of a
collection of objects with the same attributes and operations. Therefore, we have to
start by asking what should be modeled as objects.
4.1 Creating Classes
Let's look at the renovation case study from chapter 2. The things our problem
deals with should be the basis for the objects in our model. We remember that
objects are always nouns and, from the description in the beginning of chapter 2,
we can make the following list of objects:
Floor
Wall
Flooring
Wallpaper
Paint
The next stage is to divide the responsibility for maintaining information and
carrying out calculations between the objects in question. The division should be
done in such a way that each object is as independent as possible from the other
objects.
4 Constructing Your Own Classes
These objects have to be described. Therefore, we need a class for each type of
object. A proposal for the division of responsibilities is shown in the class diagram
in Figure 4.1. Let's see if we can reason our way through this figure.
First let's look at the information that will be stored in the system. Generally, this
information will become attributes.
A wall knows about its own height and length. A floor has information about its
length and width. As clients, therefore, we can ask the wall about this. If we're going to
paint, we need to know the area of the wall or the floor. Again, as clients, we ask the
wall, "How big are you?".
Now we can draw an important conclusion that will simplify the rest of our
work. We see that, in this context, there is no difference between the floor and the
walls. We can generalize and combine the descriptions of these objects into a class,
the Surface class. We have also included the operation "Get circumference" in
the Surface class. For pedagogical reasons, we want a few more operations and
this will also make the class more useful in other contexts.
The flooring has information about its width and price per meter. The paint knows
what it costs, how many square meters it covers per liter, and how many coats are
recommended. The roll of wallpaper knows about its own width, length and price.
The most difficult thing is dividing responsibility for the calculations when
several objects are involved. 1 Should the wallpaper or the wall bear the
responsibility for calculating the number of rolls needed? If we let the roll of
wallpaper figure it out, we have to give it information about the size of the wall. If
the wall is going to calculate it, it has to know the length and width of a roll of
It should be mentioned that a fair amount of work has been done in trying to systematize the
division of responsibility. "Patterns" are central. For example, see [Larman 2000).
4.2 Programming a Class
wallpaper. In addition, if we are going to calculate the cost, we have to give the wall
information about the price of the wallpaper. Both of these alternatives are fairly
good, but in this case we let the wallpaper be responsible for this calculation. We
ask the roll of wallpaper, "How much of you do we need if you are going to be used
to wallpaper a wall that is 5 m long and 2.3 m high? And how much will it cost?".
"Get number of rolls" and "Get total price" thereby become operations for objects
in the W a l l p a p e r class. We give the operations the method names
getNoOfRolls( ) andgetTotalPrice( ).
We go through a similar reasoning process for paint and flooring. The paint is
responsible for calculating the number of liters needed for a given surface, and the
flooring will have to calculate the number of meters needed for a floor.
r
* We are going to test the Surface class.
* First we instantiate an object of the class,
* then we retrieve the data from the object and
* present them to the user. By doing this we will
* prove that the object really contains the correct data
* and performs its calculations correctly.
*/
class FloorCalculations {
public static void main(String args) {
/* Step 1 : We instantiate an object of the class. */
Surface aFloor = new Surface("Mary's floor", 4.8, 2.3);
/* Step 2: We retrieve data from the object,
and we let the object perform calculations. V
4.2 Programming a Class
/* Example Run:
Information about the floor with the name: Mary's floor:
Width: 2.3
Length: 4.8
Area: 11.04
Circumference: 14.2
*/
class Surface {
private String name; // for identification purposes
private double length;
private double width;
public Surface(String initName, double initLength, double initWidth) {
2. name = initName;
3. length = initLength;
4. width = initWidth;
}
public String getName( ) {
6. return name;
}
public double getLength( ) {
10. return length;
}
public double getWidth( ) {
8. return width;
}
public double getArea( ) {
12. return width * length;
Figure 4.2 The order the statements are performed in (continued overleaf)
4 Constructing Your Own Classes
class FloorCalculations {
public static void main(String args) {
/* Step 1 : We instantiate an object of the class. */
1 . Surface aFloor = new Surface("Mary's floor", 4.8, 2.3);
/* Step 2: We retrieve data from the object,
and we let the object perform calculations. */
5. String name = aFloor. getName(;
7. double width = aFloor.getWidth( );
9. double length = aFloor.getLength( );
11 . double area = aFloor.getArea( );
13. double circumference = aFloor.getCircumference( );
/* Step 3: We present the results on the screen for control. V
15. System.out.println("lnformation about the floor with the name: " + name + ":");
16. System.out.println("Width:" + width);
17. System.out.println("Length: " + length);
18. System. out.println("Area:" + area);
19. System.out.println("Circumference:" + circumference);
An instance method can use all the instance variables directly. Here we see that the
getArea ( ) method uses the instance variables length and width.
A method declaration consists of a method head and a method body. The method
head is what comes before the first brace {. The rest of the method is the contents of
the method, or simply the method body. Anyone who is going to use the class only
needs to recognize the method head. It's the method heads that form the interface
for an object of the class. The method head contains a list of parameters. This list
can be empty as is the case in all the methods in this example.
4.2 Programming a Class
class Surface {
private String name;
private double length; instance variables
private double width;
Figure 4.3 The connection between a class diagram and a class declaration
In addition to instance variables and instance methods, we will probably find one
or more constructors in a class. A constructor always has the same name as the class.
Constructors differentiate themselves from each other by having parameter lists
that differ in their number and/or type of parameters. A client uses a constructor to
instantiate an object of a class. From the example, we have the following (see point
1 in Figure 4.2):
Surface aFloor = new Surface("Mary's floor", 4.8, 2.3);
We are entering the values "Mary's floor", 4.8 and 2.3 as arguments. The arguments
can also be expressions or names of variables.
Let's follow the order in the statements from Figure 4.2 to see what happens
next. Now we come to the constructor, and the parameters receive values equal to
the arguments in question.The parameters should be viewed as local variables in
the method. We can imagine that the following occurs behind the scenes:
String initName = "Mary's floor";
double initLength = 4.8;
double initWidth = 2.3;
Now we're in the constructor. Three statements are executed:
2. name = initName;
3. length = initLength;
4. width = initWidth;
4 Constructing Your Own Classes
The instance variables now receive values that control the initial values mentioned
before.
Then we're back in the client program. We have now finished creating the object
aFloor. In the next statement, we are sending a message to this object:
5. String name = aFloor.getName( );
In other words, we are asking the floor, "What's your name?"
Now we'll go back to the class. This method has no parameters and the next
statement is:
6. return name;
The value of the instance variable name is returned to the client and there it is
stored in the client's variable, which also is called name. The reserved word
return takes care of the return transmission.
We skip to point 11 in the client program:
11. double area = aFloor.getArea( );
We return to the class and the following statement is performed:
12. return width * length;
width and length are instance variables that now have the values 4.8 and 2.3.
These are multiplied together and the result is returned to where the method was
called from. Thus, the area variable in the client program receives the value 11.04.
Overview: local variables, parameters and instance variables
Local variables are declared in a method and can only be used in the block where
they are declared. Local variables are not given any definite initial value. That's up
to the programmer. Parameters function as local variables with initial values
provided by the argument list in the method call.
Instance variables are declared in a class, but outside all the methods. They can
be used by all the methods in the class.
Instance variables are automatically given initial values according to their data
type. Variables of a number type get the value 0, while boolean variables get
false, and variables of a reference type get the value null.
Problems
1. Change the program in Program Listing 4.1 so that the user enters the width and
length.
2. The following assertions or Java statements are all incorrect. Explain what the
error in each one is:
4. The following client program uses the class from the previous problem. Fill in
what is missing (marked with ........ ).
class CircleCalculations {
public static void main(String[] args) {
------- aCircle = new-------;
double area = aCircle.-------;
System.out.println("The area is calculated to be " + area);
.............. = aCircle.getCircumference( );
System.out.println("The circumference is calculated to be " + circumference);
5. Name the local variables, the instance variables and the parameters in Program
Listing 4.1.
method consists of the method name, number and type of parameters. Neither the
return type nor the parameter names are a part of the method's signature.2
We have the following example from the String class (section 3.4):
int indexOf(int character)
int indexOf(int character, int fromlndex)
int indexOf(String substring)
int indexOf(String substring, int fromlndex)
These methods search the string and find the position of an individual character or
a substring.
Constructors and initializing instance variables
Instance variables can be given values in the declaration. Examples:
private String name = "";
private double length = 5;
If the variables are not given values this way, they get the value 0. Boolean variables
are given the value false, while reference variables get the value null.
A constructor is used to create an object as an instance of a class. This means that
memory is allocated for all the instance variables, and that the instance variables
are initialized with their initial values.
A constructor often provides values for the instance variables. These values will
control the initial values given in the declaration. The following code extract shows
three different constructors for the Surface class:
public Surface(String initName, double initLength, double initWidth) {
name = initName;
length = initLength;
width = initWidth;
}
public Surface(double initLength) {
length = initLength;
}
public Surface( ) {
}
The first constructor gives values for all the instance variables. The second only
gives a value for length, while the last doesn't give a value for any of the instance
variables.
If we don't create any constructors in a class, a default constructor will be created.
The constructor's parameter list and body will be empty. If we created constructors
in a class, this default constructor would not be created. If we then want a
constructor with empty parameter list to exist, we have to create it ourselves.
2. The definition of the term "signature" that we are using in this book refers to the programming
language Java. The UML definition of signature also includes the return type, name and direction (in,
out, in/out) of the parameters.
4 Constructing Your Own Classes
Note that the signature has to be different for all the constructors in a class.
Instance methods
The return type from a method is either a primitive data type or a reference type.
Examples from Program Listing 4.1:
public double getCircumference( ) {// the return type is a primitive data type
return 2 * (length + width); // returns a value that goes with the return type
}
public String getName( ) {// the return type is a reference type
return name; // returns the reference to an object
}
If the method doesn't return any value, the reserved word void should be used as
the return type. As an example, suppose we expand the Surface class with the
following method:
public void setWidth(double newWidth) {
width = newWidth;
}
This method changes the contents in an instance variable. Example of call:
aFloor.setWidth(5.3);
Here we are sending the message "Hi, you will have a new width of 5.3 meters!" to
the object aFloor. Often, methods of this type don't need to send data back to
the client, and therefore they are of the void type.
Since it's not very realistic that a floor would change its width, this method is not
included in the Surface class. In other contexts, this type of method can be very
appropriate, for example to change the price of a piece of merchandise.
A mutable class is a class that contains methods that change the values for the
instance variables. An immutable class is a class that does not contain these types of
methods.
Methods that implement operations that get attribute values or calculate results
from these values are called accessors. Accessors don't change the variables in a
class. An immutable class only has accessors.
Methods that implement operations that change the attribute values are called
mutators.
An instance method can contain its own local variables. We usually use these to
store results from intermediate calculations. For example, the method
getCircumference ( ) in the Surface class could have the variable sum as
the storage location for the sum of the length and width, before this is multiplied
by 2 and returned:
public double getCircumference( ) {
double sum = length + width;
return sum * 2;
4.4 Contents of a Class
In this case there isn't much point to a local variable like this serving as
intermediate storage, but in more complicated methods we will see that these are
indispensable.
If the return type is different from void, the method must contain at least one
return statement. For the time being there is no need for more than one return
statement, but later on we will see examples where this is appropriate.
A return statement consists of the reserved word return followed by an
expression of the same type as the return type, or of a type that can be automatically
converted to the return type (for automatic conversion, see section 2.8). If the
program control runs into a return statement, it immediately jumps out of the
method regardless of whether there are more statements in the method or not.
A method with the return type void can also contain the statement return ; .
The effect is the same as if a value was returned.
All the methods in a class must have different signatures.
Constants, variables and methods with the static modifier
In section 3.6 you learned about class constants and class methods in the Java
Library. We declare a class constant in this way:
private static final double VAT = 23.0;
If the constant is of interest outside the class, it can be given the access modifier
public.
There can also be class variables. These can be useful in very specific situations.
See problem 4 at the end of this section. There you'll learn to make class methods
as well.
But in object-oriented programming, class methods are rare and, with the
exception of main ( ) , we will create very few methods of this type in this book.
Hiding names and the reserved word this
If a local variable (or a parameter) has the same name as an instance variable, it is
the local variable that applies. We say that the local variable is hiding the instance
variable. Example:
private double length;
private double width;
public Surface(double length, double width) {
Writing the statement length = length; in this constructor body has no effect
since both the right and left sides of the assignment operator refer to the parameter.
If we insist on having the same name for the parameters as for the instance
variables, we can use the reserved word this to distinguish them from each other:
public Surface(double length, double width) {
this.length = length;
this.width = width;
4 Constructing Your Own Classes
this is a reference that always points to the object the Java interpreter is busy with
at any given time. We will not use this much in this book. Instead, we prefer to
let the parameters have different names from the instance variables.
Programming conventions for classes
Note that these are the code conventions we are using in this book. There are no
rules that the compiler requires us to stick to. In chapter 12 we will go through
several subjects that will somewhat expand the guidelines below.
Class names start with a capital letter. Variable names and method names start
with lower-case letters. If the name consists of several words, a capital letter is
used for the first letters of the second word and words that follow it. The
underline character and $ are not used.3
Constructors and members are grouped in the order shown in the syntax
description below.
Accessors and mutators whose jobs are to get or change an attribute have
standardized names:
If the attribute is of the data type boolean, the following method heads will be
used:
public void setNN/(boolean value)
public boolean isNN( )
In this book we have chosen to mark the parameter name in the mutator with
the prefix new. Example:
3. Exception: We are using the underline character in class names for answers to problems to indicate
which problem we're referring to, for example Problem5_4_2. This class shows the solution to
problem 2 after section 5.4.
4.4 Contents of a Class
Java Core
Declaring a class
These rules are not complete, but cover what we've covered in this chapter. Syntax
rules for abstract classes, subclasses and inheritance are found in Chapter 12. Inner
classes are discussed in Chapter 13.
A class declaration specifies a new reference type.
Syntax:
accessModifier class className {
classConstants
classVariables
instance Variables
constructors
classMethods
instanceMethods
}
The order of constructors and members in the class is not a part of the syntax. They
can be arranged in random order, but we recommend the grouping and order
shown here.
Syntax for constructors and members is shown in Table 4.1.
Problems
There are more problems here than usual and we recommend that you do as many
of them as possible. This material is both difficult and fundamental.
1. Suppose we create the Surface class without constructors. Is it then possible
to create instances of the class?
2. What is wrong with the following method that is supposed to set a value for the
variable width in the Surface class?
public void setWidth(double width) {
width = this.width;
}
3. These problems are based on the example in Program Listing 4.2. Download the
file, compile, and run the program. Make the changes stated below. Test the
program after each change. The program contains the class constants:
private static final double VAT = 20.0;
private static final double VATfactor = 1.0 + VAT /100.0;
These are constants that are communal for all the instances of the class. Any
method in the class can refer to these constants. For example, see the method
getPriceWithVAT().
4 Constructing Your Own Classes
A class method is called on behalf of the class. The most familiar class
method is main ( ). About parameter list, see constructor, above. If the
return type is not equal to void, the method has to return a value that
agrees with the type. The client can, but does not have to, make use of
this value.
instance accessModifier retumType methodName(parametertist) {
method statements
Problem (a)
A merchandise object has information about its own name, number and price.
A client must therefore be able to ask the merchandise for this information.
Create a method that gets the merchandise's product number. The method will
not print the product number, but send it back to the client. Enter a method call
in the client program so that you can test the method.
Problem (b)
Do the same for a method that gets the merchandise name.
Problem (c)
As mentioned above, it is possible to give instance variables initial values.
Example:
private String merchandiseName = "NN";
private int merchandiseNo = 0;
private double price = 0.0;
Insert this into the class. Give initial values in the client program using a
constructor. Find out which values are significant after an object is created.
Problem (d)
Expand the class with information about how much of the merchandise is in
stock. Let this be an integer. Change the constructor such that the initial value for
the amount of merchandise in stock can be set in addition to the other initial
values. Create methods to get, increase and decrease the amount of merchandise
in stock. You don't need to consider the possibility that the amount in stock
could be negative.
4. This problem shows how class variables work. This is not recommended for
beginners since it's easy to confuse this with instance variables.
Enter the following class:
class Room {
private static int lastUsedRoomNo = 0; II a class variable
private String name;
private int roomNo;
private int noOfSeats;
public Room(String initName, int initNoOfSeats) {
name = initName;
noOfSeats = initNoOfSeats;
lastUsedRoomNo = lastUsedRoomNo + 1; // increases the class variable
roomNo = lastUsedRoomNo;
}
public String getName( ) {
return name;
4 Constructing Your Own Classes
class Merchandise {
private static final double VAT = 20.0;
private static final double VATfactor = 1.0 + VAT / 100.0;
private String merchandiseName;
private int merchandiseNo;
private double price; // price per kilo, without VAT
public Merchandise(String initMerchandiseName,
int initMerchandiseNo, double initPrice) {
merchandiseName = initMerchandiseName;
merchandiseNo = initMerchandiseNo;
price = initPrice;
class PriceCalculations {
public static void main(String[] args) {
final double amount = 2.5;
final double kiloPricel = 7.30;
final double kiloPrice2 = 7.90;
Merchandise aMerchandise = new Merchandise("Brie", 123, kiloPricel);
double pricel = aMerchandise.getPriceWithoutVAT(amount);
double price2 = aMerchandise. getPriceWithVAT(amount);
System.out.println("The price per kilo without VAT: " + kiloPricel);
System.out.println("The price for " + amount + " kilos is " + price 1 + " without VAT");
System.out.println("The price for" + amount + "kilos is" + price2 + "with VAT");
aMerchandise.setPrice(kiloPrice2);
System.out.println("New price per kilo without VAT: " + kiloPrice2);
System.out.println("The price for " + amount + " kilos is"
+ aMerchandise.getPriceWithoutVAT(amount) + "without VAT");
System.out.println("The price for" + amount + "kilos is"
+ aMerchandise.getPriceWithVAT(amount) + "with VAT");
/* Example Run:
The price per kilo without VAT: 7.3
The price for 2.5 kilos is 18.25 without VAT
The price for 2.5 kilos is 21 .9 with VAT
New price per kilo without VAT: 7.9
The price for 2.5 kilos is 19.75 without VAT
The price for 2.5 kilos is 23.7 with VAT
*/
The main object here will be a counter that can be updated with new individual
votes and with new bundles of votes. Which is to say that it has to be possible and
easy to add a single new vote and to add a number of new votes. See Figure 4.4.
The operator ++ is called the increment operator, and it's used when the contents of
a variable are to be increased by 1 . The statement
numberOfYes++;
is the same as
numberOfYes = numberOfYes + 1;
We have a corresponding decrement operator, --, which reduces the value of a
variable by I.4
4. The complete names for these operators are the postincrement operator and the postdecrement
operator, "post" because the operator is placed after the variable name. We can also place ++ and --
before the variable name, and then the operators are called the preincrement and predecrement
operators. The difference is that for the postfix versions the value of the variable will be changed after
it has been retrieved from memory. The prefix version changes the value of the variable before it's
retrieved. It is possible to use expressions with these operations as part of larger expressions. Then
the pre and post distinction can become meaningful. We discourage this use of the operators since
expressions of this type are difficult to read. In this book we use only the postfix versions of the
operators, and we don't let the expressions be part of larger expressions.
4 Constructing Your Own Classes
The following method has an integer as an argument and increases the contents
of the instance variable numberOf Yes by this amount:
public void increaseNumberOfYes(int increase) {
numberOfYes += increase;
}
The statement numberOfYes += increase; is thus the same as
numberOfYes = numberOfYes + increase;. We call the operator += a
compound assignment operator. We have similar compound assignment operators
for subtraction, multiplication, division and the modulus operation.
Table 4.2 shows the connection between new and familiar operators.
Table 4.2 Increment and decrement operators and compound assignment operators
Problems
1. Write a test program for the class YesNo Counter.
2. What is printed when the following bit of code is run?
int value = 2;
value++;
value-;
System, out.println(value);
value += 5;
value *= 2;
value %= 3;
System, out.println(value);
3. Find out what the variables a, b and c contain after the following bit of code is
run:
inta = 10;
int b = 20;
int c = b % a;
c += a;
a *=c;
b--;
c/=2;
c %= 2;
4 Constructing Your Own Classes
contains the JApplet class, which is required in all applets in this book.5 Both of
the packages contain classes for the familiar graphic components such as, for
example, push buttons, list boxes, windows, etc. The components in the
javax. swing package are the newest and most useful. Therefore, those are the
ones we'll use in this book. We will come back to these components in chapter 13.
Here we are only using the class Container that we can think of as a container
where we put our drawings. Container belongs to the java . awt package.
The class SimpleApplet
(This section contains very difficult material. However, it's completely possible to
create applets without understanding all the details. We will come back to these
details in other contexts throughout the book, so that it will sink in gradually.)
The applet class will be constructed the same way in all the examples in this
chapter.
The SimpleApplet class is the class we refer to in the HTML file (see
Appendix E). The access modifier public is at the very beginning of the class
head. This means that the class is public and can therefore be accessed from all
locations. All applets have to be public.
the superclass
for all other classes
setBackgroundQ and
getBackgroundQ are inherited from here
getContentPaneQ
is inherited from here
5. Applets of this type require Java version SDK2. Currently very few browsers support this version.
There is a way round: search for the product HTMLConverter at [URL Javasoft].
4 Constructing Your Own Classes
After the class name comes extends JApplet. This means that the class is a
subclass of the JApplet class. We can imagine that the class JApplet describes
the set of (almost) all possible applets. The SimpleApplet class only describes
applets that look exactly like our small, simple one. This will be a subset of the first,
large set of applets. Everything that is true for the set of all applets is also true for
our special applet. We say that the SimpleApplet class inherits everything that
applies to all applets.
Figure 4.6 shows a segment of the class tree in Java. There isn't room in this UML
diagram to write more than the class names in the boxes. The relationship between
the classes is the main point of the class tree. At the bottom right we find the classes
mentioned before. We see that JApplet is a subclass of Applet, which in turn is
a subclass of Panel, etc. A subclass inherits methods from all classes above it in the
tree. Therefore we say that not only the Applet class is a subclass of the Panel
class, but also that all classes under Applet are subclasses of Panel.
On the other hand, Panel is a superclass for Applet, and for all classes under
Applet.
If we want to emphasize that a class comes directly above or below another, we
talk about direct superclass or direct subclass.
The Container class has two direct subclasses under it, namely
JComponent and Panel.
In the UML diagram, the arrow goes from the subclass to the direct superclass.
Figure 4.7 shows how the objects in a subclass are a subset of the objects in the
superclass. For example, the objects that are described by the Applet class are a
subset of the objects that are described by the Panel class.
We will say a lot more about subclasses and inheritance in chapter 12.
Figure 4.7 The objects the different classes describe form sets
The SimpleApplet class contains one method, init (). This is a method we
have in all applets, much the same way that we have main () in all applications.
4.6 Introduction to Applets
As opposed to main (), this isn't a class method, but an instance method. That
means that an applet object has to exist for the method to be carried out.
The Web browser instantiates the applet object and sends the message init () to
it. This starts the applet.
Of course the contents of init () will vary, but we will usually have to get a
reference for a container where we place what is going to be displayed on the
screen:
Container content = getContentPaneQ;
We see that there is no object name before get Content Pane (). That means
that the applet object (which we are now inside) is sending this message to itself.
The method getContentPane () is a method that is inherited from the
JApplet class. We will gradually see more examples of objects sending messages
to themselves, and they don't have to be only inherited methods. Any instance
method can be of interest.
The return type from getContentPane () is Container. Among other
things, we can send the message add () to these types of objects. And what are we
"adding" to a container? Well, the components that will be displayed in the applet
window. There's a drawing here.
This example doesn't show it, but it is of course possible to use the dialogs in
JOptionPane to communicate with the user. On the other hand, output from
System, out .println () statements are displayed in the console window,
which in a Web browser is called "Java Console", or something like that.
The class Drawing
All the applets in this chapter consist of a simple drawing. A drawing should be a
subclass of the JPanel class.
Drawing on the screen occurs when the Java interpreter goes through all the
components that make up the window and sends the message
paintComponent () to every single one of them. It is these components that we
have "added" to the "content pane", cf. previous section.6
Therefore, the class Drawing has to contain a method named
paintComponent (). The method head and first line always have to be as
follows:
public void paintComponent(Graphics window) { // can use a name other than "window"
super.paintComponent(window); // Remember this!
6. If we want to have more than one component in the window, we have to think about the so-called
layout-manager. See chapter 13.
4 Constructing Your Own Classes
The Java interpreter creates an object that represents the surface we are drawing on,
the graphics context. This becomes the argument for the method
paint Component (). This method is called by the interpreter. When the
program control gets into this method, the window parameter will refer to the
graphics context.
API Reference
(0,0) x,
x
Figure 4.8 The system of coordinates' origin is in the upper left-hand corner
API Reference
The method sets a specific color to apply for drawing in the window. The Color
class is described below.
public Font getFontQ
The method gets the font that will be used.
public Color getColorQ
The method gets the color that will be used.
The rectangle encloses the oval which the arc is a part of:
window.drawRect(40, 50, 200, 150);
window.setColor(color);
window.fillRect(40, 50, 20, 120);
The next rectangle will be a shade lighter. We create a new color and set it to apply:
color = color.brighterQ;
window.setColor(color);
We continue this way until all five rectangles have been drawn. The method
darker () makes the color darker.
API Reference
Methods:
public Color brighterQ
public Color darkerQ
These methods generate a new color object in a somewhat lighter or darker shade.
window.setFont(theFont);
window.drawString("This is written with the " + theFont.getName() + "font", 40, 100);
theFont = new Font("Monospaced", Font.ITALIC, 16);
window.setFont(theFont);
window.drawString("This is written with the" + theFont.getName() + "font", 40, 140);
theFont = new FontfDialog", Font.BOLD + Font.lTALIC, 16);
window.setFont(theFont);
window.drawString("This is written with the" + theFont.getName() + "font", 40, 180);
API Reference
Problems
1. Try the ColorDemo class with colors other than gray. Also try different
combinations of brighter () and darker ().
2. Change the SimpleApplet class in the following way:
Draw a filled oval instead of an empty one. Write the text under the oval. The
oval and the text should be in different colors.
3. Try different fonts by making changes to the FontDemo class.
access modifier The modifiers public and private (and protected, see chapter 12) control access
to classes, constructors and members. The class's access controls the constructors' and
the members' access if it's stricter.
Method that gets an attribute value or a calculated result. The method doesn't change
the attribute values.
class body The contents of the class, i.e. the part of the class declaration that follows the class head,
surrounded by {}.
class head A class head consists of a possible modifier, the word class and then the class name.
class tree A tree that shows the relationship between classes and subclasses. In Java, all classes are
connected in a single tree, with the class java. lang. Object at the top.
class variable A variable that is communal for all the instances of a class, declared with the modifier
static. The variable may be accessed even if no instances of the class exist.
compound assignment + = - = * = /= %=
operator The operators change the contents of a variable, for example, value * = 3 ,-
create an object An object is an instance of a class, and we create an object with the reserved word new
and a constructor. Memory is allocated for all the instance variables, which are given
their initial values.
decrement operator --, decreases the contents of a variable by 1, for example, number- - ;
default constructor A constructor which is made automatically if you do not supply one. The default
constructor does not take any arguments.
direct subclass A class directly under the class in question in the class tree. The reserved word extends
is used in the class head followed by the name of the class that this class will be a direct
subclass of. If extends is not used, the class becomes a direct subclass for
Java.lang.Object.
direct superclass The class directly above the class in question in the class tree. See also direct subclass.
4.8 New Concepts in This Chapter
extends The keyword that denotes subclassing, class A extends B means that A becomes a
direct subclass of B.
font, logical The following five font types will correspond to a font on the computer running the
program: SansSerif, Serif, Monospaced, Dialog, Dialoglnput.
get method Method that gets the value for an attribute.
graphics context The surface our program is drawing on, for example, a specific screen type.
immutable class A class that does not contain mutators.
increment ++, increases the contents of a variable by 1, for example, number++ ;
operator
inheritence Members that are inherited from a superclass can be used the same way in the subclass
as if they were declared in the subclass. Also see the definition in chapter 12.
instance variable Represents an attribute. Has to be declared in a class, but outside all the methods in the
class. Each instance of a class gets its own set of the instance variables.
member All instance variables and methods, and all class variables and methods, are members
of the class. Constructors are not members.
method body The part of the method declaration that follows the method head, surrounded by {}.
method head A method head consists of possible modifiers, then the method's return type (possibly
void) and then the method name and parameter list.
mutable class A class that contains mutators.
mutator Method that changes one or more attribute values.
null The value for a reference that doesn't point to any object.
overloading a name Inside a class, methods and constructors with the same name can be kept apart by
having different signatures. We say that the names are "overloaded".
package access The class, constructor or member is accessible in the package the class belongs to.
Package access applies if no access modifier is used.
pixel The smallest element in a graphics interface that can be assigned color or intensity
independently. [Hofstad, L01and, Scott 1997, p. 207]
postdecrementoperator See decrement operator.
postincrementoperato r See increment operator.
predecrement operator The operator -- located in front of the variable. Not used in this book. See footnote in
section 4.5.
The operator ++ located in front of the variable. Not used in this book. See footnote in
section 4.5.
primitive name Last part of a qualified name.
4 Constructing Your Own Classes
private A member or a constructor with the access modifier private is not accessible outside
the class where it's declared. Constructors are rarely private.
public A member or a constructor with the access modifier public is accessible anywhere as
long as the class the member is part of is also declared public.
return statement A statement that begins with the reserved word return. Makes sure that the program
control immediately exits the method and returns to the place it was called from. If the
return type is anything other than void, return has to be followed by an expression
of the same type as the method's return type, potentially a type that can be
automatically converted to the return type, return is rarely used if the return type is
void.
screen resolution Number of addressable points a screen is divided into,
static Modifier that states class constants, class variables or class methods.
subclass A class one or more levels below the class in question in the class tree. All messages that
can be sent to an instance of a class can also be sent to instances of this class's
subclasses. See also direct subclass.
superclass A class one or more levels above the class in question in the class tree. See also direct
superclass.
this This keyword is used in a method and it's a reference to the object the method is being
carried out for.
void Keyword that says the method doesn't return any value.
The client program will create several project objects. Also set up statements that
change the objects you have created.
Problem 4
Create an applet that draws a smiley face
Problem 5
Create an applet that inputs the attributes for a rectangle and then draws the
rectangle. While drawing, the area and circumference of the rectangle will be
printed. Let the background texts give hints for reasonable values, so that the
rectangle doesn't go outside the applet window.
Learning goals for this chapter
After completing this chapter, you will understand the following concepts:
Boolean expression
Structure the program code in a legible manner using indents and braces
All of the client programs we've written up to this point have been sequential in
nature. Their statements are performed in the order they appear. With the
multitude of ready-made classes available, it's possible to achieve relatively
complicated programs this way.
The opportunity to choose between several alternative execution ways can make
a client program more flexible. In this chapter, we'll look at how to program if
statements, as the selection mechanism is called.
We will also benefit a great deal from using the i f statement inside methods in
classes we create.
The recurrent example in this chapter will be a very simple calculator.
5 Selection as a Control Structure
Calculator
getNumberf
getNumber2
setNumbers
cateulateSum
calculateDifference
calculateProduct
calculateQuotiont
class Calculator {
private double number1;
private double number2;
public Calculator(double initNumber1 , double initNumber2) {
number1 = initNumber1;
number2 = initNumber2;
}
public double getNumberl () {
return number1;
Problems
1. Write a little program that tests all the methods in the Calculator class.
Remember to specially test what happens in the calculateQuotient ( )
method if one or both of the numbers is zero.
2. Expand the class with a method that solves a linear equation: ax + b = 0. Test the
method.
3. Modify the Calculator class so that it can solve a second-degree equation.
There is a ready-made method for calculating the square root of a number. The
usage example follows:
double root = Math.sqrt(number); // finds the positive root
Hint: You have to create a method for each of the two roots. As a test, you can
use the equation 2x2 - 4x - 16 = 0. It's solutions are X1 = 4 and x2 = -2.
5 Selection as a Control Structure
1
I read two numbers
calcus.calculateSum()
calcus. calcus.
calcultateDifference() calcultateSum()
Figure 5.2 A client object sends messages to the calcus object (UML)
Selection is a control structure that enables the program to choose one set of
instructions or another depending on what it will do in a given situation. If we
instantiate an object of the Calculator class, we will send messages to this
instance, depending on whether we want to add, subtract, multiply, or divide the
two numbers in question. The selection control structure is the theme of this
chapter.
5.2 A Selection is a Control Structure
A loop is a control structure that makes it possible to run through the same
sequence of instructions several times. This makes it easier to run test programs and
makes it possible, for example, to do several transactions at a time in a bank
account or to calculate the renovation costs for several rooms in a condominium.
The loop control structure is the topic of the next chapter.
We use activity diagrams to illustrate control structures. Activity diagrams are part
of UML.
Figure 5.2 shows examples of the sequence and selection control structures.
We're inside the client program. The client program can be considered a client
object that goes from state to state. Every "box" in the figure represents a state of
activity. The client object is active in this state. The client object on the left can only
add two numbers together. The one on the right gives the user a choice between
addition and subtraction. We'll program this shortly. Later, we'll find out how to
let the user choose between all four arithmetical operations.
The notation used in an activity diagram is presented in Figure 5.3.
Each individual selection always has to be worded as a yes/no question. The
activity diagram doesn't show the questions, only the pertinent answers stated as
assertions, or conditions. A condition has two possible values: true or false. Hence,
the condition "will add the numbers" is the opposite of the condition "will not add
the numbers". The question is, "Should the numbers be added?" On the right, the
answer is "yes". On the left, the answer is "no". The conditions set up in the
diagram should be the opposite of each other, as the example shows. We can't write
[will subtract from each other] on the left. In that case, we would have had to ask
another yes/no question.
initial state
() final state
[text] condition
branch / join
activity state
Figure 5.4 shows data input for the calculator. The showConfirmDialog ()
method in the JOptionPane class makes it possible to ask yes/no questions.
Study Program Listing 5.2 along with Figure 5.4. The user presses one of the
buttons1, and the method returns an integer value depending on which button was
pressed. By comparing this value with class constants, we can make sure that the
program is doing what the user want.
The method for asking the user yes/no questions has the following head:
public static int showConfirmDialog(Component parent,
Object message, String title, int combinationOfButtons)
The button combination is a constant in the JOptionPane class. We used
YES_NO_OPTION (there are other possibilities in the API reference below).
The program uses the method this way:
int answer = JOptionPane.showConfirmDialog(null, "Add the numbers? ",
"Calculator", JOptionPane. YES_NO_OPTION);
Depending on the value of the answer, the program will add or subtract. We use
what we call an i f statement:
1. The user should click with the mouse or press Alt-N to get the No-button pressed. Just tab and
pressing the Enter-key do not work (at least not in the Windows environment).
5.2 A Selection is a Control Structure
/* Example Run:
See figure 5.4
*/
API Reference
These methods make it possible for the user to choose between several alternatives.
They are relatively difficult to use, and we recommend that you study the example
in Section 5.5 before reading the facts below. See also Figure 5.7 and table 5.1 later
in this chapter.
showOptionDialog () shows the options as pushbuttons, while
showInputDialog () shows the options in the form of a list (dropdown list if
fewer than 20 alternatives).
The parameters parent, message, title, typeOfMessage, and icon
are explained in Section 3.7. combinationOfButtons is explained above.
options is an array of the possible options. They can be e.g. texts or icons.
initialOption shows what will be selected if the user doesn't make a choice
of his own.
showOptionDialog () returns the number of the option selected. The first
option has number 0. If the user presses Cancel, the dialog closes and the constant
CLOSED_OPTION is returned.
showInputDialog () returns a reference to the object selected. If the user
presses Cancel, null is returned.
Problem
Modify the program so that it gives the user the choice between multiplying and
dividing.
Figure 5.5 The scope for names in the revised calculator program
Problems
1. The following is given:
double sum = 0.0;
int value = 10;
if (value > 5) sum += value;
else sum -= value;
What is the value of sum after this section of a program is executed?
2. The following is given:
2. In the examples in this book, it will often look as though the indentation is less than two positions.
This is because we are writing program code in a proportional font out of space considerations. If
you look at the Java files in an editor, you will see that a two-position indent is used.
5.4 The if Statement
[not (boolean
expression)] [boolean expression]
/ X if (boolean expression)
statement1
else
statement2
if (boolean expression)
statement1
[not (boolean
expression)]
Java Core
The if statement
Syntax:
if (booleanExpression)
statement1
or
if (booleanExpression)
statement1
else
statement2
statement 1 and/or statement2 can be a block.
The boolean expression is evaluated. If the value is true, statement 1 is
executed. If the value of the boolean expression is false, one of two things takes
place:
Examples:
if (number > 10) {
number = 0;
System.out.println("Number is set to 0");
} else {
number++;
System.out.println("Number is increased by 1");
}
if (number1 > number2) number1 = number2;
A return statement inside the if or else block abruptly completes the
method you're in.
After some time, we've found an error in the program. In addition to the statement
sum += a ; we will also change b if a > b. We modify the bit of code so that
now it looks like this:
if (a > b)
sum += a;
This gives the visual impression that the two statements form a block that will be
executed if a > b. This doesn't happen. The statements aren't enclosed in {}.
Therefore, the statement b++ ; will be executed regardless of whether a > b or not.
If the statement that is to be executed is in a line by itself, it should be
enclosed in {} to prevent errors from cropping up during later maintenance of
the program. The pieces of code above should therefore look like this:
if (a > b) {
sum += a;
and
if (a > b) {
sum += a;
Problems
1. Set up if statements for the following:
(a) If number is greater than 20, code will be set to 'M' (for "many"),
otherwise, code will have the value 'F' (for "few").
(b) If "body mass index" (BMI) is greater than 25, print out "You weigh too
much", otherwise, nothing will happen. BMI is calculated according to the
formula (weight / (height * height)). Weight is measured in kilograms, height in
meters.
2. Write the following segment of code according to the recommendations for
indenting and {} given above. Then find the values for all the variables after the
code segment has been executed.
int a = 20;
int b = 30;
int p = 20;
int q = 40;
int r = 30;
ints = 15;
if (a <b) a = b;b = 10;
if (p==20) q = 13;else q = 17;
5.5 Nested if and Multiple-Choice Statements
if (r>s) {q=100;
} s = 200;
3. What do the following statements do?
if (size > 38);
else System. out.println("Small!");
How should this section of code be written?
as if and else. We should make use of this to improve the readability. We write
the example in the following manner:
if (temperature > 0) System.out.println("Degrees above zero.");
else {
if (temperature == 0) System.out.println("Zero degrees');
else System.out.println("Degrees below zero.");
} // end of the outermost if-else statement
Furthermore, we observe that there's actually only one statement, namely an if
statement, after the first else. Even if this statement doesn't fit on one line, we
usually omit {} in multiple choice statements like this. Now the lines can be written
this way:
if (temperature > 0) System.out.println("Degrees above zero.");
else if (temperature == 0) System.out.println("Zero degrees");
else System.out.println("Degrees below zero.");
What does the Object data type mean? From Figure 4.6 we see that the
Object class is a superclass to all the other classes. That means that the
description given for the Object class applies to all possible objects. In
practice, this means that if the parameter type is Ob ject, then the argument can
be of any class.
What does the symbol [ ] mean? We want to present the user with multiple
choicesthis symbol says that the parameter options can receive more than
one value as its argument. We submit an "array" of all the possible choices. We
make the array this way:
3. Note that you have to click on the correct pushbutton with the mouse, just tabbing with the tab-key
and pressing Enter do not work (at least not in the Windows environment).
4. Arrays are covered in chapters 9 and 10. For now, we're just mentioning what we need to use these
methods.
5.5 Nested if and Multiple-Choice Statements
We will construct a string that contains the math problem in question. The string
is printed in a message box. (Example: 2.3 + 5.6 = 7.9.) The operator depends on
the operation, and we store it in the variable operator.
A boolean variable ok keeps track of whether or not errors occur. The only error
of interest here occurs if the user asks to divide by zero. Then ok is set equal to
false, and the division is not performed.5 We also set ok equal to false if the
user hits the Esc key or closes the dialog. In these cases, the variable option is set
to equal the value CLOSED_OPTION.
Table 5.1 The relationship between parameters and arguments in the showOptionDia-
log () method
5. We execute the test if (number2 == 0 . 0)... We can do this because the numbers are input. If
the numbers have been computed, we can't use a test this simple between variables that contain
decimal numerals. We will spend more time on this at the end of this chapter.
5.5 Nested if and Multiple-Choice Statements
import javax.swing.JOptionPane;
class TestCalculator2 {
public static void main(String[] args) {
/* Reading data */
String numberlRead = JOptionPane.showlnputDialog("First number:");
String number2Read = JOptionPane.showlnputDialog("Second number:
double numberl = Double.parseDouble(number1 Read);
double number2 = Double.parseDouble(number2Read);
String[] options = {"plus", "minus", "multiply", "divide"};
int option = JOptionPane.showOptionDialog(null, "Choose operator",
"The four arithmetical operations", 0, JOptionPane.PLAIN_MESSAGE,
null, options, options[0]);
/* Calculating results */
Calculator calcus = new Calculator(number1, number2);
double calculatedAnswer = 0.0;
char operator = "; // uses this in the result string
boolean ok = true;
if (option == 0) {
operator ='+';
calculatedAnswer = calcus.calculateSum();
} else if (option == 1) {
calculatedAnswer = calcus.calculateDifferenceQ;
operator = '-';
} else if (option == 2) {
calculatedAnswer = calcus.calculateProduct();
operator = '*';
} else if (option == 3) {
5 Selection as a Control Structure
operator = '/;
if (number2 == 0.0) ok = false; // we have to avoid division by zero
else calculatedAnswer = calcus.calculateQuotient();
} else { // Esc is typed, or the dialog is closed
ok = false;
}
/* Printing the result */
String result;
if (ok) result = number1 + " " + operator + " " + number2 + " = " + calculatedAnswer;
else result = "It is not possible to calculate a result.";
JOptionPane.showMessageDialog(null, result);
System.exit(0);
/* Example Run:
First number: 12.5
Second number: 3.56
Choose the operation "multiply"
Result: 12.5* 3.56 = 44.5
First number: 12.5
Second number: 0.0
Choose the operation "divide"
Result: It is not possible to calculate a result.
*/
A possible trap...
Try to find out what prints out when the following bit of code is run:
inta = -10;
int b = 20;
if (a > 0) {
if (b > 10) b = 10;
}
else a = 0;
System.out.println(a + " " + b);
a = -10;
b = 20;
if (a > 0)
if (b > 10) b = 10;
else a = 0;
System.out.println(a + " " + b);
Aside from the fact that the bottom section of the code doesn't contain curly braces
in the prescribed locations, is there any difference between these two pieces of
code? The indentation gives the impression that the author means the same thing
namely, that a is set equal to 0 if a is not greater than 0.
5.5 Nested if and Multiple-Choice Statements
This is explained by the fact that the bottom else belongs to the if statement
immediately above it, so that a is set equal to 0 only if b is not greater than 10. We
come to the following conclusion:
If you use multiple if statements inside each other (nested if), and an else
block doesn't belong to the closest preceding if, it has to be marked with {}.
Decision tables
A special application of multiple choice statements is programming decision tables.
Table 5.2 shows an example of a decision table.
A method that calculates the grade, when the point total is given as an instance
variable, looks like this:
public char getGrade() { // returns an 'X' if too many points, a 'Z' if too few points
if (points > 100) return 'X';
else if (points >= 90) return 'A';
else if (points >= 80) return 'B';
else if (points >= 70) return 'C';
else if (points >= 60) return 'D';
else if (points >= 0) return 'F';
else return 'Z';
}
Note that the order of the i f statements is not arbitrary. How would the program
behave if we change around the tests for the two upper limits (90 and 80)?
Table 5.2 A decision table to determine the grade when the point total is known
Points Grade
90-100 A
80-89 B
70-79 C
60-69 D
0-59 F
5 Selection as a Control Structure
Problems
1. Make an activity diagram for the client object in Program Listing 5.3.
2. Rewrite the code below so that the indentation and {} placement follow the
recommendations listed earlier. Then find out what is printed out.
int a = 20;
int b = 30;
int c = 40;
if (a > b) a = b; else { a = c;
b = 50;
if (a > 50) a =100;}
System.out.println("a = " + a + ", b =" + b + ", c = " + c);
3. Rewrite the coding for the decision table above so that you're using "less than"
tests instead of "greater than or equal to" tests.
4. Program the class that the method get Grade () belongs to. Write a little test
program.
6. There is also the instanceof comparison operator. This is covered in chapter 11.
5.6 Boolean Expressions
Examples:
numberOfStudents < lowerLimit
price * number != 5
numberOfMen + numberOfWomen == totalNumber - numberOfChildren
The arithmetical operators have higher priority than the comparison operators. The
last two expressions are calculated as if they said:
(price * number) != 5
(numberOfMen + numberOfWomen) == (totalNumber - numberOfChildren)
Constants and variables of the data type char can also be compared. The extent to
which a character is "greater" or "less" than another character is determined by
where the character comes in the Unicode ranking. The letters a-z are in
alphabetical order so that we can use the operators to sort.7
We can create more complex expressions by combining simple boolean
expressions using the following two operators:
&& conditional-and (or only: "and")
|| conditional-or (or only: "or")
The operators are listed in order of priority. Table 5.4 summarizes the operators
we've covered up to this point. Operators in the same group have the same priority.
If we have several operators in an expression with the same priority, they are
interpreted according to associativity. Most are interpreted from left to right.
Expressions with assignment operators are interpreted from right to left. In most
practical cases, however, it's sufficient to think about left-associativity, which, for
example, means that the expression (5 * 10 / 2) is evaluated from left to right, like
this: (5 * 10) / 2.
Here are some examples of combining simple boolean expressions:
We want to know if the number of students is in the closed interval [20, 30]. We
can't write this the way we would in math: 20 <= number <= 30. Instead we have
to create a compound boolean expression:
We want to know the opposite: is the number of students outside the interval
[20, 30]? We can write it like this:
7. Those who use an alphabet with letters outside a-z should take care and check the ordering of the
letters. See [URL Unicode].
5 Selection as a Control Structure
Table 5.3 Truth tables for the conditional-and and conditional-or operators
false
false
false
false
Comparing strings
A method call with the return type boolean will be a boolean expression. As an
example, we'll look at the possibilities in the String class for comparing strings.
First we try the equals () method. The piece of code: (top of page 148)
5.6 Boolean Expressions
Table 5.4 Operators in the same group have the same priority, highest at the top of the
table
multiplication left
division
modulo
addition left
subtraction
less than left
less than or equal to
greater than
greater than or equal to
equal to left
not equal to
conditional-and left
conditional-or left
assignment right
compound assignment operator
compound assignment operator
%= compound assignment operator
compound assignment operator
compound assignment operator
5 Selection as a Control Structure
We can use the operator == between operands of the String type. The expression
is true if both of the operands point to the same String object. To compare the
contents of the String objects, we have to use methods in the String class.
API Reference
Comparison methods:8
8. For those with an alphabet with letters outside a-z: With the exception of the equals () method,
you should check if the methods work for letters outside a-z. In chapter 10, we will see that it's
relatively easy to achieve a comparison that works for these letters as well, without using multiple
choice statements that treat the characters specially, as we often have to.
5.6 Boolean Expressions
Short-circuit evaluation
If a boolean expression contains && or ||, Java uses short-circuit evaluation. That
means the computation ends as soon as the result is determined. If there's an "and"
between the expressions, the evaluation continues as long as the expressions are
true. The instant the Java interpreter encounters the first expression which evaluates
to false, the compound expression as a whole will be false, and it can terminate the
computation. If there's an "or" between the expressions, the opposite happens. The
interpreter keeps going as long as the expressions are false. The instant one of them
is true, it can stop, because then the whole expression is true.
For example: we want to find out if the square root of a number is less than
limit. But we don't want to try to figure out the square root at all if the number
is negative. So we can write
if (number >= 0 && Math.sqrt(number) < limit)....
The value of the expression number >= 0 is evaluated first. Only if this expression
is true will the computation continue such that the square root is calculated.
Problems
1. Set up the boolean value for each of the following expressions:
(a) The number of students will be between 20 and 30 - i.e., 20 and 30 aren't
legal numbers.
(b) The winning lottery numbers are 3, 18, and 25.
(c) The answer to the question should be an upper- or lower-case 'Y' (for "yes").
(d) The temperature has to be outside the closed interval [15, 25].
(e) The sum will be positive and outside the open interval <10, 100>.
(f) The character has to be a letter (A-Z), capital or lower-case.
5 Selection as a Control Structure
default label. There are a great many rules and limitations associated with
the switch statement. These are listed in the following syntax description:
Java Core
If the program control encounters break, it jumps out of the switch block.
Otherwise it continues through the other labels up to the first break,
potentially to the end of the switch block.
Example:
String text = JOptionPane.showlnputDialog("Which place?");
int place = Integer.parselnt(text);
5 Selection as a Control Structure
switch (place) {
case 1:
JOptionPane.showMessageDialog(null, "Gold!");
break;
case 2:
JOptionPane.showMessageDialog(null, "Silver!");
break;
case 3:
JOptionPane.showMessageDialog(null, "Bronze!");
break;
case 4:
/* falls through */
case 5:
/* falls through */
case 6:
JOptionPane.showMessageDialog(null, "You have points!");
break;
default:
int luckyNumber = (int) (100 * Math.random() + 1);
JOptionPane.showMessageDialog(null, "Thank you for honourable achievement!\n" +
"Your lucky number is:" + luckyNumber);
break;
}
If break is skipped, we recommend the comment /* falls through */ as
shown in the example above.
The class method Math. random () is used in the example. This method creates
a random decimal numeral in the interval [0.0, 1.0>. By multiplying by 100, we get
a random number between 0.0 and 100.0. By adding 1 and converting the result to
int using casting, we end up with a "lucky number" in the interval [ 1, 100].
Problem
Point out errors and weaknesses in the following switch statement:
switch (dayOfWeek) {
case 1, 2:
System.out.println("ln the beginning of the week");
case 3, 4:
System.out.println("ln the middle of the week");
case 5:
System.out.println("Near the end of the week");
case 6, 7:
System.out.println("Weekend");
5.8 Comparing Computed Decimal Numerals
Never use the operators == and ! = to compare results from calculations involving
decimal numerals. Instead, check that the difference between the numbers is less
than a given tolerance:
final double tolerance = 0.00001;
if (Math.abs(number1 - number2) < tolerance) {
System.out.println("The numbers are almost the same");
} else System.out.println("The numbers are different.");
Remember to use the absolute value of the difference between the numbers.
The size of tolerance has to be in proportion with the size of the numbers
that are being compared. For instance, in this example, numbers where both are
smaller than 0.00001 will be considered as equal regardless of how different they
are.
Java Core
The value of the expression as a whole is determined by the value of the boolean
expression. If the boolean expression is true, the value is equal to expression1;
otherwise, the value is equal to expression2.
The operator is left-associative and it's prioritized just above the assignment
operators.
For example:
max = (number2 > number1) ? number2 : number1;
is the same as:
if (number2 > number1) max = number2;
else max = number1;
Many people find expressions that use this operator difficult to read. Therefore, we
don't use this operator in this book.
associativity Direction of interpretation (from the left or from the right) in an expression.
break Keyword that interrupts sequential program flow.break means that the program control
jumps out of the switch block (and other blocks, but this isn't used in this book).
comparison Operators that make it possible to compare values (less than <, greater than >, etc.).
operator
compound boolean Two or more comparisons combined using conditional-and and/or conditional-
expression or operators.
Birthday Room
1-8 113
9-14 120
15-25 125
26-31 134
5.12 Programming Problems
Problem 3
In this problem, you will use the ForeignCurrency class from programming
problem 2, chapter 4.
Make an activity diagram that shows how a client object (client program) lets the
user choose which direction the currency exchange will take place in.
Write the client program.
Problem 4
A year is a leap year if it's divisible by 4. Years ending in 00 are the exceptionthey
have to be divisible by 400. Write a program that inputs a year from the user and
finds out if it's a leap year.
Problem 5
We will write a program that helps us with the following problem: ground meat
from brand A costs $3.60 for 450 grams, while ground meat from brand B costs
$3.95 for 500 grams. Which brand is cheaper?
Create a Brand class. Suggest attributes and methods that are relevant for this
problem.
Make an activity diagram that shows how a client object (client program) can use
instances of this class to find out which of the two brands is cheaper.
Write the client program.
This page intentionally left blank
Learning goals for this chapter
After completing this chapter, you will understand the following concepts:
Initializing loops
Loop conditions
Counter-controlled loops
Endless loops
Formulate loops by identifying the different parts of the loop and selecting the
right loop statement (while, for, or do-while)
In this chapter, we'll cover the third control structure, loops. Up to this point, we've
written several programs to test classes. We've had to run the programs again for
each new set of test data. Now we'll find out how to program this reiteration.
Loops can also be used in many other contexts. We'll look at a graphics example.
Further on in the book, we'll use loops to search for data values, sort data, and
much more.
There are three different loop statements in Java. The while and for
statements can, in principle, be used for the same thing, but they have come to be
used somewhat differently in practice. The do-while statement is useful when
inputting data from the user, and especially if the program is going to test the
validity of this data.
6 Loops as a Control Structure
loop initialization
loop condition
loop body
It's the while statement in the program code that causes a set of instructions to be
executed multiple times. In this context, while can best be interpreted as "as long
as": as long as counter is less than 5, the following will be done: print a text and
increase counter by 1.
In the previous chapter, we covered if statements. The main difference between
while and if is that a block in a while statement can be executed many times,
while a block in an if statement is never executed more than once. else cannot
be used in conjunction with a while statement.
A counter-controlled loop is a loop where the number of iterations is known in
advance. In the example, we decided to print out five lines and we use a "counter"
to keep track of the number. In the next section, we will look at loops where the
number of iterations is not known in advance.
Initialization
Loop condition
We will look more closely at what these concepts entail by tying them to the simple
example above (see also the right side of Figure 6.1):
Initialization: This is program code that makes it possible to answer the yes/no
question in the while statement the first time the program control reaches it.
Here the question is: "Is counter < 5?". In order to answer this, counter
needs to have a value. Initialization consists of setting counter to equal 0 just
before the while statement.
Loop condition: This is the yes/no question. The condition is a boolean
expression as in an if statement. In the example, the loop condition is
(counter < 5) .
Loop body: This is comprised of the statements that will be executed if the loop
condition is true. If there's more than one statement to be executed, the
statements have to be collected in a block using {}. The recommendations for
using {} and indentation are the same as for if statements. In the example, the
loop body consists of the following statements:
6 Loops as a Control Structure
System.out.println("This is a line.");
counter++;
Update condition: The loop body must include a statement that changes the
value of the loop condition from true to false. If this is not the case, the loop will
never stop and will be an endless loop. In the example, it's the statement
counter++; that finally makes the loop condition false. Usually we find the
loop update condition near the end of the loop body.
It's customary to start the counter for a counter-controlled loop at 0 and not 1. If
the loop is to be run N times, the condition will be (counter < N).
Java Core
Problem
The loop in the example is executed exactly five times. Modify the example so that
the loop is executed 0 times, and then an infinite number of times.
1
loop initialization
loop body
loop condition update
/* Example Run:
97
12
45
We had to draw 3 numbers until we got an illegal one: 74
*/
Loop constructions always need to be tested. We always have to formulate test data
that will catch the following situations:
The loop runs 0 times. The test data must make the condition false the first time
the program control comes to the while statement. Do all the variables have
reasonable values after the loop statement, even if the program control isn't in
the loop body at all?
Is it possible to construct data that never makes the loop condition false? If yes,
that means you've created something that can become an endless loop. The loop
6.2 A Loop with a General Condition
wouldn't stop unless it's interrupted from the outside in some way. This is
usually a mistake.
If you have problems getting the loop to work, insert print statements
(System. out.println ()) in appropriate locations to check that the data has
relevant values and to check if the number of iterations is correct.
Problems
1. In the section of code below, random numbers in the interval [1, 500] should be
drawn. Insert this drawing for the numbers into the right place. Also fill in
anything else that's missing in the following section of code:
int smallNumbers = 0;
int bigNumbers = 0;
while (.....) { // finish when the number 250 is encountered
....if number is greater than 250 increase bigNumbers by 1 ,
....otherwise increase smallNumbers by 1.
}
2. Find logical errors in the following program that should calculate xn, where n >=
0:
import javax.swing.JOptionPane;
class Problem6_2_2 {
public static void main(String[] args) {
String inputBase = JOptionPane.showlnputDialogfWhat is the base? ");
String inputExponent = (JOptionPane.showlnputDialog("What is the exponent? ");
double x = Double.parseDouble(inputBase);
int n = Integer.parselnt(inputExponent);
double answer = 0;
int counter = 1 ;
while (counter < n) {
answer *= n;
3. Make a test data set for the program in the previous problem.
4. The situations below can be formulated as loops. In each case, identify the
individual parts the loop consists of. Make activity diagrams.
(a) Edward will water all the flowers in the living room.
6 Loops as a Control Structure
(b) Jane forgot the key. She has to look for an open window she can climb in
through.
(c) Matthew will count how many days he biked to and from school in May.
Figure 6.3 The spots are spread randomly throughout the window
We have a counter-controlled loop with a condition (counter < 10).
Updating the condition will consist of increasing counter by 1. How should we
set up the initialization and in what order should we insert the instructions in the
loop body? Initialization, in addition to setting counter = 0, will consist of
finding the first point and drawing the first filled circle. The loop body will thus
consist of drawing a line, followed by drawing a circle with the line's end point as
its center.
Study Program Listing 6.2. Pay special attention to how the variables lastX
and lastY are used to keep track of the end point of the previous line. The first
time, lastX and lastY are equal to the first point. The arguments x and y for
the fillOval ( ) method denote the upper left comer of the square that
6.3 A Graphics Example
surrounds the circle that will be drawn. Thus diameter is subtracted from the
height and width of the window when it's time to determine x and y.
Problems
1 . Modify the applet so that the last filled circle is connected to the first filled circle
by a line.
6 Loops as a Control Structure
2. Modify the applet so that every other circle is filled and every other circle is open.
int counter
while (counter < 5)
System. out println("This is a line.");
counter+
The relationship between while and for statements is shown in Figure 6.4.
Notice that we can (but don't have to) declare the counter inside the for
statement. In this case, the counter's scope will be the for statement. If we're going
to make another for loop, we have to declare counter again.
Java Core
Syntax:
for (looplnitialization; loopCondition; loopConditionUpdate)
statement
corresponds to the following while statement:
looplnitialization
while (loopCondition)
statement incl. loop condition update
statement can be a block.
Variables declared in the initialization portion of the for statement have the
loop body as their scope.
It's customary to use a for statement for counter-controlled loops, and for
loops where an integer variable increases or decreases by a fixed value for every
iteration.
Example:
/* draws 30 circles one after the other */
int x = 0;
int y = 50;
for (int counter = 0; counter < 30; counter++) {
window.drawOval(x, y, 20, 20);
x += 20;
}
Other for statements:
for (int number = 1000; number > 500; number-) { // counts down from 1000 to 501
for (int xPos = 100; xPos < 800; xPos += 5) { // increases by 5 for every iteration
for (int membNo = 101; membNo <= 900; membNo++) {// member no. from 101 to 900
Problem
In the syntax description above, there's a small section of code that draws 30 circles.
Insert this into an applet and run it. Modify it so that the size of the circles increases
by 2 pixels in diameter for every iteration. Every other circle should be filled, and
every other one open.
* The program calculates and prints all sums in the interval [0, 9]
*/
class SumNumbers {
public static void main(StringQ args) {
for (int lineCounter = 0; lineCounter < 10; lineCounter++) {
int sum = 0;
for (int number = 1 ; number <= lineCounter; number++) {
sum += number;
System.out.print(number + " ");
}
System.out.println("The sum is: " + sum);
/* Example Run:
The sum is: 0
1 The sum is: 1
1 2 The sum is: 3
1 2 3 The sum is: 6
1 2 3 4 The sum is: 10
1 2 3 4 5 The sum is: 15
1 2 3 4 5 6 The sum is: 21
1 2 3 4 5 6 7 The sum is: 28
1 2 3 4 5 6 7 8 The sum is: 36
1 2 3 4 5 6 7 8 9 The sum is: 45
V
Problems
1. What is printed when the following program runs?
public class Problem6_5_1 {
public static void main(StringQ args) {
String text = "ABVVUIHJV";
char luckySymbol = 'V;
int noOfTimes = 1 ;
for (int counter = 0; counter < text.length(); counter++){
char character = text.charAt(counter);
if (character == luckySymbol) {
noOfTimes *= 2;
for (counter = 0; counter < noOfTimes; counter++) {
6.6 The do-while Statement
System.out.print(character);
}
System.out.println();
2. Modify the applet in Program Listing 6.2 so that, instead of each filled circle, it
draws out concentric (i.e. with the same center) open circles the first time 1, the
second time 2, etc. The smallest of the circles will have a diameter of 6 pixels.
Then the size increases by 4 pixels for every circle. The x and y values are found
this way:
x = (int) (windowWidth * Math.random() + 1);
y = (int) (windowHeight * Math.random() + 1);
Java Core
We will write a client program that uses the YesNoCounter class from chapter 4.
The program will be used to register results from yes and no lists that people have
signed themselves up on. We have, for example, the following:
12 yes answers
14 no answers
32 yes answers
20 no answers
71 no answers
etc
We let an instance of the YesNoCounter class keep track of this. Let's call the
instance addingMachine. The appropriate message, depending on the yes or no
answers, is sent to the instance. This is repeated as long as there's data to input into
the program.
We need a loop and have to identify the parts that the loop will consist of: we
already know something about the loop body. It will consist of sending the right
message to addingMachine. What will the condition be? The condition for
continuing is that the user has more data to input. How should we word it? We
can't use a counter-controlled loop since we can't insist that the user count the lists
in advance. At a given point in time, the user will have to tell the program that
there's no more data to input. How should we do that? Let's look at the input data
for the program.
The number of yes and no votes is input data. These are integers different from
0 with additional information about the type of vote. We are not yet able to create
a custom graphical user interface. What can we do? We can input an integer, and
for every number ask the user if they were yes or no votes. And for every number
we can also ask if there are more results to be input. In the long run, this is very
inconvenient for the user. Instead, we assume that yes votes are input as positive
integers, while no votes are input as negative. Then we're left with a number that
isn't used, namely 0. We can let the user write 0 to indicate that now there's no
more data to enter.
Now we can write the loop condition: number ! = 0.
Updating the loop condition will consist of reading a new number.
What about initializing the loop? This initialization will differ depending on
whether we choose a loop construction where the test of the condition comes at the
beginning of the loop (while or for) or a loop construction where the test of the
condition comes at the end of the loop (do-while).
Since the program's purpose is to input data, we can assume that the loop will
always be run through at least once. Therefore, we choose to use a do-while
loop. (If we think the user might change his mind after he's started the program,
but before any data has been input, then we should use a while loop.) What is
then the initialization? See Program Listing 6.4. What's required for the loop to
work? The object addingMachine needs to exist and the variable number has
to be declared outside the loop because this variable is part of the condition.
6.7 Choosing the Right Loop Statement
/* Example Run:
Input number: 23
Input number: -56
Input number: 101
Input number: 24
Input number: 0
The result is 148 yes votes and 56 no votes.
*/
Use a for statement if the number of iterations of the loop is known in advance,
or if there is an integer variable that increases or decreases by a fixed value for
every iteration.
If the user presses Cancel, or doses the window or doesn't enter any data, the
message "You have to enter data!" appears.
If numbers should be entered, and the user enters a text that cannot be
interpreted as a number, the message "Invalid integer!" or "Invalid decimal
numeral!" comes up.
The methods ask again and again until the user enters valid data.
return text.trim();
}
public static int inputlnteger(String prompt) {
int number = 0;
boolean ok = false;
do {
String thelnputText = inputText(prompt);
try {
number = Integer.parselnt(thelnputText);
ok = true;
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null, "Invalid integer!\n");
}
} while (!ok);
return number;
}
public static double inputDecimalNumeral(String prompt) {
double number = 0;
boolean ok = false;
do {
String thelnputText = inputText(prompt);
try {
number = Double.parseDouble(thelnputText);
ok = true;
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null, "Invalid decimal numeral!\n");
}
} while (!ok);
return number;
class TestlnputReader {
public static void main(String[] args) {
String text = InputReader.inputText("Enter a text:");
double decimal = lnputReader.inputDecimalNumeral("Enter a decimal numeral:");
int integer = InputReader.inputlntegerfEnter an integer:");
System.out.println("You entered this:");
System.out.println(text);
System.out.println(decimal);
System.out.println(integer);
System.exit(0);
Let's look more closely at the individual methods. We'll start with the
inputText ( ) method. We use showInputDialog ( ) to input data. This
method returns null if the user presses Cancel or closes the window. The
6 Loops as a Control Structure
following section of code checks this and prints out the message "You have to enter
data!" before the user is asked again:
String text = JOptionPane.showlnputDialog(prompt);
while (text == null || text.trim().equals("")) {
JOptionPane.showMessageDialog(null, "You have to enter data!");
text = JOptionPane.showlnputDialog(prompt);
}
Notice how the loop is constructed. The program control only goes into the loop if
the text is not valid.
We can use a do-while statement if we aren't going to print out a message
about the error:
String text;
do{
text = JOptionPane.showlnputDialog(prompt);
} while (text == null || text.trim().equals(""));
Don't succumb to the temptation to use do-while if a message will be printed!
Then you would need an if statement after the input inside the loop body, and
that's not very elegant.
The methods for inputting numbers are more difficult. As you know, we use
parselnt() orparseDouble () to convert text to numbers. Up to this point,
if the text can't be converted to a valid number, an error message comes up in the
console window and the program stops. This is, of course, an unfortunate situation,
and now we'll find out how to catch this situation and also ask the user again.
We use the inputText () method discussed above to input the text. We can
call this method directly, without qualifications, since we're in the same class.
String thelnputText = inputText(prompt); // calls another method in the same class
We can interpret the text and handle any potential errors that arise:
try { // we'll try to convert the text to numbers
number = Integer.parselnt(thelnputText); // we try here
we only end up here if it succeeds
} catch (NumberFormatException e) {// we end up here only if it didn't succeed
JOptionPane.showMessageDialog(null, "Invalid integer!\n");
}
There's quite a bit of unfamiliar material here.
The call to parselnt () is inside a block that starts with the keyword try. It
signals that we are going to try something with an outcome we're unsure of. What
we are going to try is to convert the text into a valid number. If it's not successful, a
so called "exception object" will be thrown (someplace inside the parselnt ()
method there's actually a throw statement). We have to do something with this
object, otherwise the user will get the ugly error message mentioned above. What
we'll do is to "catch" the object. That happens in a catch block a little further
down in the program code.
6.9 New Concepts in This Chapter
Study the comments in the code above. Notice which statements are executed
when the error occurs, and which are executed if everything is successful.
In the input Integer () method, we use a boolean variable, ok, to keep
track of whether the conversion was successful or not. We set the variable equal to
false in the beginning of the method, and it is only set to equal true if we get
through the call to parselnt () without any errors occurring.
Don't despair if you find this difficult. Exception handling is covered in chapter
8, and we'll spend more time on the details of it then. Until then, copy the class and
use the methods where you need them. Remember to qualify it with the class name:
String text = lnputReader.inputText("Enter a text:");
Problems
Modify the program WallCalculations2 from listing 3.4 in this way:
(a) If the user enters data that cannot be converted into valid numbers, let the
program ask again.
(b) Limit valid lengths to between 1 and 15 meters, and valid heights to between
1.5 and 7 meters. Let these numbers be named constants.
Problem 4
Create an applet that draws a polygon line by line. Input the number of corners
from the user. Generate the polygon's corner coordinates with a random number
generator.
Problem 5
Create an applet that draws various geometric figures in random colors scattered
around in a window. Use the random number generator to determine the type of
figure, its color, and its location. Limit the number of different types of figures and
the number of different colors to three. There should be 15 figures in total.
This page intentionally left blank
Elaboration Between
>'<>CtS
In order to complete tasks, objects often have to collaborate. Examples from reality:
The teacher sends the message "Complete this task" to a student. The student
searches for help from other students, and searches on the Internet or in books
to complete the task.
Elisabeth turns her CD player on. It has to collaborate with the CD to be able to
make music.
The myCDplayer object can now collaborate with (send messages to) its own
instance variables (the parts the CD player is made up of) and the "Four
Seasons" object which it has received via the parameter list.
In this chapter, we will work with the renovation example. We will program
several of the classes and create a simple, menu-driven client program that can be
used to find the materials required and prices for wallpapering, painting, and
laying flooring.
Collaboration between objects must necessarily lead to our having references to
the same object from several locations in the program. We will look at the
consequences this can have.
*/
class Flooring {
private static final double limit = 0.02; // limit for one more width
private String name; // for identification purposes
private double price; // price per meter
private double widthOfFlooring; // meter
public Flooring(String initName, double initPrice, double initWidth) {
name = initName;
price = initPrice;
widthOfFlooring = initWidth;
}
public String getName() {
return name;
}
public double getPricePerM() {
return price;
7.1 Examples of Collaboration Between Objects
/*
* Wallpaper.java E.L. 2001 -05-17
*/
class Wallpaper {
private static final double limit = 0.02; // limit for one more width
private String name; // for identification purposes
private double price; // price per roll
private double lengthPerRoll; // meter
private double widthPerRoll; // meter
public Wallpaper(String initName, double initPrice, double initLengthPerRoll,
double initWidthPerRoll) {
name = initName;
price = initPrice;
lengthPerRoll = initLengthPerRoll;
widthPerRoll = initWidthPerRoll;
}
public String getName() {
return name;
}
public double getPricePerRoll() {
return price;
7 Collaboration Between Objects
Here we instantiate a Surface object and a Flooring object and send two
messages to the Flooring object. First we ask it to find the number of meters
required, then what that costs. The output from the program looks like this:
You need 6.0 meters, price $147.0
References as arguments
We send a message to object A by calling a method. In order for object A to be able
to collaborate with object B in completing a task, a reference to object B often has
to be an argument for the method. In this way, object A can send messages to object
B.
In the example, A is equal to theFlooring, while B is equal to theSurf ace.
Method head:
public double getNoOfMeters(Surface aSurface)
Call:
double noOfMeters = theFlooring.getNoOfMeters(theSurface);
Read through the program code for the getNoOf Meters () method. It sends
messages to the Surface object to get the length and width:
double lengthSurface = aSurface.getLength();
double widthSurface = aSurface.getWidth();
A sequence diagram shows how messages are sent from object to object (see Figure
7.1). l The italics in this diagram explain the use of symbols in the diagram and are
not a part of UML. Here we follow the objects over time (vertical axis). We can read
the following message exchange from the figure:
1. The client instantiates an object named the Flooring.
2. The client instantiates an object named theSurf ace.
UML offers something called collaboration diagrams, too. Sequence diagrams and collaboration
diagrams express similar information, but show it in different ways. For this text we have found
sequence diagrams to be the most appropriate.
7 Collaboration Between Objects
underlining
indicates objectname
The dotted vertical lines represent the object's life span. The narrow vertical
rectangles that partially overlap the life lines show the period of the life when the
object is active.
A sequence diagram is usually used to show how the objects collaborate to
perform a specific task. The object named theFlooring can be active in other
periods of its life when there are other tasks to be done. But that isn't shown in this
figure.
Note the difference between an activity diagram (chapter 5) and a sequence
diagram. Both types of diagrams show things that happen in a time perspective.
7.1 Examples of Collaboration Between Objects
Our activity diagrams show what's happening on a detail level2 with an object in a
part of its life that is represented by a narrow, vertical rectangle in a sequence
diagram. Example: An activity diagram for the getNoOf Meters () method in
the Flooring class shows what happens with the object named theFlooring
while it's active (inside the vertical rectangle in the middle of the figure).
Example 2: the getTotalPrice() method
From the client program above, we have the following statement:
double price = theFlooring.getTotalPrice(theSurface);
The getTotalPrice () method looks like this:
public double getTotalPrice(Surface aSurface) {
return getNoOfMeters(aSurface) * price;
}
We will find out what it costs to cover the surface with the flooring in question. In
order to do so, we first have to determine the number of meters required, and then
multiply this by the price. Of course the Flooring class already has a method
that finds the number of meters, so we will use that. The object sends the message
getNoOf Meters () to itself.
Example 3: two objects of the same class collaborate
An object can collaborate with another object of the same class to complete a task.
Let's expand the Surface class with a method that compares the area of this
surface with another surface. It's common for a comparison method to return 0 if
the objects are the same, a negative value if the first one is smaller, and a positive
value if the first one is bigger. We can use the compare Areas () method this
way:
Surface surface"! = new SurfacefA", 5, 4);
Surface surface2 = new Surface("B", 4, 4);
int result = surface"! .compareAreas(surface2);
if (result < 0) System.out.println(surface1.getName() + " is the smaller one.");
else if (result > 0) System.out.println(surface2.getName() + " is the smaller one.");
else System.out.println("The surfaces have the same area.");
We see that we send a message to surface 1. The argument for the comparision
method is surf ace2. How should we program the method?
It's clear that surfacel has to collaborate with surf ace2 to come up with
an answer. First it has to find its own area, then the area for surf ace2, and then
compare them (see Figure 7.2). Notice how we draw an object sending a message
to itself.
The program code looks like this:
public int compareAreas(Surface theOtherSurface) {
final double precision = 0.00001;
2. However, activity diagrams are often used to show the control flow on a higher level.
7 Collaboration Between Objects
new
new
the client
tells surface"! compareAreas(surface2)
to compare - getArea()
itself to
surface2
surface1 asks
itself about its
own area, getArea()
then it asks
surface2 about
its area
then surface1
com pares the
areas and
returns the
result of the
comparison
Figure 7.2 An Instance of the Surface class sends a message to itself and to another
instance of the same class to complete a task (UML)
(a) find out if the person is the same age as another person, return type
boolean
7 Collaboration Between Objects
(b) compare the person's age with the age of another person, return type int
(younger than, same age, older than)
(c) find out if the person is more than x years older than another person, return
type boolean
i
show instructions
to the user
sf
let the user do
a menu choice
[option ==
[option != exit]
v
carry out the chosen task
Figure 7.3 The activity for a client object that's estimating the materials required for
renovation (UML)
The communication with the user is more complicated than we've seen in the
programs we've covered up to this point. We need an object that can be responsible
for carrying out the tasks in the activity diagram. Let's call the class this object
belongs to Project Chap 7. See the class on the left in Figure 7.5. We'll introduce
a little bit of new notation in this class diagram:
detais: ReaderRenovationCase
re
Figure 7.5 Classes with responsibility for communication with the user (UML)
Up to this point, the number of values an attribute can have for a specific object
has been 1. However, the number of alternatives in a menu is usually more than
one. We use the notation [1..*], or more generally, [m..n], to indicate this. The
first number indicates the lower limit for the number of values; the second
number indicates the upper limit. An asterisk instead of a number (as in the
figure here) says that there is no upper limit on the number of values.
In this case we have found that it's correct to include parameter lists for the
operations. The extent to which we do this depends on how far we've come in
the development process. The data type and parameter name are indicated the
same way for parameters as for attributes.
Here we have indicated the return type for operations that return values. The
operation doAChoice () returns an integer. We express that by putting a colon
and the data type after the operation.
7 Collaboration Between Objects
For a task associated with a menu selection to be carried out, data concerning
surfaces and materials has to be input. New objects have to be instantiated and
calculations have to be performed. As an example, we will look at what has to
happen when the program runs to estimate how much paint will be used:
1. Input data about the surface that will be painted (name, length, width).
2. Create an instance of the Surface class.
3. Input data about the paint that will be used (name, price, number of coats,
number of square meters per liter).
4. Create an instance of the Paint class.
5. Ask the paint object how much paint is needed to cover the given surface and
what it will cost.
6. Output the answers.
We can place all this in the ProjectChap7 class or we can compose a new
class that is responsible for the portion of these tasks that may be useful in other
contexts. We choose to separate out points 1 and 2 on their own, and points 3 and
4.
We compose a new class with methods for inputting information and
instantiating objects. See the ReaderRenovationCase class on the right in
Figure 7.5.
We distinguish between tasks that are linked directly to the specific client
program we are writing now (the Proj ectChap7 class) and tasks of a somewhat
more general nature (the ReaderRenovationCase class).
We let an instance of the ReaderRenovationCase class be an attribute for
an instance of the ProjectChap7 class. In this, we make it possible for there to
be collaboration between these objects.
The client program is in the same file as the ProjectChap7 class (see
Program Listing 7.2). Notice that we have named the integers that represent the
menu selections. This makes the program code easier to read and also has another
important benefit: one of these constants (exit) is used in main () to terminate
the loop. Now we can insert several menu selections into the ProjectChap7
class and still have the selection exit at the end of the menu. Even if exit
changes value to, for example, 4, this doesn't mean anything to main (). The value
of the constant is only changed in one place.
The ProjectChap7 class contains three methods:
The doAChoice () method presents the menu to the user and returns the
selection to the client.
7.2 A Menu-Driven Program
*rtKa**dM*
, i-instantiates
client L .- , mlX. new aProiect
mroaw*
objects
new .
showlnstructions L "
client asks aProiect to
show user instructions
^
doAChoice
g
fe '
client asks
aProiect to get
the user's choice
option
carryOutTheRightThin 1:
l)
client asks aProiect to readAndinstantiateSurface
carry out this choice
w
aProiect delegates aSurface ^ aSurface
I U-
reading and
instantiating of surface read And InstantiateWallpaper
and wallpaper objects
to the details object 1 /
nev
aWallpaper
^rniiBpMp^N'
i i
aProiect tells
aWallpaper to getNoOfRofls(aSurface) |
calculate the number i noOfRolls
of rolls ^ ^ - i-
' ' T
t t
t
Problems
Respond to the following questions in conjunction with Program Listings 7.2 and
7.3:
1. Name all the classes that are used. Show where instances of the classes are
created.
2. Suppose that we replace the while loop in main () (starting with "int
option = ...") with the following do-while loop:
do{
option = aProject.doAChoice();
7 Collaboration Between Objects
aProject.carryOutTheRightThing(option);
} while (option != ProjectChap7.exit);
Why doesn't this work satisfactorily?
3. In the beginning of the ProjectChapT class, the constants wallpaper,
paint, flooring, and exit get values. Explain why they can't get values
other than the ones they receive here.
Program Listing 7.2
/*
* RenovationChap7.java E.L. 2001-06-19
*
*/
import javax.swing.JOptionPane;
class ProjectChap7{
public static String[] alternatives = ("Wallpaper", "Paint", "Flooring", "Exit"};
public static final int wallpaper = 0
public static final int paint = 1;
public static final int flooring = 2;
public static final int exit = 3;
private ReaderRenovationCase details = new ReaderRenovationCase();
public void showlnstructions() {
String instruction =
"The program calculates the price and amount needed to renovate surfaces,\n" +
"such as floors and walls. First, you are presented a menu where you\n" +
"choose between materials: wallpaper, paint, or flooring. Then you have to enter\n" +
"data about the surface and about the chosen material.\n" +
"The area of the surface, the price and amount of material are then outputAn" +
"After that you are back into the menu againAn";
JOptionPane.showMessageDialog(null, instruction);
}
public int doAChoice() {
return JOptionPane.showOptionDialog(null, "What do you choose:", "Renovation",
JOptionPane.DEFAULTJDPTION, JOptionPane.PLAIN_MESSAGE, null,
alternatives, altematives[0]);
}
public void carryOutTheRightThing(int option) {
Surface aSurface = details.readAndlnstantiateSurfaceQ;
String result =
"\nThe area of" + aSurface.getName() + " is:" + aSurface.getArea() + " sq m.\n";
switch (option) {
case wallpaper:
Wallpaper aWallpaper = details.readAndlnstantiateWallpaper();
result += ("You will need " + aWallpaper.getNoOfRolls(aSurface) +
" rolls of wallpaper" + aWallpaper.getName() + ", price $" +
7.2 A Menu-Driven Program
aWallpaper.getTotalPrice(aSurface));
break;
case paint:
Paint aPaint = details.readAndlnstantiatePaint();
result += ("You will need" + aPaint.getNoOfLiters(aSurface) + "liters of paint" +
aPaint.getName() + ",price $" + aPaint.getTotalPrice(aSurface));
break;
case flooring:
Flooring aFlooring = details. readAndlnstantiateFlooringQ;
result += ("You will need" + aFlooring.getNoOfMeters(aSurface) +
"meters of flooring" + aFlooring.getName() + ", price $" +
aFlooring. getTotalPrice(aSurface));
break;
default:
break;
}
JOptionPane.showMessageDialog(null, result);
class RenovationChap7 {
public static void main(String[] args) {
ProjectChap7 aProject = new ProjectChap7();
aProject.showlnstructions();
int option = aProject.doAChoice();
while (option != ProjectChap7.exit) { // we have to qualify the name exit
aProject.carryOuttheRightThing(option);
option = aProject.doAChoice();
}
System. exit(0);
/* Sample data:
Input:
Margaret's wall: 7.2 m x 2.35 m,
Wallpaper Sungold: price $9.50, length: 12.5 m, width: 0.54 m.
Anne's wall: 7.2 m x 2.35 m, paint 056789: price $9.90, 3 coats, 10 sq m/l.
John's floor: 5 m x 4 m, Flooring Berger XX: price $34.00 , width: 5 m.
Output:
The area of Margaret's wall is: 16.92 sq m.
You will need 3 rolls of wallpaper Sungold, price $28.50
The area of Anne's wall is: 16.92 sq m.
You will need 5.5 liters of paint 056789, price $54.45
The area of John's wall is: 20.0 sq m.
You will need 4.0 meters of flooring Berger XX, price $136.0
V
7 Collaboration Between Objects
method = myFloorclient;
aSurface thus becomes a reference for the object that contains the data about
Anne's floor (see Figure 7.7).
What do we do with aSurface inside the method? See Program Listing 7.1.
We send messages where we ask about the length and width:
double lengthSurface = aSurface.getLength();
double widthSurface = aSurface.getWidth();
myFloor aSurface
Figure 7.7 What happens during a call to the getNoOf Meters () method?
Assume that the Surface class is mutable (i.e., that it contains methods that
change the data contents), and that it contains the following method:
public void setLength(double newLength) {
length = newLength;
leads to an object that "belongs" to the client changing contents. The object is
declared as a variable in the client program, and in this way we can say that it
belongs to the client. With the statement above inside the getNoOf Meters ()
method the object changes its value far away from its owner. Such changes can
quickly lead to our losing the overall picture. One way of assuring ourselves that
this will never happen is simply to not make the class mutable. On the other hand,
7.3 Several References to the Same Object
this is often far from the reality that we are modeling. When the real objects change
values, our model objects should, too.
Starting point:
myFloor
aSurface
(the client)
(parameter in the
getNoOfMetersQ method)
aSurface.setLength(5.7);
myFloor
(the client) aSurface
able to change the contents of the objects by using the mutation methods that may
exist.
If the Flooring class is mutable, we ought to evaluate whether the constructor
should create a copy of the object instead:
public Surface(String initName, double initLength, double initWidth,
Flooring initFlooring) {
name = initName;
length = initLength;
width = initWidth;
flooring = new Flooring(initFlooring.getName(), initFlooring.getPrice(),
initFlooring.getWidth());
Figure 7.9 An instance variable in the server object points to the same object as a variable
in the client object
Finally, one small thing: What happens to all the objects as time goes by? Does the
memory finally fill up if you constantly create new objects? Java uses a technology
called automatic garbage collection: At regular intervals, Java cleans up the memory.
When no more references to an object exist, the object is deleted. Not all
programming languages clean up after themselves. A C++ programmer, for
example, has to be careful to free up space that is no longer needed. Java also
provides methods that let the programmer request a cleanup in special situations.
Problems
1. Suppose that the Surface class has the following method:
public void setLength(double newLength) {
length = newLength;
}
The following program is produced:
class Playground {
private String name;
private Surface theSpot;
public Playground (String initName, Surface initSpot) {
name = initName;
theSpot = initSpot;
}
public Surface getSpot() {
return theSpot;
}
public void changeSpot(double newLength) {
theSpot.setLength(newLength);
class Problem7_3_1 {
public static void main(String[] args) {
Surface spotl = new Surface("spot1 ", 4.5, 3);
Playground aPlayground = new Playground("playground1 ", spot1);
System.out.println("A: " + spot1 .getName() + " length: "
+ spotl .getLengthQ + " width: " + spotl .getWidthQ);
aPlayground.changeSpot(8.5);
spot1 .setLength(5.0);
spot 1 = aPlayground.getSpotQ;
System. out.println("B: " + spotl .getNameQ + " length: "
+ spotl .getLengthQ + " width: " + spotl .getWidth());
(a) Draw a figure that shows which objects are created, and which references
there are to these objects. The figure will show the situation before the first print
statement.
7 Collaboration Between Objects
(b) What has changed when we come to the next print statement?
(c) What will be output when the program runs?
2. In this section, we expanded the Surface class with the attribute flooring.
Create a set-method that changes the value for this instance variable. Create two
versions of the set-methodone makes a copy of the client's flooring object, the
other doesn't.
"Margarets flooring"
theFtooring 24.50
5
newPrice
Let's expand the Flooring class with the following methods that change the
price of the flooring:
public void setPrice(double newPrice) {
price = newPrice;
newPrice = 0.0;
The method zeroes the variable newPrice after it's used. Does this have any
effect on the client? Let's say that the client creates an instance of the class, and then
inputs a new price from the user:
7.4 Summary: Argument Passing
The parameter is of a primitive data type: if the method changes the value for this
variable, that doesn't affect the argument at all.
The parameter is a reference: a copy of the argument means that the method and
the client each have their own reference to the same object. If the method makes
changes to the object, they will, of course, apply to the object that the argument
points to, since that's the same object we're talking about.
arguments
The call: aObject.doSomething(10, theSurface);
theSurface
number
Problems
1. What is printed when the following code bit runs?
int numberl = 3;
int number2 = 4;
System.out.println(*Before:" + numberl +"" + number2);
int help = numberl;
numberl = number2;
number2 = help;
System.out.println("Afterwards:" + numberl +"" + number2);
2. Suppose that we have inserted number swapping in a method:
public void swapNumbers(int t1, int t2) {
int help = t1;
t1 =t2;
t2 = help;
}
The method belongs to the Nonsense class and we do the following in a client
program:
Nonsense aObject = new Nonsense();
inta = 10;
int b = 4;
System.out.println("Before:" + a + "" + b);
aObject.swapNumbers(a, b);
System.out.println("Afterwards:" + a +"" + b);
What is printed now?
3. We create the following two methods to change the contents of the two objects:
public void swapObjects1 (Surface f1, Surface f2) {
Surface help = f1;
f1 = f2;
f2 = help;
}
public void swapObjects2(Surface f1, Surface f2) {
Surface help = new Surface(f1 .getName(), f1 .getLength(), f1 .getWidth());
f1 = new Surface(f2.getName(), f2.getLength(), f2.getWidth());
f2 = help;
}
None of these work. Explain why.
4. Is it possible to create a method that changes the contents of two objects in the
Surface class? If so, how?
7.5 New Concepts in This Chapter
sequence A UML diagram that shows which messages are sent between objects that are collaborating. The
diagram diagram shows the order of the messages along a time axis.
Find tax withholding per year. To our employees June is tax free, and in
December there's only half the usual tax.
7 Collaboration Between Objects
Find name (in the format: last name, first name. Example: Johnsen, Ann)
Find age
Find out if the person has been employed for more than a given number of years
(parameter)
Find out in which cases an instance of the Employee class has to collaborate
with its personalia object in order to complete these tasks. Draw sequence
diagrams for these operations.
The following code lines will tell you the current year:
java.util.GregorianCalendar calendar = new java.util.GregorianCalendar();
int year = calendar.get(java.util.Calendar.YEAR);
Write a simple program that puts data into an instance of the Employee class and
calls all the methods you've created. Check that the results are correct.
Write a menu-driven program that makes it possible for the user to change the
data contents in the object. Let the program run in a loop such that several changes
can be made. For every run-through of the loop, the program will send suitable get
messages to the object and print their results so that it's possible to check that the
changes were made.
Problem 2
Compose a class, Poster. The poster will have three lines. Every line will have its
own font, color, and upper- and lower-case letter designation. The text is also an
attribute for the line. Think about which class should be responsible for the lines'
placements.
The classes will be used in an applet. Therefore, you also need methods for
painting. The parameter for paint Component () has to be passed to the paint
methods you create in the Poster class and possibly in the Line class.
Create the applet.
Problem 3
Compose a class to handle books. Name, author, publication year, number of
pages, and publisher are pertinent attributes for a book. In addition to get methods,
you will create operations that compare the ages of two books, that compare the
number of pages, and that find out if two books were written by the same author
or if they were published by the same publisher.
Write a simple program that tests the class.
(To find the current year, see problem 1.)
? ,
Use the part of the Java documentation that describes the Java API
in Figure 4.6. Here, we will look at how to construct package structures that make
class names globally unambiguous. We'll also look at how to create our own
libraries for classes of a more general nature.
We'll look at how to handle exceptions so that we can avoid having them show
up on the screen as messages that result in a program abortion. We'll look at
various types of exceptionswhich ones you should try to program around and
which ones you should catch and take care of.
1. The name of this directory may change as new versions come out.
2. This definition is from (URL Java glossary] where you'll find definitions for many of the current
concepts.
8.1 The Online API Documentation
Click back to the page shown in Figure 8.2. On the left there's a summary of all
the classes in the Java API. Click on the String class. At the top are all the
superclasses for the String class:
java.lang.Object
I
+--java.lang. String
Figure 8.1 The main page for "Java 2 SDK, Standard Edition Documentation Version
1.4.0"
Notice that String is right under the Object class. Other classes may be far
from the class on the top, which is always the Object class.
The class tree and superclass concepts were covered in Section 4.6 in connection
with applets. For a brief review, look at Figures 4.6 and 4.7. Absolutely all objects
belong to the Object class. The Component class, which is a direct subclass of
Object, describes a subset of all the objects. The further down the class tree we
go, the more restricted the sets are. Public variables and methods declared in a class
are inherited by all subclasses. That means they can be used as if they were declared
in the subclass.
Back to the online documentation: a class description always begins with a text
that describes the purpose of the class and often also includes usage examples. A lot
of useful information can be found here. Read what it says for the String class.
You understood most of it, right? Go down to the "Constructor Summary" section.
This shows you all the constructors that can be used to instantiate objects of the
String class. Note that some of the constructors are marked "Deprecated". That
8 Java Libraries and Exception Handling
means you shouldn't use them. Sooner or later they will disappear from the lava
API. You'll find this label on many methods and constructors in the Java API. Most
of these methods are from the earliest and most incomplete versions of the Java
API.
In Chapter 3 you were introduced to one of the String constructors. Do you
see it on the list? Clicking on it will give you a somewhat more detailed description.
Most of the other String constructors have a parameter of a type that includes
the [ ] characters. This means that the argument has to be an array (we'll cover this
in chapter 9).
Let's keep going and look at the methods. There are a great many methodsin
most cases you'll find what you need.
Figure 8.2 The main page for "Java 2 Platform API Specification"
Field Summary: This section is at the top. It contains public variables, as a rule,
class constants. If you look here under the Color class, you'll find the colors
red, black, white, etc. Notice that you have to put the class name in front of
class constants if you are going to use them outside the class. For example:
Methods inherited from class xxx: This section is below the methods section.
Methods listed here are methods that are inherited from a (direct or indirect)
superclass. Look up the JApplet class. You'll find that JApplet inherits
from all its superclasses. Do you recognize any of these methods?
Problems
1. How do you find a method that will find a number's absolute value?
2. By no means does the list on the left side of the documentation window show all
the classes without scrolling. How can you limit this list to show only the classes
in a specific package?
3. Look up the StringBuffer class. What's the main difference between the
String class and the StringBuffer class?
com
import com.xssoft.graphics.Circle; xssoft
graphics databases
/ \
Circle.class \
/ \
Person.class \
Polygon.class Rea Estate, class
Figure 8.3 The package structure for classes from the XSSoft company
Suppose that we buy a number of Java classes from a company called XSSoft.
Among other things, the company produces classes for graphics and managing
8 Java Libraries and Exception Handling
archives of people and real estate. It's a plus for customers who use these classes
that they have names that won't conflict with the other classes they're using. Is it
possible to construct globally unambiguous class names? Yes, you can be
reasonably sure that the class name is unambiguous if you let the class belong to a
package named with the URL of the company's home pages on the Internet. Our
fictional company's home page is http://www.xssoft.com. XSSoft.com is unique on
the Internet, and that should also be adequate for the Java classes the company
produces. It's common to create a package structure whose top part consists of the
names contained in the URL, but in the reverse order. An example of a class from
the company XSSoft is com.xssoft .graphics .Circle. Furthermore, the
package structure is identical to the directory structure on the hard disk (see Figure
8.3). The Circle class is in a subdirectory named graphics, which in turn is a
directory under xssoft. Above xssoft we find com. Notice how the import statement
looks in a program where we will use the Circle class:
import com.xssoft.graphics.Circle;
Or we can write
import com.xssoft.graphics.*;
and gain access to all the classes in the com. xssoft. graphics package.
But what about the directory structure above com? This depends on where the
person installing the software puts the packages. The figure shows that we placed
the packages under c:\java. (In the following, we are assuming that we're working
in MS Windows.)
When we run a Java program that uses the packages from XSSoft, we have to tell
the Java interpreter where these packages are. This problem is solved by assigning
values to an environmental variable called CLASSPATH. You may be familiar with
the PATH variable; CLASSPATH is similar in that it contains a series of paths
separated by semicolons. The paths indicate where the Java interpreter should look
for packages. (See also appendix A.) In our case, then, CLASSPATH will contain
c:\java. In addition, if the environmental variable CLASSPATH exists on the
computer, then it also has to contain the path to the actual directory, where we
usually have a number of classes. The path to the actual directory is a period. Then
CLASSPATH will look like this:
CLASSPATH=.;c:\Java
Large class libraries are often delivered as packaged files. The zip and jar formats are
common, jar files can be created with the Java tool jar, and are basically zip files
with some additional information. The documentation for the compiler has more
information about the jar tool and jar files. Both zip and jar files can be included
directly in CLASSPATH. In that case both the path and file name should be included
in CLASSPATH.3
CLASSPATH=.;C:\java
myLJbrary
import myLibrary.lnputReader; I
InputReader.class
package myLibrary;
import javax.swing.JOptionPane;
public class Input Reader {
Note the differences from Section 6.8.
Near the end of the class you'll find the test program. We have put main () into
the class. For a utility class it's a good idea to put the test program into the class.
When you start the Java interpreter you input the name of a class, and the
interpreter looks for the main () in that class. Now we'll try the test program.
If you've set up CLASSPATH correctly, it'll be possible to run main () from any
directory (but there may be problems from an editor):
>java myLibrary/InputReader
Notice the direction of the slashthis direction also applies if the console window
is an MS-DOS window! Here you're indicating that you are going to run the
myLibrary. InputReader class. When you start the program from the
command line, write the slash instead of a period.
Now work out what happens if you move to the directory myLibrary and write
>java InputReader
Try to explain why this happens.
8.3 Localization
By formatting, we mean how, for example, a number is displayed on the screen or
on another output unit. Formatting doesn't affect the value itself. Assume the
variable number contains the value 35645.4. The numerical value can be output
(formatted) in several ways:
35,645.4 English/American locale
35 645,4 Some European locale
35 645,40 Some European locale
35645 Likely to be anyone
As you see, a main difference between locales is the decimal separator. Some use
period, others use comma.
The contents of the variable number remain the same, regardless of the output
format.
Formatting decimal numerals is a mere fragment of what is called localization.
This refers, for example, to currency units, date formats, alphabet sort orders, and
alsoof courselanguage. Java provides classes for creating programs that support
settings like this.
A specific location is identified by its language and country, and possibly also its
language variant. We'll ignore the variants here.
Look up the Locale class in the online API documentation. Browse through
the page quickly. The Locale class is used to specify which language and which
country the format should be set for. The country and language designation follow
international standards. The Locale documentation contains URLs for these
8.3 Localization
standards. For example, the German language is designated as "de" and the country
of Germany as "DE". We specify that the formatting should follow the German
standard this way:
Locale german = new Locale("de", "DE");
Locale.setDefault(german);
The java . text. NumberFormat class provides class methods for formatting
numbers according to the rules that apply for the location that is designated. For
example:
Locale german = new Locale("de", "DE");
Locale.setDefault(german);
double number = 0.757;
NumberFormat numberFormat = NumberFormat.getNumberlnstanceQ;
NumberFormat percentFormat = NumberFormat.getPercentlnstance();
NumberFormat currencyFormat = NumberFormat.getCurrencylnstance();
System.out.println("As decimal numeral:" + numberFormat.format(number));
System.out.println("As percent:" + percentFormat.format(number));
System.out.println("As currency:" + currencyFormat.format(number));
gives the following output:
As decimal numeral: 0,757
As percent: 76%
As currency: 0,76 DM4
Notice that the contents of the variable number are not changed. The format ()
method returns a string with the characters that will be outputin one case the
string contains "0,76 DM", in another case, "76%".
It's possible to control the details concerning the number of decimal places and
symbols that will be included in the formatting. Refer to the online API
documentation if you're interested in learning about this. Here, we'll stick to
looking at the DecimalFormat class. It's used to control the output format for
decimal numerals. We indicate the format as a string that says how the number will
look. The most important codes are shown with examples in table 8.1.
Thus
Locale locc = new Locale("en", "US");
Locale.setDefault(locc);
DecimalFormat theFormat = new DecimalFormat("###0.00");
String text = theFormat.format(13.4);
System.out.println(text);
text = theFormat.format(-3456789.4);
System.out.println(text);
gives the output
4. With version 1.4 of SDK, you'll get the symbol (euro) from 01.01.2002 for countries of the European
Monetary Union.
8 Java Libraries and Exception Handling
13.40
-3456789.40
Try this bit of code without setting location. Then you should get a result reflecting
the environment your program is running in ("Regional Settings" in Windows).
We see that even if the format is too restrictive, the number prints out.
Table 8.1 Codes to create patterns for the Decimal Format constructor. The codes can be
combined
API Reference
5. This is a font where all the characters take the same amount of room (see the "Monospaced" font in
Figure 4.1 1).
8 Java Libraries and Exception Handling
API Reference
6. AudioClip is an interface, not a class. The distinction doesn't mean anything in practical use here.
We will cover interfaces in chapter 10.
8 Java Libraries and Exception Handling
These three methods respectively play the music file once, play it infinitely many
times, and stop it from playing. It's possible to play several music files at one time.
The Java.awt.Graphics class
See also Section 4.7.
Methods:
public boolean drawlmage(lmage image, int x, int y, ImageObserver observer)
public boolean drawlmage(lmage image, int x, int y, int width, int height,
Color background, ImageObserver observer)
x and y are the coordinates for the upper left corner of the image, width and
height are the size of the image, measured as a number of pixels.
Calling the method registers that an image should be painted. A new thread (see
chapter 16) is started by downloading the image. Then the original program thread
returns to the client. Thus two program threads, or processes, run in parallel until
the image is downloaded. The last argument in the method call can be an object
that is alerted about how the download of the image is progressing. In our
examples, we use this as an argument here.
Problem
Try the applet with other file formats for sound and images.
The program tries to divide by zero, find the square root or logarithm of a
negative number, or some other mathematical "impossibility".
The program has to handle the exception states that arise during runtime in a
sensible manner. Depending on the circumstances, the programmer has to tackle
the possibilities that may arise, and program a way out of them.
8.5 Introduction to Exception Handling
The getGrade ( ) method returns an 'X' or a 'Z' if the point total is invalid. The
client has to check the return value:
Grade theGrade = new Grade(points);
char grade = theGrade.getGradeQ;
if (grade == 'Z') {
JOptionPane.showMessageDialog(null, "Negative number of points not allowed.");
} else if (grade == 'X') {
JOptionPane.showMessageDialog(null, "Max. number of points is 100");
} else {
JOptionPane.showMessageDialog(null, points + " points gives the grade " + grade);
8 Java Libraries and Exception Handling
For simple error situations, the boolean return type can be used. Then the return
value false will mean that something has gone wrong, while the return value
true is used if everything is normal.
Exception objects
From now on, an exception will mean a Java exception object.
In Program Listing 6.8 we saw that parseDouble () and parselnt ()
threw exception objects if the text in question couldn't be converted to a number.
Now we will see what an "exception object" is, and what it means to "throw" one.
This method of handling errors is essentially different from the procedure
described above. The mechanism is based on creating and dealing with instances
of the so-called Throwable classes where Exception is an important subclass.
First let's look at the problems that can occur if we are using the simple exception
handling described in the previous section.
What if all possible characters were valid return values from the getGrade ()
method? How would we warn the client then if something was wrong? And how
can we warn the client about errors that occur in a constructor? Exceptions make it
possible to send feedback to the client without using a return value.
File handling (covered in chapter 11) is an occasion where you can imagine
things going wrong. Briefly, that means that the program reads and writes data to a
file instead of (or in addition to) communicating with the user. This makes it
possible to store data from run to run. Communication with a file can always go
wrongfor example, it could happen that parts of the file are damaged. After every
single file operation, therefore, it's important to check that everything went well so
that you can continue:
establish a connection to the file
if this was successful
read a little data from the file
while this was successful and there is more data
read data from the file
end the connection to the file
There can be many messages to the file object inside the while loop. Every single
one of these can go wrong. This can lead to very complicated control structures with
many if statements embedded inside each other.
Exceptions make it possible to handle these errors in one place in the program.
Now the program outline from before will look like this:
try
establish a connection to the file (exception object may be thrown)
read a little data from the file (exception object may be thrown)
while there is more data
read a little data from the file (exception object may be thrown)
end the connection to the file (exception object may be thrown)
catch any exception object
common error handling
We're trying to do a number of things with this file. If an error occurs inside a file
method, this method will throw an exception object. We can catch it (as we did
here), or we can throw it again.
As you may remember from chapter 6, the keywords in this context are throw,
throws, try, and catch.
Figure 8.5 shows how main () handles an error that may occur in the get-
Data () method. Notice that the method head says that this method throws
("throws") an exception if an error occurs.
Figure 8.5 main () catches an exception object that is generated in the getData ()
method
In Figure 8.6 it's methodX () that calls the getData () method. An exception
object is generated in this method and sent back to methodX (). It says in the
method head that exceptions will be thrown (throws Except ion). In this case,
the exception object is handled by main (). We can also imagine that main ()
sent the object onthen a message would print out on the screen and the program
would stop.
8 Java Libraries and Exception Handling
Figure 8.6 methodx () receives an exception object from getData (), which it sends on
to main ()
If the compiler says that the exception has to be caught or thrown onwards, it's
easiest to throw it onward. Write throws Exception in the method head. If
that doesn't work (for example, in the init () method in an applet),7 enclose
the block that contains the problematic method with try and catch.
7. Why doesn't this work? See the "Java Core" description later on in this chapter.
8.5 Introduction to Exception Handling
If the exception causes the program to stop when it's running, you should try to
change the program to avoid that happening (see the examples below).
The online API documentation covers all the exceptions a method can throw.
We can find information about a specific class of exceptions by looking up the class
name in the online API documentation. The exceptions a method throws are also
described there.
2. Internal errors,
3. These exceptions have nothing to do
to be handled with try and
catch, or they should be
thrown out of the method
You may also see the message NullPointerException on your screen. That
means that you're trying to use a reference before you've set it to point to a concrete
object. For example:
Suppose we've declared the following instance variable in the Person class:
private Car myCar;
The variable automatically gets the value nul1.If we don't give it some other value
(in a constructor, for example), it will still have the value null when we do the
following inside an instance method:
myCar.startO;
We are trying to send a message to a non-existent object, and that is of course not
possible. Thus a NullPointerException is thrown.
It's not always easy to program your way around an exception of type 1. For
example, in Program Listing 6.5 we instead used the data control in
parseDouble ( ) and parse lnt ( ) and let these methods throw an exception
object if the text in question cannot be converted into a number.
Problem
What is printed out when the program below runs?
class Problem8_5_1 {
public static void main(String[] args) {
try{
for (int i = 0; i < 5; i++) {
System.out.println(The value of i:" + i);
System.out.println(1/i);
}
} catch(ArithmeticException e) {
System.out.println("Division by zero!");
}
System.out.println("For-loop no. 2 starts here:");
for (int i = 0; i < 5; i++) {
try{
System.out.println(The value of i: " + i);
System.out.println(1/i);
} catch(ArithmeticException e) {
System.out.println("Division by zero!");
Here we let the main () method throw the exception onwards. In this case, that
means that it appears on the screen and the program stops.
We can also write:
class MaintainNameArchive {
public static void main(String[] args) {
try{
...file handling...
} catch (Exception e) {
System. out.println("Program aborted: " + e);
Here we catch the exception. There's not much of a practical difference between
this example and the previous. In the latter case, the text "Program aborted: xxxxx"
prints out. Then the program stops because there's nothing else to do.
If we compile the example in Program Listing 11.1 without doing anything
about the exceptions, we get a lot of compile errors, an example:
C : \ T e m p \ E x C h a p l l \ M a i n t a i n N a m e A r c h i v e . j a v a : 13 :
unreported exception Java. io. FileNotFoundException; must
be caught or declared to be thrown:
FileReader readingConnToFile = new FileReader (filename) ;
>.
The main () method should catch all exceptions to avoid "ugly* messages on
the screen and program abortions. In simple examples and test programs, of
course, this is less important.
Other methods should only catch exceptions that can be handled reasonably.
Other exceptions are thrown on so that the client can handle them.
How precise do you have to be when you declare the type of exception?
Figure 8.7 shows the class tree for the Throwable class with subclasses.
Remember that in a way the class tree shows sets and subsets of objects. The
exceptions we need to worry about belong to the set of exceptions described by the
Exception class. Using Exception after throws or as a parameter type for
catch will cover all the pertinent types of exceptions.
By indicating the name of a subclass, you're being more specific and therefore
excluding other types of exceptions.
If you use multiple catch blocks under each other, you have to be careful to
put the most specific one first.
Java Core
try statements
Syntax:
try{
statements
} catch (parameter) {
statements
} catch (parametei) {
statements
} finally {
sfatemenfs
}
Here there's a try block, two catch blocks, and a finally block.
We can have zero, one, or more than one catch blocks as long as the parameter
is of a different type. Every catch block has exactly one parameter. The parameter
has to be of the Throwable type or one of its subclasses.
The finally block is only needed in specific situations and otherwise can be
omitted. The contents of this block are always executed, regardless of what happens
in the try block. Common uses for the finally block, for example, are dosing
files or releasing database resources.
What's actually happening?
The statements in the try block are executed. If no exceptions are thrown, the
program continues to the contents of any finally block that might be there and
then executes the statements after the try statement.
8.6 Exception Handling in Detail
If an exception is thrown in the try block, the program control jumps over the
rest of the try block to the first catch block that has a parameter that fits the
exception that was thrown. That means that the parameter has to belong to the
same class as the exception, or a superclass of this. The contents of this catch
block are executed. Then the program continues to the contents of any finally
block that's there and then executes the statements after the try statement.
If an exception is thrown in the try block, and no catch block matches, the
contents of any finally block are executed before the program control jumps
out of the method (with an exception thrown out of the method).
If no catch blocks fit the exception, and the exception is also not thrown out
of the method, then depending on the type of exception either the compiler
protests or the program execution is aborted.8
Example 1 (Program Listing 1 1.2):
public static void main(String[] args) {
String filename = "numberFile.txt";
try{
...establish connection to the file...
int sum = 0;
try{
...read text from the file...
...convert the text into number, and update sum...
} catch (lOException e) {
System. out.println("IO-Error when reading from file: " + filename);
} catch (NumberFormatException e) {
System. out.println("Error when converting from text to number.");
}
... close the file...
...print the sum...
} catch (FileNotFoundException e) {
System.out.println("File not found:" + filename);
} catch (lOException e) { // all other IO errors are caught here
System. out.println("IO-Error when opening/closing the file:" + filename);
8. Actually, the running thread is aborted. Other threads continue. More about threads in Chapter 16.
8 Java Libraries and Exception Handling
Here, all exceptions other than FileNotFoundExcept ions are thrown out of
main ( ) .
If the method is a redefinition of an inherited method, it can't throw any more
type 3 exceptions (see Figure 8.7) than the method it redefines. For example, the
Applet class declares the following method:
public void init()
For all intents and purposes, the init ( ) method in any applet will be a
redefinition of this inherited method. We are trying to let the method throw an
exception of type 3, then an exception of type 2:
public void init() throws lOException { // not ok, results in a compiling error
public void init() throws VirtualMachineError { // ok, but not much point?
throw statements
Syntax:
throw expression;
The value of expression has to be a reference of the Throwable type or a
subclass of this class. The statement means that, after any possible finally block
is executed, the program control will immediately jump out of the method it's in
and over the other methods to the first try statement that handles the exception
in question. If no such try block is found, the program control jumps to the end
of main ( ) , and the program is aborted.
8.6 Exception Handling in Detail
API Reference
9. The src.jar file contains the source code for all the classes that come with the SDK. It can be
downloaded along with the SDK from Sun's Web pages. The contents of the file can be extracted
using, for example, WinZip.
8 Java Libraries and Exception Handling
The constructor with the parameter is used if you want to insert a specific message
in the exception object.
Methods:
public String getMessageQ
If the object was instantiated with the constructor with a parameter, the message
that was inserted is returned, otherwise null is returned.
public String toStringO
This method returns a brief description of the exception object. If the object was
created with the constructor with a parameter, a string is returned that consists of
the name of the class the object is an instance of, followed by a colon and the
message that was entered when the object was instantiated. If the object was
instantiated with the constructor without parameter list, the name of the class the
object is an instance of is returned.
principle, we can use any of the ready-made exception classes, but this one is
chosen because it describes the problem fairly well. It's the argument for the
constructor that there's something wrong with.
Notice how we insert an appropriate message into the call for the exception
object's constructor:
if (initSalary < limitSal) {
throw new HlegalArgumentException("Salary:" + initSalary +
"\nThe salary should be at least $" + limitSal);
}
else if (initNumber < limitNo1 || initNumber > limitNo2) {
throw new IllegalArgumentExceptionfNumber:" + initNumber +
"\nThe number should be in the interval [" + limitNo1 + " , " + limitNo2 +"].");
} else {
The try -catch statement in the client program is placed inside the whi1e loop,
and if the exception is thrown, we get the message on the screen:
JOptionPane.showMessageDialog(null, e.getMessage() +
"\nStart over again with this employee");
V
import myLibrary.lnputReader;
import javax.swing.JOptionPane;
import java.util.ArrayList;
class Employee {
private static final int limitNo1 = 1001; // lower limit, employeeno.
private static final int limitNo2 = 9999; // upper limit, employeeno.
private static final int limitSal = 6; // minimum salary per hour ($)
private int number;
private String name;
private int salary; // per hour
public Employee(int initNumber, String initName, int initSalary)
throws illegalArgumentException {
if (initSalary < limitSal) {
throw new HlegalArgumentExceptionfSalary:" + initSalary +
"\nThe salary should be at least $" + limitSal);
}
else if (initNumber < limitNol || initNumber > limitNo2) {
throw new IllegalArgumentException("Number:" + initNumber +
"\nThe number should be in the interval [" + limitNol + "," + limitNo2 +"].");
} else {
number = initNumber;
name = initName;
8 Java Libraries and Exception Handling
salary = initSalary;
class TestEmployee {
public static void main(String[] args) {
Array List employees = new Array List(); // see chapter 10.
int number = lnputReader.inputlnteger("Employee no. (0 for exit):");
while (number != 0) {
try{
String name = lnputReader.inputText("Name:");
int salary = lnputReader.inputlnteger("Salary, per hour:");
Employee emp = new Employee(number, name, salary);
employees.add(emp);
} catch (IHegalArgumentException e) {
JOptionPane.showMessageDialog(null, e.getMessageQ +
"\nStart over again with this employee");
}
number = lnputReader.inputlnteger("Employee no. (0 for exit):");
}
System.out.println("Control outputAn");
for (int i = 0; i < employees.size(); i++) System.out.println(employees.get(i));
System.exit(0);
We can go another step further and create our own exception class. This class can
describe the error in question, and it must be a subclass of the Throwable class
or of one of the subclasses under Throwable. By letting the class be a subclass of
Except ion (but not of Runt imeExcept ion) we get the compiler to force the
client to handle the exception in one way or another. If the exception is an instance
of a subclass of Runt imeExcept ion (group 1, Figure 8.7), like
IHegalArgumentException, handling is not required.
8.6 Exception Handling in Detail
Like the other exception classes, it contains two constructors, a constructor with
empty parameter list, and a constructor with a string as parameter.
In a class tree, the constructors are called successively up the tree. The
constructor that will be used on one level is stated on the level below. If nothing is
stated, the constructor with empty parameter list is used. To specify a constructor
with parameters, the keyword super has to be used followed by a parenthetical
statement with the actual arguments. The constructors for InvalidEmploye-
eException contain super with a string as its argument. This means that the
equivalent constructor in the Exception class is used.
The constructor for the Employee class has to be changed to use the new
exception class:
public Employee(int initNumber, String initName, int initSalary)
throws InvalidEmployeeException {
if (initSalary < limitSal) {
throw new lnvalidEmployeeException("Salary: " + initSalary +
"\nThe salary should be at least $" + limitSal);
}
else if (initNumber < limitNo1 || initNumber > limitNo2) {
throw new lnvalidEmployeeException("Number: " + initNumber +
"\nThe number should be in the interval [" + limitNo1 + ", " + limitNo2 + "].");
} else {
number = initNumber;
name = initName;
salary = initSalary;
} catch (InvalidEmployeeException e) {
Problems
1. Change the constructor in Program Listing 8.2 in such a way that it handles the
case where both the number and the salary are invalid.
8 Java Libraries and Exception Handling
2. (You may solve this problem after you've read chapter 11.) The program in
Program Listing 11.2 will abort if it encounters an invalid number. Change the
program in such a way that invalid numbers will be skipped. Valid numbers will
be summed.
API "The specification of how a programmer writing an application accesses the behavior and state of
classes and objects" (see [URL Java glossary]).
catch Keyword that introduces a code block where an exception of a specific type is handled. Part of the
try statement.
deprecated In the API documentation, some methods (and classes) are marked as "deprecated". This means
that they are scheduled to be removed in a future version of the SDK. Therefore we shouldn't use
these types of methods.
exception Generally: a condition that can arise during runtime, but that is an aberration from normal. At
the same time, most often used in a slightly more specialized meaning, namely about objects
which are instances of subclasses of Throwable. These objects contain information about the
exception encountered.
finally Keyword that introduces a code block that is always executed regardless of whether exceptions are
thrown or not. Part of the try statement.
format data To display data in a specific way. Formatting doesn't affect the contents of the variable where the
data value is.
location Language, country, and possibly variantdetermines how, for example, numbers and dates will
be formatted (see the Locale class).
package Keyword to indicate that a class belongs to a specific package. The package name has to be the
same as the name of the subdirectory where the package is.
throw Keyword to throw an exception. The program control jumps out of the method (but see finally).
throws Keyword to throw an exception on, used in the method or constructor head.
try Keyword that introduces the try statement. The statement starts with a block of instructions
where errors can occur.
4. How do we set the formatting of numbers, dates, etc. so that it will follow, for
example, the French standard?
5. Explain how we use the keywords package and import.
6. What's the purpose of CLASSPATH?
7. What does the concept of an "exception" involve?
8. We should write programs such that some types of exceptions don't occur.
Which ones? Name examples.
9. What are the characteristics of the two other types of exceptions?
10. What does the keyword finally mean?
Create a new date that is equal to this date plus a specific number of days (this
number can be negative)
Problem 2
The String class contains a great many methods. Now we'll create more.
Create a class called MyString. It should have an instance variable of the
String class. The MyString class will be immutable and offer the following
services:
loop and, for example, the String methods: substring (), indexOf (),
and charAt ().
Deleting a character. For example: if the character V is removed from the text
"this sentence can be abbreviated," then we're left with "this sntnc can b
abbrviatd." Hint: use a while loop and, for example, the String methods
indexOf() and substring().
Problem 3
Let the MyString class from problem 2 contain an instance of the String-
Buffer class instead. Otherwise, let it offer the same services. Decide for yourself
whether the class should be mutable or immutable.
<T r ,WS O
'* > f i 1'Vpf^
In this chapter, we will look at an easy way to handle large quantities of data of the
same type. As an example, we will look at a month's worth of precipitation data and
a year's worth of sales data.
A data structure is a collection of data that is stored in the internal memory under
one name. The data structure for storing lots of data of the same type is called an
array. An object is also a data structure. In an array, the individual data elements are
numbered, whereas in an object they have name (the name of the instance
variables).
The data in an array can be of any data type. In this chapter, we will limit
ourselves to the primitive data types.
9 Arrays of Primitive Data Types
Month
preclpitatton(28..31]: int
getMaxImum
gctNoOfDryDays
getAverage
oi.QM I o
[0] [1] [2] [3] [27] [28] [29] [30]
march l\
index
As shown in the figure, the name of an array is a reference. And the array itself is an
object with special characteristics. The statement
int[] march = new int[31]; // note the square brackets!
declares the array march and reserves room for 31 integers. lust as with ordinary
objects, it's possible to declare the array without reserving space. Space can be
reserved when you know how large an array is needed:
int[] month; // months have different lengths
month = new int[31];
We can use every single element in the array as if it were an individual variable of
the int type. The name of the element is the array name followed by its index in
square brackets. To begin with, all the elements have a value of 0. This is true both
if the array is a local variable and if it's an instance variable. (For simple variables,
the zero setting will not apply if they're local.) We can assign an individual element
a specific value, for example:
march[0] = 20; // 20 mm of precipitation on the first day of the month
march[15] = 0; // no precipitation on the 16th of the month
march[30] = 10; //10 mm of precipitation on the last day (31st) of the month
int oneDay = march[15]; // the precipitation for March 16th is stored in the variable oneDay
int sum = march[0] + march[1] + march[2]; // compute the total rainfall for March 1st-3rd
It's important for the index to be valid. Invalid indices are meaningless. In this
example, a valid index has one of the values 0, 1, 2, 3, ..., 30. If there's any doubt
about the validity of the index, we have to test it with an if statement. If the
program discovers that we're trying to use an invalid index, it throws an
ArraylndexOutOfBoundsException and then stops.
The following lines print out the precipitation on the different days of the
month:
9 Arrays of Primitive Data Types
The index for the first element in an array is always equal to 0. This makes
standardized formulations of, for example, if tests and for loops possible:
if (index >= 0 && index < array.length) { // valid index
for (int i = 0; i < array.length; i++) { // sequential handling of all the elements in the array
If, through communication with the user, we instead want to number them starting
with, for example, 1, we insert this in the background texts for the user. For
example:
System.out.println("The number of pupils in the " + (i +1) + "th grade is" + noOfPupils[i]);
We can input precipitation data as follows (with InputReader from chap. 6.8):
for (int i = 0; i < march.length; i++) {
march[i] =
InputReader.inputlntegerfNo. of mm on March " + (i + 1) + "th:");
}
Notice that this loop also works if the array is empty (i.e., when march. length
equals 0). Then the loop body won't be executed at all.
9.1 What is an Array?
If possible, we should wait to set aside room for the array until we know how large
it's going to be. If that's not possible, we have to create an array that is large enough
and then keep track of how much of the array is full. However, it's often hard to
know how large "large enough" is. The result may be that we have to set aside quite
a bit of room and risk this space not being used.
A better solution is to use something called array lists. This is a type of array that
expands as needed. We will look at array lists in the next chapter.
Problems
1. (a) Create an array that will have room to store the number of days in every
month. Assign values to all the array elements by initialization. The number of
days in February is set to equal 28.
(b) Write code that asks the user if it's a leap year. If it is, the number of days in
February should be set to equal 29.
2. Create an array of the data type char. It should be initialized with the values 'A,'
'N,' 'N,' 'E'. Write program code that prints these values out in the opposite
order.
3. The integer array myArray is initialized with the values: 3, 8, -5, 5, 6, 0, 3, -2, 8,
9.
Then the following statements are executed:
myArray[2] = myArray[6] + 5;
int a = myArray[8];
myArray[7] = a + myArray[0] * myArray[0];
myArray[4] = myArray[4] + 1;
myArray[5] = myArray[3] + myArray[9];
myArray[3] = myArray[2*myArray[0]];
Now what are the contents of the array?
API Reference
_ arrayl
7
arrayl - '
1-4 61-2
array2 array2
7 14 -6 0
Figure 9.3 Setting array2 = arrayl means that we get two references to the same array
9 Arrays of Primitive Data Types
array2 array2 7 I 14 I -6 I 0
array1 4 6 2
int[] array1 = {1,4, 6,-2};
int[] array2 = {7, 14,-6,0};
array2 7 |14|-6|0
arra 1
After the statement V
System.arraycopy(array1, 1, array2, 2, 2);
.
array2 bl7|l4|4|6
Figure 9.5 The contents of an array can be copied to another array using System. array-
copy ()
Problems
1. array1 and array2 are given as at the top of Figure 9.5. Set up a for loop
that copies the contents from arrayl to array2, but so that the values in
array2 end up in the reverse order from array1. In other words, after
copying, array2 will contain the values in the following order: -2, 6, 4, 1.
2. Use the online API documentation and find out what exceptions
arraycopy () can throw. Which of these should you prevent from
happening? And how do you do that?
3. We can use arraycopy () to shift elements internally in an array. What is
printed out when you run the following?
9.3 The Month Class for Precipitation Data
char[] month1 = {'S', 'e', 'p', T, 'e', 'm', 'b', 'e', 'r'};
char[] month2 = {'N', 'o', V, 'e1, 'm', 'b', 'e', 'r'};
System.arraycopy(month2, 0, month"!, 0, 3);
System.arraycopy(month1, 4, month1, 3, 5);
for (int i = 0; i < month"! .length; i++) System.out.print(month1[i]);
System. out.println();
char[] months = {'M', 'M', 'M', 'a', 'y'};
System.arraycopy(month3, 2, months, 0, 3);
for (int i = 0; i < monthS.length; i++) System.out.print(month3[i]);
System. out.println();
precipitation days to find out which days had this amount of precipitation. But
that's not enoughwe also have to store these days. For example: if we have a
maximum precipitation on the days with indices 0, 5, and 17, these indices have to
be stored. We create an integer array with the same size as the precipitation array.
Theoretically, in the worst conceivable case, all the days will have precipitation that
equals the maximum value. Then we'll run in a loop and check every individual
precipitation value against the maximum value. If they are equal, we take note of
the index and increase noOf Max by 1.
It is important that the client receives an array of the right size. We do this by
creating a new array, the maxDays array, and copying over the data.
It's possible to engineer this in other and more efficient ways, but the method
shown here is probably the most "straightforward." Here we see what problems
come up when we don't know the exact size of the array we need in advance. These
problems are elegantly solved in the java.util .ArrayList class (chapter
10).
At the very end of the program listing we find a short test program. Notice that
the class is tested for arrays with lengths of 0 and 1, as well as for an array with a
more "normal" length. Instead of a length of 30, we've used a length of 5, which is
a much more manageable array size for testing.
V
class Month {
private String monthName;
private int[] precipitation;
r
* The constructor makes a copy of the precipitation data.
* The client may therefore use the same data structure to hold data
* for other months. Every one instance of the Month class holds
* its own precipitation data, independent of the client's data.
* (See Section 7.3).
V
public Month(String initMonthName, int[] initPrecipitation) {
monthName = initMonthName;
int noOfDays = initPrecipitation.length;
precipitation = new int[noOfDays];
for (int i = 0; i < noOfDays; i++) precipitation[i] = initPrecipitation[i];
}
public String getMonthNameQ {
return monthName;
9.3 The Month Class for Precipitation Data
return max;
r
* The method returns an array holding the indices of days
* with precipitation equal to the maximum precipitation.
*/
public int[] getDaysMaxQ {
int max = getMaximum();
/* Prepare for the worst;
we create an array with room for all the days in the month. */
int [] array = new int[precipitation.length];
int noOfMax = 0;
for (int i = 0; i < precipitation.length; i++) {
if (precipitation[i] == max) {
array[noOfMax] = i;
noOfMax++;
/* Now we create an array with correct size, and copy the data */
int[] maxDays = new int[noOfMax];
for (int i = 0; i < noOfMax; i++) maxDays[i] = array[i];
return maxDays;
class PrecipitationStatistics {
public static void main(String[] args) {
int[] precipitation = {1,4, 0, 4, 3}; // a very short month for testing
/*int[] precipitation = {}; // We have tested with arrays of
*int[] precipitation = {1}; // length 0 and 1 , too. */
Month oneMonth = new Month("January", precipitation);
System.out.println("Statistics " + oneMonth.getMonthNameQ);
System.out.printlnfMaximum:" + oneMonth.getMaximumO);
System.out.println("Average: " + oneMonth.getAverageQ);
System.out.println("No. of dry days: " + oneMonth.getNoOfDryDaysO);
for (int i = 0; i < oneMonth.getNoOfDaysQ; i++) {
System.out.println("Precipitation day no." + (i + 1) + ": "
+ oneMonth.getPrecipitation(i));
}
int[] maxDays = oneMonth.getDaysMax();
for (int i = 0; i < maxDays. length; i++) {
System.out.println("Max. precipitation day no.: " + (maxDays[i] + 1));
/* Example Run:
Statistics January
Maximum: 4
9.4 Sorting
Average: 2.4
No. of dry days: 1
Precipitation day no. 1: 1
Precipitation day no. 2: 4
Precipitation day no. 3: 0
Precipitation day no. 4: 4
Precipitation day no. 5: 3
Max. precipitation day no.: 2
Max. precipitation day no.: 4
V
Problems
You will write several more methods for the Month class. They will be tested by
expanding the client program.
1. Create a method that finds the total number of days with precipitation equal to
the maximum.
2. Create a method that finds the number of days when it rained less than a given
number of millimeters. This number will be a parameter.
3. Create a method that finds the average deviation from the mean value (standard
deviation). You may have to look the formula up in a statistics book.
9.4 Sorting
Sorting an array means putting the elements in order depending on their size. We
distinguish between ascending sons, where the smallest value comes first and the
largest last, and descending sorts, where the largest comes first.
As examples of the need for sorting data, we can mention ranking the
participants in a competition, sorting names in a telephone directory, and ranking
cities according to the price of local services.
We assume that there is room in the internal memory for the whole array which
will be sorted. As elsewhere in the chapter, we will limit ourselves to data belonging
to a primitive data typein other words, numbers or characters (the numeric
characters '0'-'9' and the letters 'a'-'z'). Sorting names, for example, will mean
that we have to sort instances of the String class.
Sorting an array often means that you have to compare the values of the
individual elements and let them change places until all the elements are in the
right order. Now let's look at an algorithm for the sorting method "Sorting by
selection."
In this method, we choose an element and place it in the right spot in the array.
We can summarize this algorithm as follows:
for (start = 0; start < array.length; start++) {
find the index for the smallest element in the interval [start, array.length - 1]
9 Arrays of Primitive Data Types
-5 -2 3 13 10 (I)) 8 4
-5 -2 0 13 10 (;\) 8 4
-5 -2 0 3 10 13 8 0
-5 -2 0 3 4 13 (D 10
-5 -2 0 3 4 8 13 @
-5 -2 0 3 4 8 10 13
*/
package myLibrary;
public class Sort {
public static void sortlntegerArray(int[] array) {
9 Arrays of Primitive Data "types
lient
Method invocation:
Sort.sortlntegerArray(test);
arraysortlntegerArray
Figure 9.7 An array as an argument gives the method a reference to the array object that
belongs to the client
9.5 Searching
Searching in an array means finding the element or elements that satisfy specific
criteria. For example, we indicate a value and go to find the index for the element
or elements that have this value. We also have to consider the possibility that this
value may not be found at all. Sometimes it's enough to find one occurrence of the
value; at other times we have to find all occurrences.
In Program Listing 9.1 there are two search examples:
The getNoOf DryDays ( ) method searches for the value 0. It counts the
number of times this value occurs.
The getDaysMax ( ) method finds the indices for all the occurrences of a
specific value.
The traditional search problem is searching for a specific value. We expand the
Month class with a method that finds the index for a day on which there was a
specific amount of precipitation (although this method may not be of much
practical use):
public int getDay(int value) {
for (int i = 0; i < precipitation.length; i++) {
if (precipitation[i] == value) return i; // value found
}
return -1; // value not found
}
If the value is not found, we have to tell the client this. We do that by returning a
negative value. This is meaningful here because an index never has a negative value.
If the array is sorted, we can stop the search as soon as the values are larger than or
equal to the one we're searching for.
In the search we immediately exit the for loop when the value is found. We
should avoid immediately exiting loops in long methods (for example, more than
10 lines). That can make the method difficult to read. It's best if we can divide large
methods up into several smaller ones. If that's not possible, we should formulate
the condition to avoid exiting abruptly. Let's look at two alternative formulations
of the search above.
To avoid exiting abruptly, we include the exit condition as part of the loop
condition. We can still use the for statement, but the condition is no longer linked
to only a counter, and it makes just as much sense to use a while statement:
int dayNo = 0;
while (dayNo < precipitation.length && precipitation[dayNo] != value) dayNo++;
if (dayNo < precipitation.length) {
...do what should be done if the value is found...
} else {
...do what should be done if the value is not found..
9 Arrays of Primitive Data Types
The condition contains a boolean expression that consists of two comparisons. The
order of these comparisons is important. We check first that the index is valid
(dayNo < precipitation, length), then we use the index. This works
because Java uses short-circuit evaluation (see Section 5.6) when calculating the
condition. If the first part is false, the second part won't be computed at all.
(precipitation [dayNo] with an invalid index will throw an
Array IndexOutOfBoundsExcept ion.)
Sometimes the search condition is so complicated that it's a good idea to
introduce a boolean variable that keeps track of when the value is found:
boolean found = false;
int dayNo = 0;
while (dayNo < precipitation.length && !found) {
if (precipitation[dayNo] = value) found = true;
else dayNo++; // increase only if not found
}
if (found) {
...do what should be done if the value is found...
} else {
...do what should be done if the value is not found...
}
In the next section, we'll look at the search methods available in the
java. uti1. Arrays class.
Problems
1. Create a class method that searches for a specific value in an integer array.
Assume that the numbers in the array are sorted in ascending order. The method
will return the index for the value. If the value doesn't exist -1 is returned. Use
return from the loop body.
2. Program the method in problem 1 without using return from the loop body.
The return statement should be at the very end of the method.
The search method is called binary search, and it requires the array to be sorted
beforehand. Binary search works like this: in a sorted array we know that small
values are at the beginning of the array and large values at the end. If we compare
the value of the middle element with the one we're searching for, we can find out
if what we're searching for is in the first or last half of the array. Then we can just
forget about the half of the array that the element is not in. Then we evaluate the
value of the middle element in the half that is still of interest and again rule out the
half that does not contain the element. We continue like this until we either get to
the element we're looking for or there are no elements left, in which case we can
establish that the value isn't there.
API Reference
These exceptions should be avoided with necessary tests before the method call.
public static void sort(dafaType array)
public static void sort(dataType( ) array, int fromIndex, int toIndex)
These methods sort the entire array or parts of an array (from fromIndex
inclusive to toIndex exclusive).
The method throws exceptions under the same conditions as the f i l l ( )
method.
Problems
1. Write a program that tests both of the fill ( ) methods. Remember to check the
indices before calling the second of the two methods.
2. The binarySearch ( ) method returns a negative value if the value you're
searching for doesn't exist. It indicates where this value would have been in the
array (see the API reference above). What do you have to do to get this value into
that place in the array? Write code that does this.
Table 9.1 Sales data for every day for one year
Week 51
9.7 Two-Dimensional Arrays
Find the most profitable day of the week on average over the course of the whole
year
In computer contexts, we call the arrays we've seen up to this point one-dimensional.
We can store the array layout above in a data structure that we call a two-dimensional
array. A two-dimensional array is an array that consists of a series of one-
dimensional arrays. The sales data can be stored in 52 one-dimensional arrays (i.e.,
an array for each week).
Figure 9.8 shows a two-dimensional array of sales data where we've restricted
ourselves to four weeks. We create a two-dimensional array in the following
manner (example):
int[][] sales = new int[4][5];
Every line is viewed as a one-dimensional array with the following name:
sales[0]
sales[1]
sales[2]
sales[3]
As we now know, we can access an element in a one-dimensional array by putting
the index after the array name. An element with the index 3 in the sales [ 1 ] array
is therefore accessed as sales [l] [3]. We can use these elements the same way
we use a simple variable of the same data type:
sales[1][3] = 400;
int theSale = sales[0][4];
int sum = sales[3][0] + sales[3][1];
The two-dimensional array at the figure can be initialized as follows:
int[ ][ ] sales = {{100, 200,150, 210, 300}, {230, 200, 160, 300, 450},
{120, 210, 180, 400, 120}, {300, 310, 250, 240, 200}};
9 Arrays of Primitive Data Types
The data in each line is placed in curly braces, separated by commas. The lines are
separated by commas and the whole thing is enclosed in an outer pair of curly
braces.
Figure 9.8 ATwo-Dimensional Array with Four Lines and Five Columns
Program Listing 9.3 shows the Sales class with the operations mentioned above
implemented. In the problems at the end of this section, you will create a client
program that works with an instance of this class. You will also create some more
methods.
class Sales {
private String department;
private int theSales;
public Sales(String initDepartment, int noOfWeeks, int noOfDays) {
department = initDepartment;
theSales = new int[noOfWeeks][noOfDays];
}
public String getDepartment( ) {
return department;
}
public int getNoOfWeeks( ) {
return theSales. length;
return mostProfitToDay;
}
return -1; //no data
Instead of repeating this test multiple times, we created methods that are called
when such a test is needed. A client has no interest in these methods, so we've made
them private. In these methods we also see how length is used in conjunction
with a two-dimensional array. The number of lines (in other words, the number of
one-dimensional arrays in the sales array) is given by sales . length. The
length of the line with the index weekNo is sales [weekNo] .length. All the
lines have the same length. In the next example, we'll see that the lines can have
different lengths.
Various kinds of errors may occur in many of the methods. The methods return
false or a negative value if this happens.
Notice the similarities and differences between the getSalesForAWeek ( )
and getSalesForAWeekDay ( ) methods. The former method adds up all the
sales numbers in a line, while the latter adds up all the sales numbers in a column.
The getTotalSales ( ) method adds up all the numbers in the entire array.
The outer for loop runs through all the weeks and the inner for loop all the days
in a week.
The getMostProf itDay ( ) method finds out which day of the week is the
most profitable for all the weeks combined. We use the getSalesForA-
WeekDay ( ) method to find the sales for a given day of the week. If multiple days
of the week have sales that equal the maximum sales amount, this method only
finds the first of these days.
Lines with different lengths
As mentioned above, the lines in a two-dimensional array can differ in length.
Study the little example in Program Listing 9.4. There we create an array with three
lines. The first line (index 0) has a length of 5, the second has a length of 4, and the
last has a length of 2.
/*
* We put test values into the array, one line at a time.
9 Arrays of Primitive Data Types
/* Example Run:
The length of line: 5 Data: 0 1 2 3 4
The length of line: 4 Data: 0 1 2 3
The length of line: 2 Data: 0 1
V
One use for this technique might be if we want to collect rainfall statistics for the
whole year in a two-dimensional array. Then the lengths of the lines would
correspond to the lengths of the different months.
Problems
1. Set up the following statements in a client program that works with the Sales
class (Program Listing 9.3):
(a) Make an object named the Year 2001. It should have room for sales data
for 52 weeks, 5 days per week.
You will send messages to the object theYear2001. Messages d) through g)
will be worded so that the responses from the object print out on the screen (use
System, out .println ( ) ):
(b) Register sales of $10,000 for Monday of week 10.
(c) Register sales of $12,100 for Thursday of week 8.
(d) Find total sales for week 5.
(e) Find sales for Monday of week 6.
(f) Find total sales for the whole year.
(g) Find out which day of the week (day number) is the most profitable and
how much was sold on this day of the week.
9.8 More Than Two Dimensions
Problem
We have three fields of apple trees, with ten trees each. We want to find out if there's
any difference between the fields and register the number of kilos of apples on each
tree. We take measurements five years in a row.
Figure 9.9 Objects with monthly statistics are hidden inside objects with annual statistics,
which are collected into one large statistics object
We should be able to deal with arrays where the elements are objects. This is the
topic of the next chapter.
Multidimensional arrays are useful if we need to handle data in multiple
dimensions. In the array of sales numbers, we needed to do computations for both
lines and columns.
array A data structure where all the data is of the same type and where each data value has an
index and can be accessed by indexing.
component See element. "Component" is used here in the list of concepts as defined in the Java
Language Specification [Gosling, Joy, Steele 1996, p. 193]. In other parts of the book we use
"component" in other ways.
data structure A collection of data stored in the internal memory under a name.
element The smallest building block that makes up an array; has room for a single value.
Multidimensional arrays are divided into components until a component itself is no longer
an array. Then the component is an element. See component.
9 Arrays of Primitive Data Types
index The position of a component or an element in an array. The positions are numbers from 0 to
(length - 1) inclusive.
Change the price of a product that is already registered. The change will be given
as a percentage.
Find out how many products cost more than a given amount. The amount will
be a parameter.
9.12 Programming Problems
Remember that the methods have to return an error code if, for example, invalid
product numbers are given.
Create a menu-driven client program (hint: see Program Listing 7.2).
Problem 2
Create a Temperature class. It will contain a two-dimensional array of
temperatures for every hour of the day for a month.
The class will offer methods that make it possible to find
The class will be immutable. In other words, all the methods have to make new
matrices that are returned. If the operations are impossible, the methods will return
null.
Write a simple client program that can be used to test the class.
This page intentionally left blank
of
Wrapper class
Create and use arrays of reference type and create and use array lists
Use ready-made sort and search methods for arrays and array lists
As we have seen earlier, the length of an array cannot be changed after the array
has been created. The java. uti1. ArrayList class solves this problem for us.
This class contains an array of references and offers methods for, among other
things, inserting and removing elements from this array. If the array is too small,
the class creates a new, larger array and copies the references over. As a user of the
class we don't need to think about the array filling up.
To demonstrate the use of array lists we will create a program to calculate what
it costs to paint surfaces in an apartment with different types of paint. In this
context, we will also look at what an association is and how this fits into the class
diagram.
Finally, we'll see how to sort arrays of reference types. We will look especially at
how we deal with sorting strings according to location. We will also look at library
methods for sorting arrays of reference types and array lists.
names
Figure 10.1 An array of reference type is an array of references. The objects have to be cre-
ated individually
We make an array of reference type the same way we make an array of a primitive
data type, but we also have to create each individual object. As an example, let us
declare an array of the String type:
String names = new String[4];
This is an array of references. Every individual instance of the String class has to
be created:
names[0] = new String("Anne");
names[1] = new StringfThomas");
10.1 An Array of Reference Type
Instances of the String class can also be created by using the shortened form:
names[2] = "Edward";
Or we can input the name:
names[3] = JOptionPane.showlnputDialogfWrite a name:");
See Figure 10.1.
names
copyOfNames
Figure 10.2 Copying an array of references does not copy the objects
10 Arrays of Reference Types and Array Lists
The references in an array get the initial value null. This occurs independently of
whether the array is a member in a class or a local variable. Every individual
reference in the array has to be set to refer to an object before it can be used. If we
try to use an array element that does not refer to any object, a
NullPointerException is thrown.
Problems
1. Find the error(s) in the following bit of code:
Merchandise] items = new Merchandise[3]; // see Program Listing 4.2
items[1].setPrice(320.50);
items[2].setPrice(123.70);
items[3].setPrice(120.65);
2. Suppose that the names array is as shown in Figure 10.1. In addition, we have
the variable aName:
String aName = "Martha";
Set up statements that do the following:
(a) names [1] will refer to a new String object with the text "Paul".
(b) names [3 ] will refer to the same object that aName refers to.
(c) Store the sum of the lengths for all four of the strings in the variable
sumLength. Use a for statement.
(d) Find the number of 'r's in all the strings (hint: use indexOf ( ) and a for
statement).
3. In [URL Java book] under chapter 10, you'll find a revised version of the class
Merchandise from Program Listing 4.2. Download this and do the
following:
10.2 Array Lists
(a) Create an array of the Merchandise class with four elements. Fill the
array with data. Decide on suitable values for the attributes yourself.
Set up bits of code that do the following with a Merchandise array of general
length:
(b) Print the names of all the merchandise items.
(c) Find the most expensive item.
(d) Increase the price of all the items by 7%.
4. The names array is as given in Figure 10.1. Figure 10.2 shows the result of
copying the array elements. Rewrite the body in the for loop in the figure so
that copyOf Names will refer to copies of the objects in names. Hint: the
String class has a constructor that takes a reference to a String as an
argument.
5. The parameter for main ( ) is String [ ] args, i.e. an array of strings. If we
run the program from the command line, the words we write after the program
name will end up in this array. Example:
>java aProgram London Paris Rome
Create a main ( ) method that prints all the elements in the array args, and run
the program as shown here. Then the city names will print out.
1. We can fine tune both the start capacity and the way this increases and decreases. See the online API
documentation.
10 Arrays of Reference Types and Array Lists
The number of elements in the array list is called the size of the array list and is given
by the method size (). This must not be confused with the capacity, size ()
gives us the number of elements that contain meaningful data. In all practical work,
it is the size that is of interest for us, not capacity. The elements are numbered the
same way as in an array. Therefore, we can print out all the elements in the array
list this way:
for (inti = 0; i < texts.size(); i++) {
String thisText = (String) texts.get(i);
System.out.println("Text no." + i + " : " + thisText);
}
We are using the get () method. The return type is Object. Therefore we have to
cast to the right type. An exception is thrown (ClassCast Except ion) if we try
to cast to the wrong type.
If the return type from a method is Object, we have to cast the return object to
the right class before we can send messages to it.
API Reference
This method removes a reference from the array list. The elements are transferred
one position closer to the beginning of the array list starting with the position
where there was an empty space and proceeding from there. The method returns
the reference. Casting may be necessary if we are going to send messages to the
returned object.
public Object set(int index, Object obj)
This method replaces the reference in the stated index with the reference to
another object, obj can be null.
Problems
Use the class Merchandise that you'll find under chapter 10 in the [URL Java
book] in these problems as well.
1. Create an array list named items. Write program code that inserts instances of
the Merchandise class into the array list. The product number will be equal
to the index + 100, i.e. 100, 101, 102, 103, etc. The objects will be created by the
program running in a loop and for each item of merchandise, the merchandise
name and price are input. Find suitable termination criteria for the inputting
actions yourself.
2. Write program code that runs through the whole items array list and prints out
the input information.
3. Write program code that searches for a product with a given name. We are
assuming that the product name is unambiguous.
4. Write program code that removes the product found in Exercise 3.
The statement
Integer integerObject = new Integer(50);
creates an instance of the Integer class and place the number 50 in this object.
The following bit of code inputs positive integers from the user, converts them to
an integer object and inserts them into the array list. The input is completed when
the user enters a non-positive number:
ArrayList numbers = new ArrayList();
int aNumber = lnputReader.inputlnteger("Write a positive number: "); // see chap. 6.8
while (aNumber > 0) {
Integer integerObject = new Integer(aNumber);
numbers. add(integerObject);
aNumber = lnputReader.inputlnteger("Write a positive number: ");
API Reference
} catch (NumberFormatException e) {
numberObject = new Double("0.0"); // possible error message
}
System.out.println(numberObject.doubleValue()); // gets the numerical value
The printout will be 0.0 because the text "23..5* cannot be converted to a decimal
numeral.
If the constructor is going to create an instance of the Boolean class, the string
"true", despite a combination of upper and lower case letters, is converted to
true. All other strings, including null, are converted to false.
The Java.lang.Number class
This class declares a number of methods that are all implemented in the subclasses
Byte, Integer, Short, Long, Float and Double. That means that all these
methods can be used for objects which are instances of these six classes.
Methods:
public double doubleValue();
public float floatValue();
public int intValue();
public long longValue)();
public short shortValue();
These methods get the value of the object after the necessary conversion is done. An
exception is not thrown if the type it is converted to is too small, but the result will
not be correct.
The Java.lang.Integer class
Class constants:
public static final int MAX_VALUE;
public static final int MIN_VALUE;
The constants contain the maximum and minimum value for the data type int.
Class methods:
public static int parselnt(String text)
The method converts text to an integer and returns the integer value. The
exception NumberFormatException is thrown if the conversion is not
successful. For exception handling, see Program Listing 6.5, method
inputInteger().
The Java.lang.Double class
Among other things, the class includes treatment of the special values "Not-A-
Number" and "Infinity". See Section 2.6.
10.4 The Methods - equalsQ and toStringQ
Class constants:
public static final double MAX_VALUE
public static final double MIN_VALUE
public static final double NaN
public static final double NEGATIVE_INFINITY
public static final double POSITIVEJNFINITY
Class method:
public static double parseDouble(String text)
The method converts text to decimal numerals and returns the value. The
exception Number Format Except ion is thrown if the conversion is not
successful. For exception handling, see Program Listing 6.5, method
inputDecimalNumeral().
Methods:
public boolean islnfiniteQ
The method returns true if the Double object contains a value that is infinitely
large (positive or negative).
public boolean isNaN()
The method returns true if the Double object contains the special value NaN.
Problems
1. Write statements that
equals () compares the reference this (see Section 4.4) to the reference
obj. If they are equal (i.e, they refer to the same object), the method returns
true, otherwise false.
toString () returns the name of the class the object is an instance of,
followed by '@' and a numeric code.
If this implementation doesn't suit a class, the class can have its own version of
the method.
Many library classes have their own versions of these methods. For any given
class, these methods should be programmed this way:
toString () should return a string that can be used to print out the data
contents of an instance of the class.
10.5Associations
Previously, we have looked at how objects can collaborate to solve a problem. In
those cases, we are describing a connection that exists during the short instant it
takes to solve the task. Meanwhile, we also discussed that in order for this to be
possible, there has to be an underlying structural relationship. An object can
collaborate with an object that is, for example, a parameter or an instance variable.
Let's look at a relationship type called association. An association between classes
means that there is a connection between instances of the classes. In the class
diagram, an association is drawn as a straight line between the classes. In the
examples in this section, we are focusing on the associations. Therefore, the boxes
contain only the class name. We can link names and multiplicity to an association.
multiplicity
1.1 consists of g *
Figure 10.3 An association between the classes Apartment and Surface (UML)
Figure 10.3 shows an association between the class Apartment and the class
Surface. The figure demonstrates that there is a relationship between an
apartment and the surfaces (ceiling, walls, floor) it is composed of.
The name of the association is "consists of, and the arrow shows that the
association should be read from left to right. In this book, we have chosen to set the
reading direction from the class that needs to know about the other class. Now, you
can imagine that both of the classes need to know about each other and then you
can choose the name and the reading direction you think will tell the most, maybe
even set up both directions. In the figure shown here, we are demonstrating that an
apartment has to know which surfaces it is made of. A given surface, however, does
not need to know what apartment it belongs to.
The multiplicity says something about the number of instances of each class that
are included in a given relationship. It can be stated as an interval in the form of
10 Arrays of Reference Types and Array Lists
1 1
Person Office
stays at
is written by
Let's look at our renovation case study. We will now create a solution with the
following limitations and possibilities:
The apartment consists of an arbitrary number of surfaces. While the number of
surfaces can be anything whatsover, in this version we want to limit ourselves to
only one type of renovation material, namely paint. For every surface, we record the
type of paint. We want to maintain a register of all the surfaces and a register of all
the paint types and connect paints to surfaces as we wish. See Figure 10.5. We have
a one-to-many association between Paint and Surf ace. A specific type of paint
can be used on many surfaces, but each surface can only be painted with one type
of paint.
We choose to combine the two registers (surfaces and paint types) in an object
described by the class Renovat ionProject. Operations for this object will be,
for example, registering a new type of paint, registering a new surface, finding a
specific type of paint, etc. Thus, our renovation project has to know which surfaces
and which types of paint are recorded, which why we read in the direction from the
class RenovationProj ect.
10.6 A Bigger Example
What about the relationship between Surface and Paint? Does a type of
paint need to know what surfaces it is going to paint and/or does the surface need
to know what type of paint it is going to be painted with? We are choosing to be
satisfied with the latter - the surface has to know what type of paint is going to be
used on it. Therefore, we name the association so that we read from Surface to
Paint: A surface "uses" a specific type of paint
Problems
1. Use the class Merchandise that you'll find in chapter 10 in the [URL Java
book]. Setup an association between the class MerchandiseRegister and
the class Merchandise. The register should contain lots of merchandise.
Suggest operations linked to the class MerchandiseRegister.
2. Describe what is in the associations in Figure 10.4 in words.
3. Look at the bottom of Figure 10.4. Suppose that books and authors are going to
be stored in a register. We also want to have the relationship between them as
shown in the figure. What changes do we have to make to the class diagram?
Figure 10.5 Surfaces and paint types included in a renovation project (UML)
If we choose a surface that's already registered in the list box on the left, that
means that we want to change the type of paint for this surface and the list box on
the right comes up.
In constructing the classes, we distinguish between the classes that belong to the
problem area that we are going to treat and the classes that belong to the user
communication. We begin with the first group.
Figure 10.6 User interface for renovation project with many surfaces and many types of
paint
Figure 10.7 shows the class diagram with attributes and operations.
Compared with Figure 4.1, the class Paint has not been changed and it
contains information about name, number of coats, covering ability and price. It
offers get methods for each attribute and also methods that calculate the need for
paint and the price.
The class Surface has information about length, width, area and
circumference calculations. In addition, it can get and change the type of paint. The
type of paint is not set up as an attribute, but is obtained through the association to
Paint.
Now let's see how we program the associations in the figure.
A register emerges as a one-to-many association between a class that is
responsible for maintaining the register (here, RenovationProject) and the
class that is describing the objects that are included in the register.
10.6 A Bigger Example
We create a register by creating an array list. This array list will contain references
to the objects that are stored in the register.
The class RenovationProject has one-to-many associations to both the
class Surface and the class Paint. Thus, the class will contain two array lists,
one for surfaces and one for types of paint:
class RenovationProject {
private String name;
private ArrayList allSurfaces = new ArrayList();
private ArrayList allPaints = new ArrayList();
We have a one-to-many association from Paint to Surface. Should we
program it the same way? In other words, should we create an array list in the class
Paint?
uses
Surface
name: String
1 length: double
name: String width: double Paint
consists of
name: String
price: double
noOfCoats: int
newSurface; Surface)
getSurface) getSurface(
name: String)
getNoOfSurfaces()
getSurface(index: int)
aSurface: Surface)
needs etTotalPrice (
getPaird(intex: int) aSurface: Surface)
We are going to look at how we program the different methods in the class
RenovationProject. See Program Listing 10.1. We satisfy ourselves by
looking at the treatment of the register for paint types. The Surface register is
treated the same way.
A client has to be able to insert a new element in the register. In the example, it's
the method addNewPaint ( ) that takes care of this task. We have to be careful
here to check possible requriements to the object, before we accept it and register
it. In the example, we assume that all the paint types have different names.
Therefore, we check that before we put the element in place. If there already is a
paint type registered with this name from before, the new element is not put in
place and the method returns a reference to the type of paint that is already
registered. If, on the other hand, the registration succeeds, the method returns a
reference to the new paint type. The client can use this:
We have to offer the client the ability to look at the elements in the array list. In
general it should be possible to look at one element at a time. Then we need a
method that finds the number of elements and one that gets an element (a
reference) with a given index. In the example, this general need is covered by the
methods getNoOf Paints ( ) and get Paint (int index) . A client can
use these methods in the following way:
10.6 A Bigger Example
* This class maintains a register with surfaces and different types of paint.
* The class works with references to the objects all the time. No copies of
* objects are created.
* A client may add new references to the register, or it may retrieve a
* reference to an object. In this way it may change the content of the object
* in the register, if the object belongs to a mutable class.
*/
import java.util.ArrayList;
class RenovationProject {
private String name;
private ArrayList allSurfaces = new ArrayList();
private ArrayList allPaints = new ArrayList();
public RenovationProject(String initName) {
name = initName;
}
public String getName() {
return name;
}
/*
* This method adds a new surface to the register. If a surface
* with this name already exists, a reference to this object is returned,
* if not a reference to the newly added object is returned.
*/
public Surface addNewSurface(Surface newSurface) {
Surface thisSurface = getSurface(newSurface.getName());
if (thisSurface == null) {
allSurfaces.add(newSurface);
10 Arrays of Reference Types and Array Lists
*/
public int getNoOfPaintsQ {
return allPaints.size();
}
public Paint getPaint(int index){
if (index >= 0 && index < allPaints.size()) {
return (Paint) allPaints.get(index);
}
else return null;
}
public int getNoOfSurfacesQ {
return allSurfaces.size();
}
public Surface getSurface(int index){
if (index >= 0 && index < allSurfaces.size()) {
return (Surface) allSurfaces.get(index);
}
else return null;
Now let's look at the classes that take care of communication with the user. We
construct them the same way as in Section 7.2. The client program looks like the
one in chapter 7:
public static void main(String[] args) {
ProjectChap 10 aProject = new ProjectChap10();
aProject.showlnstructions();
int option = aProject.doAChoiceQ;
while (option != ProjectChap10.exit) {
aProject.carryOutTheRightThing(option);
option = aProject.doAChoiceQ;
}
System. exit(0;
}
We're going to go through what distinguishes the class ProjectChap10,
Program Listing 10.2 , from the class ProjectChap?, Program Listing 7.2. Read
the text along with the program code and the comments written there.
First we have to go through how we create the contents of the list on the left in
Figure 10.6. This is an array with strings, one string for each line. The array of strings
is created in the method setOptions ( ) . The number of strings will be equal to
the number of registered surfaces + 3. The last three strings contain the total price,
the text "New surface" and the text "Exit".
We find the number of registered surfaces by sending the message
getNoOf Surf aces () to project, which is an instance of the
RenovationProject class.
10 Arrays of Reference Types and Array Lists
We use a for-loop to run through all the registered surfaces. First we get the
surface and then the paint this surface is going to be painted with. We calculate the
paint needs and price by sending messages to the paint object. This way we can
construct the string the usual way. For decimal numerals we use a format object that
shows decimal numerals with two decimal places. Decimal separator and currency
formatting are according to the running environment (Windows: Regional
Settings).
Then we can turn our attention to the beginning of the class Project Chapl0.
As is clear from the description of setOptions () above, the value for the
menu selection "Exit" will vary from time to time. We let the constant exit receive
a value that cannot be a menu selection, namely -1. If the user selects "Exit", the
method doAChoice () returns this value. The client can compare the return value
from doAChoice () with exit and in this way find out when the program will
be terminated.
The method carryOutTheRightThing () is very different from the
corresponding method in chapter 7.
If the selection has a value less than the number of surfaces, that means that the
user has clicked on one of the lines that describes surfaces and by doing that she is
signalling that she wants to try another paint type on this surface. After a paint type
is selected (the method get Paint ( ), right box in Figure 10.6), we get a reference
to the surface object and change the paint type for this surface.
As in chapter 7, the user also has to register new surfaces and new paints. We are
using a sligthly revised ReaderRenovationCase class from Program Listing
7.3. See [URL Java book].
*/
import java.text.*;
import javax.swing.JOptionPane;
import myLibrary.lnputReader; // see chap. 6.8
class ProjectChap 10 {
public static final int exit = -1;
private ReaderRenovationCase details = new ReaderRenovationCase();
private RenovationProject project = new RenovationProject("My Rat");
private DecimalFormat numberFormat = new DecimalFormat("###0.00"); // see ch.8.2
private DecimalFormat currencyFormat =
(DecimalFormat) NumberFormat.getCurrencylnstance();
public void showlnstructions() {
String instruction =
"This program calculates the price and amount needed to paint several surfaces\n" +
"with different kinds of paint. You may choose to change the type of paint on\n" +
"a registered surface, or to register a new surface. You have to register a new \n" +
10.6 A Bigger Example
"surface as the first thing you do. Every time you do a change, the amount of\n " +
"paint and the price are shown in the list box.";
JOptionPane.showMessageDialog(null, instruction);
}
public int doAChoice() {
String[] options = setOptions();
String selectionDone = (String) JOptionPane.showlnputDialog(null,
"Drop down the list, and do a choice, " +
"\nif you click on a surface, you will get the opportunity to " +
"\nchange the paint for that surface:",
"Renovation", JOptionPane.DEFAULT_OPTION, null, options, options[0]);
int selection = getSelectionAslnt(options, selectionDone);
if (selection == options. length - 1) return exit;
else return selection;
}
public void carryOutTheRightThing(int option) {
if (option < project.getNoOfSurfacesQ) { // changes paint
Paint thePaint = getPaintQ;
Surface theSurface = project.getSurface(option); //get a reference to the surface object
theSurface.setPaint(thePaint);
} else { // new surface is to be registered
Surface aSurface = details.readAndlnstantiateSurfaceQ;
if (project.addNewSurface(aSurface) == aSurface) { // ok, finds the paint
Paint thePaint = getPaintQ;
aSurface.setPaint(thePaint);
} else {
JOptionPane.showMessageDialog(null,
"Surface with this name is already registered.");
class RenovationChap10 {
public static void main(String[] args) {
ProjectChap10 aProject = new ProjectChap10();
aProject.showlnstructions();
int option = aProject.doAChoice();
while (option != ProjectChap10.exit) {
aProject.carryOutTheRightThing(option);
option = aProject.doAChoice();
}
System. exit(0);
/* Example Run:
Data:
Surfaces: A wall in Mary's room: 3 x 4 m, Ceiling in the corridor: 6 x 1 m,
Paints: Heimdal Extra: 3 coats, 10 kvm/l, 100 NOK/I,
Heimdal Super: 2 coats, 12 kvm/l, 80 NOK/I
In this example we use Norwegian crowns as currency. The program
will use the currency given by the regional settings.
The output window, see figure 10.6.
*/
Problems
Expand the class RenovationProject with the following methods:
1 . A method to remove a surface.
2. A method to remove a paint type. A paint type can only be removed if no surfaces
have references to it.
Create your own test program to try out these methods.
10 Arrays of Reference Types and Array Lists
API Reference
Figure 10.8 shows what happens when you swap two values in the string array. We
have come to the second round of sorting. In other words, the first element
("Anne") is in the right place. The value to start is 1 ("Thomas"). We go through the
rest of the array and first find "Edward" who will trade places with "Thomas". The
value of smallestToNow is 2. What happens during the exchange?
10 Arrays of Reference Types and Array Lists
Step 1: The reference that refers to "Edward" should refer to "Thomas" instead.
Therefore, we have to take care of the reference to the object "Edward". We do
this by setting help to refer to this object: help = array [smallest-
ToNow];
Step 3: The reference that originally referred to "Thomas" will be set to refer to
"Edward". We have taken care of the reference to "Edward" in the variable
help. Therefore we can write: array [start] = help ;
*/
package myLibrary;
public class Sort {
API Reference
API Reference
These methods assume that the array is sorted. They return the index for an element
that is equal to value. If the value is not found in the array, the return value will
tell us where the value should be placed in the array so that it will still be sorted. If
we store the returned value into the variable index, the position will be equal to
(- index - 1). For an example of using this return value, see the method with the
same name in Section 9.6.
public static void sort(Object[] array)
public static void sort(Object[] array, int fromlndex, int tolndex)
public static void sort(Object[] array, Comparator comp)
public static void sort(Object[] array, int fromlndex, int tolndex, Comparator comp)
The methods sort all or parts (from fromlndex inclusive to tolndex exclusive)
of an array. The method throws out exceptions:
Problems
1. (a) Make an array with five strings. The strings will contain the following names:
Maud, Amy, Nella, Louis, John.
(b) Create program code that stores these names into the array list list 1.
10 Arrays of Reference Types and Array Lists
(c) Create a Iist2 that is a copy of list 1. Elements with the same index in
the two array lists will refer to the same object.
(d) Create a figure that shows all objects and references.
(e) Sort list2 using the sort () method in the Java.util. Collect-
ions class.
(f) Create a new figure showing the result.
2. In the exercise in Section 10.7 you changed the class Merchandise so that it
implements the interface Comparable. Create an array of merchandise. Sort
the merchandise using the sort () method in the java. ut i1. Arrays
class.
3. Typical Norwegian names shown in alphabetical order are: "Einar", "Fetter",
"Synnove", "oyvind", "Asmund". Create a little program which sorts these
names. Remember to insert them into the array (or array list) in another order
than the alphabetical, to check the sorting. You have to sort according to the
Norwegian locale (new Locale ( "no" , "No" )).
Find employee number for employees who have worked for the company for
more than five years
Remove an item
Extensions:
Streams, opening and closing files, reading data from a file, writing data to a file
Text and binary data transfer, file pointer, sequential versus random access
Serialization
Up to this point, we have been writing programs that communicate with the world
through the keyboard and the screen. Programs can also communicate with data
files. A program can read input data from a file, and output data can be written to
a file instead of to the screen.
Data files make it possible for the program to remember data from run to run.
This is practical for us userswe don't need to reenter data if we run a program
several times with only minor changes in the input data.
You're already familiar with data files. All the files you work with in word
processors, spreadsheet programs, and editors are data files. You open the
application, open the data file (the text document, spreadsheet, or whatever it is),
make any necessary changes, and save it for later use.
Now we will look at how we program the handling of data files: how a program
assigns the connection to a data file, how the data is input into the program, and
how it is rewritten to the file. We can transfer data from a program to a file in two
ways:
All data is converted into text before saving. People can read files created in this
way using an editor. Programs written in languages other than Java may be able
to read these files, too.
11 Using Data Files and Streams
The data is not converted before saving. We're talking about binary transfer of
data, and files created in this way can only be read by programs where the data
is represented internally the same way as in the program that saved the file.
It is also easy to store entire objects in a file. The transfer is binary and the process
is called serialization.
The java . io package contains over 60 classes and interfaces for file handling.
We include only a small selection of them here.
that different operating systems, platforms and programs use different byte-
oriented character sets.
Then we run the program: see Figure 11.1. The program reads the contents of the
data file and displays them in a message box on the screen (not shown in the
figure). Then it asks the user if there are more names to add in. The user says "yes"
and enters two new names. The program writes these names to the data file, after
the ones that were already there from before. If we take the file into an editor now,
we see that it has the following contents:
11 Using Data Files and Streams
Tony Kingsley
Ken Brown
Margaret Gibson
Matthew Johnson
Peter Adams
The program is shown in Program Listing 11.1. We'll go through this program line
by line in the next two sections.
V
import java.io.*;
import javax.swing.JOptionPane;
class MaintainNameArchive {
public static void main(String[] args) throws Exception {
String filename = "nameFile.txt";
r
* Reads all the names, and prints them on the screen.
*/
FileReader readConnToFile = new FileReader(filename);
BufferedReader reader = new BufferedReader(readConnToFile);
String result = "The register:\n";
String oneName = reader.readlLine();
while(oneName != null) { // null means end-of-file
result += oneName + "\n";
oneName = reader.readlLine();
}
JOptionPane.showMessageDialog(null, result);
reader.close();
/*
* Does the user want more names to be registered?
*/
int answer = JOptionPane.showConfirmDialog(null, "Do you want to add more names?",
"Archive", JOptionPane.YES_NO_OPTION);
if (answer == JOptionPane.YESJDPTION) {
FileWriter writeConnToFile = new FileWriter(filename, true);
PrintWriter printer = new PrintWriter(new BufferedWriter(writeConnToFile));
while (answer == JOptionPane.YES_OPTION) {
String newName = JOptionPane.showlnputDialog("Name:");
printer.println(newName);
answer = JOptionPane.showConfirmDialog(null, "Do you want to add more names?",
"Archive", JOptionPane.YES_NO_OPTION);
11.3 Reading Text from a File
printer.close();
}
System. exit(O);
/* Example Run:
=> The data file before program run:
Tony Kingsley
Ken Brown
Margaret Gibson
=> The user enters two new names:
Matthew Johnson
Peter Adams
=> The data file after program run:
Tony Kingsley
Ken Brown
Margaret Gibson
Matthew Johnson
Peter Adams
*/
The File class is in the java. io package. This class contains many methods for
handling files and directories. For more information, refer to the online API
documentation.
When we look at the program, we see that main () throws Except ion:
public static void main(String[] args) throws Exception {
Most methods that have to do with handling files and streams can throw exceptions
that we have to deal with, or throw away (see Section 8.5). Here we do the easiest
thing, we throw them away. This means that an error will abort the program. This
is acceptable in a simple program like this.
We link a stream object to the physical file with the following statement:
FileReader readConnToFile = new FileReader(filename);
For the program to read from a file, the file has to exist in advance. If the file does
not exist, the constructor FileReader () throws a FileNotFoundExc-
eption.
A program that reads data from a file can read individual characters, or a line,
depending on the input instruction that is used. Every input will mean that the
program has to contact the disk to retrieve the data that is being requested. This
takes time. Therefore, the speed of the program will depend on whether we are
inputting characters one at a time or as whole lines. To avoid this, it is common for
the data to be input into a buffer (an area in the internal memory that functions as
temporary storage) first. This way, the program's read statements retrieve data from
the buffer and not directly from the disk. In practical terms, this means that
character-by-character input goes just as fast as line-by-line input. A buffer of this
type is often much larger than the amount of data the program demands in an
instruction. The standard size for a buffer used to buffer input data from a file into
a Java program is 8192 characters. A read instruction in the program retrieves the
data from the buffer. The buffer is filled with new data from the disk gradually as
read instructions in the program empty it. The disk is accessed less often with
buffering than without it, which helps to increase a program's speed. In the
example above, all three of the names will be input during one disk access.
We accomplish buffered reading by wrapping an instance of the
BufferedReader class around an instance of the FileReader class:
BufferedReader reader = new BufferedReader(readConnToFile);
Another reason to use the BufferedReader class is that this class offers a more
practical input method than the FileReader class. In the BufferedReader
class, we find the readLine () method that we use to read a line of text at a time.
The input looks like this:
String oneName = reader.readLine();
The input always starts at the beginning of the stream and continues sequentially
through the stream. The readLine () method returns null when there is no
more data to read. If there's an error during reading, the method throws an
lOException.
11.3 Reading Text from a File
The program in Program Listing 11.1 runs in a loop, adding the input text to the
result string and inputting new texts from the stream until there is no more text to
read.
Finally, the stream is closed:
reader.close();
1. You can find even more details here by looking in the source code for the classes. It may have to be
downloaded and unpacked. Then it will be in the src directory under jdkl.4. You will find the rest of
the directory structure by following the package name.
11 Using Data Files and Streams
Problem
Write a program that reads lines of text from the data file mineData.txt. The program
will count the number of lines read and display this number on the screen.
(a) Try the program without the file existing. What happens?
11.4 Writing Text to a File
(b) Create the file, but do not store any data in it (use an editor). Now the
number of lines read should be 0. Is that right?
(c) Enter data in the file. Try the program. Are the results right? Put the file in a
subdirectory called MineData. What changes do you have to make to the
program now?
2. As described in the details section for input, we have to mention that this can be considered a short
form of the following two statements:
FileOutputStream outfile = new FileOutputStream(filename, true);
OutputStreamWriter writeConnToFile = new OutputStreamWriter(outfile);
11 Using Data Files and Streams
Data files are opened for reading or writing. Reading always starts at the
beginning of the file. Writing can happen at the beginning of the file or after
what is already there from before.3
3. In Section 11.9, we will see how we can move forward and backward in a file. This method of
handling a file also makes reciprocal rereading and rewriting possible.
11.5 Data Files: Summary and Class Descriptions
provides two groups of classes for handling input and output data. The older group
(JDK 1.0, Figure 11.3) ignores the conversion between Unicode and ASCII. The
classes in this group are subclasses of the classes InputStream and Output-
Stream. They have names that end in Stream. The classes that belong to the new
group (JDK 1.1, Figure 11.4) handle the conversion between the two character sets
as well as the different ASCII extensions that exist around the world. The new classes
are also more efficient. These classes are subclasses of the classes Reader and
Writer, and they have names that end in Reader and Writer.
Figure 11.3 A small selection of the input and output classes in JDK 1.0 (UML)
BufferedReader
PrintWrtter BufferedWriter
Figure 11.4 A small selection of the input and output classes in JDK 1.1 and newer versions
of java (UML)
11 Using Data Files and Streams
API Reference
Methods:
These methods can also be used for System. out.
public void println()
This method outputs a blank line. The new line can be a single character or several
characters, depending on the platform. This method uses the string returned from
the method System, get Property ("line. separator" ) ;
public void print(dafaType value)
public void println(date Type value)
The former outputs the value without the newline after it. The latter ends the
printout with a newline.
The dataType can be boolean, char, char [], double, float, int,
long, Object, or String. That the data type can be an Object means that the
argument can be of any class. In these cases, the class's implementation of the
method toString() is used (see Section 10.4). The method String.
valueOf ( d a t a T y p e ) is used for the primitive data types.
public void flush()
This method flushes the buffer.
public void closeQ
This method closes the stream.
All the data in a text stream has to be input with the method readLine ().
There are no methods for reading a number or just a single word.
Program listing 11.2 shows a program that inputs many numbers from a text
stream and calculates the sum of these numbers.
We have a try-catch block to handle the exceptions that might occur. Then
we have a loop where each run deals with one line. Each line consists of many
numbers. The loop body in the innermost loop deals with one number.
11.6 Reading Numbers from a Data File
We are using the class StringTokenizer to find the numbers. This class
parses a string that consists of several parts ("tokens") separated by delimiters.
Standard delimiters are spaces, tabs, newlines, and carriage returns. This works well
for us. We can also define our own delimiters. The method next Token () returns
the next portion of the string, while the method hasMoreTokens () returns
false when there are no more portions to be retrieved.
/* Example Run:
Data file:
23 45 678 1 -56
-42 898 7
3 56 -90 0 67
4
Output:
The sum of all the numbers is 1594
*/
API Reference
Problem
Create a class that contains two methods, one to read a line of integers and another
to read a line of decimal numerals from a file. The numbers will be returned to the
client in an array.
The class will have an instance variable of the BufferedReader type.
Create a program that makes it possible to test the class. Input several lines of
numbers.
integer 25 in
binary form
at the disk
t10101
Figure 11.5 Numbers are converted to and from text through text transfer of data
There can be a number of reasons for this conversion to be done. The data file can
be read by people and can be read by programs written in languages other than
Java. If we do not have requirements of this type for our files, transferring data
without converting it to text is a good alternative. That means that the data is stored
in the same form on the disk as in the internal memory. Transferring data without
converting to text is called binary transfer of data. The number 25 is stored as 11001
both in the internal memory and on the disk.
4. It is not important for you to understand the exact order of the zeros and ones. What is important is
that you understand that this order differs depending on whether the number is represented in
binary form or in text form.
11.9 Random Access to the Contents of a File
The conversion from binary form to text takes time and is particularly unsuitable
if there are decimal numerals to transfer. To maintain accuracy in the text form of
the number, a double has to be written to a file with 15 digits.
A variable that is transferred without conversion from the internal memory to
the disk takes just as much room on the disk as in the internal memory. The amount
of space taken up by variables of the different data types is given in Section 2.6.
Methods for transferring data without converting it are specified in the interfaces
Datalnput and DataOutput. As an example of a class that implements these
interfaces, we will look in the next section at the class RandomAccessFile,
which gives us random access to the contents of a file. In connection with this class,
we will go through several of the methods in the two interfaces. Other classes that
implement these interfaces are DatalnputStream and D a t a O u t p u t -
Stream.
Problem
Draw a figure corresponding to Figure 11.5 for a variable of the type int that
contains the number 15, and a variable of the type char that contains the
character '3'.
Each number takes up four bytes. Therefore, the length of the file is 40 bytes. We
get the length with the method length ( ) and write it on the screen.
long fileLength = file.length(); // the length() method returns long
System.out.println(The file is " + fileLength + " bytes long.");
Now the file pointer is sitting after the last number that was written to the file. For
example, we move it to the seventh number and read it:
file.seek(6 * 4); // moves past 6 integers of 4 bytes each, to position 2 in figure 1 1 .6
int number = file.readlnt(); // position 3 in figure 1 1 .6
We multiply the number by 10 and write it back again. In order to rewrite the
number in the right place, we have to move the file pointer back to position 2 in
the figure. Note that we always give the position relative to the beginning of the file.
number *= 10;
file.seek(6 * 4); // moves the filepointer "back"
file.writelnt(number);
After writing, the file pointer is in position 3 again. Finally, the program reads the
whole file and writes the data on the screen for inspection. Before reading, we have
to remember to move the file pointer to the beginning of the file:
file.seek(0); // moves to the beginning of the file
try {
while (true) { // stops when EOFException is thrown
int t = file. readlnt();
System.out.println(t);
catch (EOFException e) {
}
file.close();
This loop is complicated because the method re ad Int ( ) does not return any
definite value at the end of the file. (What should it be? All possible return values
are valid integers.) Instead, it throws an EOFException. Therefore, we have to
let the input happen in a loop where the loop condition is always true. Thus, the
loop is exited directly from readlnt ( ) when the EOFException is thrown.
We have to handle this exception right outside the loop, so that the file is closed
when the input is finished.
o| -1 | 2 | 3 | 4 | 5 1 6 7 | 8 |9
T '
t
for
for(int
(inti i= 0; i < 10; i++) file.writelnt(i);
file.seek(6 * 4);
file.readlnt(number)
Figure 11.6 The positions of the file pointer during the running of the program in listing
11.3
11.9 Random Access to the Contents of a File
*/
import Java. io.*;
class DirectAccessFile {
public static void main(String[] args) {
try{
RandomAccessFile file = new RandomAccessFile("DirectFile.dat", "rw");
/* writes 10 integers to the file */
for (int i = 0; i < 10; i++) file.writelnt(i);
long fileLength = file.length();
System.out.println("The file is " + fileLength + " bytes long.");
/*
* moves the file pointer to integer no. 7, reads i,
* multiplies it by 10, and rewrites it to the file.
*/
file.seek(6 * 4); // moves past 6 integers, each 4 bytes
int number = file.readlnt();
number *= 10;
file.seek(6 * 4); // moves the filepointer "back"
file.writelnt(number);
/* reads the whole file */
file.seek(0); // moves to the beginning of the file
try{
while (true) { // stops when EOFException is thrown
int t = file.readlnt();
System.out.println(t);
catch (EOFException e) {
}
file.close();
} catch (Exception e) {
System. out.println("Error: " + e);
/* Example Run:
The file is 40 bytes long.
0
1
2
3
11 Using Data Files and Streams
4
5
60
7
8
9
V
API Reference
This method reads bytes from the file until a newline is encountered. Every
individual byte is converted to a two-byte Unicode character. This means that only
a part of the Unicode character set is supported in this method. The method returns
null if the file pointer is at the end of the file.
public void writeChars(String text)
This method writes a string with two bytes (Unicode) for every character.
11.10Serialization
Suppose we need to store objects in a file. Let's look at the
RenovationProject class in Program Listing 10.1. We want to store
information about surfaces and paint types from program run to program run.
What do we have to do to save all this information in a data file?
For the sake of simplicity, let's limit ourselves to the surfaces. We have to make
a loop that runs through all the elements in the array list allSurfaces. For every
surface, we have to store the name, length, width, and paint. The last is a reference,
where we have to obtain the paint name and store it. To simplify the input, we
should store every individual data value on one line:
11 Using Data Files and Streams
*/
import java.io.*;
class SerializeWrite {
public static void main(String[] args) throws lOException {
Paint m1 = new Paint("Extra", 10, 3,10);
Paint m2 = new Paint(Super", 8, 2, 12);
Surface f1 = new Surface("Wall in children's room", 4, 3);
Surface f2 = new Surface("Ceiling in the corridor", 6, 3);
f1.setPaint(m1);
f2.setPaint(m2);
RenovationProject myApartment = new RenovationProject("My apartment");
myApartment.addNewPaint(m1);
myApartment.addNewPaint(m2);
myApartment.addNewSurface(f1);
myApartment.addNewSurface(f2);
FileOutputStream outstream = new FileOutputStream("apartment1 .ser");
ObjectOutputStream out = new ObjectOutputStream(outstream);
out.writeObject(myApartment);
out.close();
outstream = new FileOutputStream("apartment2.ser");
out = new ObjectOutputStream(outstream);
out.writeObject(f1);
out.writeObject(f2);
out.writeObject(m1);
out.writeObject(m2);
11.10 Serialization
out.close();
/*
* SerializeRead.java E.L. 20010816
*/
import java.io.*;
class SerializeRead {
public static void main(String[] args) throws Exception{
FilelnputStream instream = new FilelnputStream("apartment1.ser");
ObjectlnputStream in = new ObjectlnputStream(instream);
Renovation Project myApartment = (RenovationProject) in.readObject();
in.close();
System. out.println("Apartment data read from the file apartmenti .ser:");
for (int i = 0; i < myApartment.getNoOfSurfaces();
System.out.println(myApartment.getSurface(i));
}
for (int i = 0; i < myApartment.getNoOfPaints();
System. out.println(myApartment.getPaint(i));
}
System.out.println("Surface and paint data, read from the file apartment2.ser");
instream = new FilelnputStream("apartment2.ser");
in = new ObjectlnputStream(instream);
try {
while (true) { // stops when EOFException is thrown
java.lang.Object obj = in.readObject();
System. out.println(obj);
catch (EOFException e) {
}
in.close();
Program Listing 11.4 shows first a program that writes serialized objects to a file,
then a program that reads these objects. We will go through these programs. The
code bit below links an object stream to a file, writes all the data in the object
myApartment to this stream, and then closes the stream.
FileOutputStream outstream = new FileOutputStream("apartment1 .ser*);
ObjectOutputStream out = new ObjectOutputStream(outstream);
out.writeObject(myApartment); // (class constants and class variables are not stored)
out.close();
The input is just as straightforward:
FilelnputStream instream = new FilelnputStream("apartment1 .ser");
ObjectlnputStream in = new ObjectlnputStream(instream);
RenovationProject myApartment = (RenovationProject) in.readObject();
in.close();
The return type from the method readObject 0 is Object. Therefore, we
have to cast to the RenovationProject class if we are going to use
RenovationProject's methods on the object. The input object contains
information about its own class. If we try to cast to the wrong class, a
ClassCastException is thrown.
What's required for us to be able to store objects so easily? The classes we store
all have to implement the interface Java . io. Serializable. This is a very
simple interface. It doesn't contain any methods. Therefore, it's enough to write
implements Java. io. Serializable in the class head. In this example,
we have to change the class heads as follows:
class Surface implements java.io.Serializable {
class Paint implements java.io.Serializable {
class RenovationProject implements java.io.Serializable {
These classes use the predefined classes java.util .ArrayList and
java. lang. String. By looking them up in the online API documentation, we
find out that these classes implement java.io.Serializable. The vast
majority of the classes that go with SDK implement this interface.
The program that reads the data file prints the data on the screen for inspection.
The program runs through all the surfaces and prints information about every
individual surface in the apartment:
for (int i = 0; i < myApartment.getNoOfSurfaces(); i++) {
System.out.println(myApartment.getSurface(i));
}
The method getSurface () returns a reference to a Surface object. When we
put that into a print In () method, a call to the method toString () will be
implied. Thus, the body of the preceding loop can be written in the following
manner:
Surface f = myApartment.getSurface(i);
System.out.println(f.toStringO);
11.10 Serialization
The program runs through all the Paint objects the same way.
The second part of the first of the two programs in Program Listing 1 1.4 shows
an alternative version, where we treat the Surface and Paint objects
individually. First we write:
outstream = new FileOutputStrearn("apartment2.ser");
out = new ObjectOutputStream(outstream);
out.writeObject(fl);
out.writeObject(f2);
out.writeObject(m1);
out.writeObject(m2);
out.close();
We have to input the same way we wrote, i.e., one object at a time. Either we can
assume that we know that exactly two Surface objects and two Paint objects
are stored in the file, or we can let the program find out the type of object, and then
finish inputting when the end of the file is reached:
instream = new FilelnputStream("apartment2.ser");
in = new ObjectlnputStream(instream);
try {
while (true) { // stops when EOFException is thrown
Java. lang. Object obj = in.readObject();
System.out.println(obj);
catch (EOFException e) {
}
in.close();
In the same way as the method readlnt ( ) in the RandomAccessFile class,
the method readObject ( ) also does not return any definite value at the end of
the file. Therefore, we also have to handle EOFExceptions here.
We see that we can send the object directly to the print In () statement
without casting to the right object type. The reason for this is that the method
toString() is declared in the Object class. Since the method is also
implemented for the Surface and Paint classes, this version will be used, and
not the standard version that we find in the Object class.
What if we had wanted to use methods declared in the Surface or Paint
class? Then we would have had to check the object type before casting:
if (obj instanceof Surface) {
Surface s = (Surface) obj;
. . . send messages to the object s. .
} else if (obj instanceof Paint) {
Paint p = (Paint) obj;
. . . send messages to the object p. . .
11 Using Data Files and Streams
Java Core
3. Also try to serialize an array of integers. Hint: you cast an object to an array of
integers by writing (int [] ).
binary transfer of The data is transferred between internal and secondary memory without conversion.
data
buffer Intermediate storage for data transport between internal and secondary memory.
close file To bring the connection between a stream and a physical file to an end.
file pointer Keeps track of where the next read or write statement starts. The file pointer changes value
gradually as the read or write process is performed.
inistanceof Comparison operator with an object as its first operand and a class or an interface as its
second operand. The expression has the value true if the object is an instance of the
class, or of a subclass of the class. If the second operand is an interface, the object has to
be an instance of a class (or of a subclass of a class) that implements this interface. The
operator has the same priority as the other comparison operators.
native Used about methods that are written in platform-dependent code, native is a modifier
found in method heads, see for example the online API documentation for the
RandomAccessFile class.
random access to the Reading and writing can occur to any specified location, and the file pointer can be
contents of a file positioned anywhere in the file.
serialization A technique for storing whole objects in a file, including other objects that are referred to.
stream An abstraction that hides the details of data transfer between the internal memory and the
disk or other secondary memory.
text transfer of data Data in binary form is converted to text when writing to a secondary memory. When
reading, the data is converted from text and back to binary form.
5. What is the advantage of text data transfer over binary transfer? Are there any
disadvantages?
6. What is the purpose of buffering?
7. Why is it important to close a file (a stream)?
8. Set up code lines that read a decimal numeral from a file and store it in the
variable oneNumber.
9. What can we use the StringTokenizer class for?
10. Suppose that we want to consider the console to be a file. What is the file name?
11. How do we write a complete file name, including path, in Java?
12. What types of streams give us access to manipulate the file pointer? What can
we do with it?
13. A program that reads from a file has to stop reading when it comes to the end
of the file. How can the program check that it has reached the end of the file?
14. What does the concept "to serialize an object" mean?
15. Explain how we use the operator instanceof.
Find the average precipitation per day in the summer half of the year (April-
September)
Find the average precipitation per day in the winter half of the year (October-
March)
Read the precipitation from a file and print precipitation statistics for each of the
12 months and for the year as a whole.
Test the program by using a file that contains the same precipitation every day of
the year. The data file is easy to make with a little program.
11.13 Programming Problems
You might get more realistic data by generating random numbers for the
precipitation.
Problem 2
Create a program that encrypts a text. The text is read from a file. The results are
written to another file. The file names are read from the user. The program will also
be able to take a file in encrypted format and convert it back to "readable" form.
Only the letters will be encrypted. Every letter will be replaced by a different
letter. Enter the codes as a string. The first character in the string is the letter that 'A'
will be replaced by, the second character the letter that 'B' will be replaced by, etc.
If you start with a capital letter, the result should be a capital letter; if with a lower-
case letter, the result should be a lower-case letter. Punctuation marks are kept
unencrypted.
The codes are read from a file that the user has to provide the name for.
Example:
The letters BAN have the codes GHY. The word "banana" is then coded to
"ghyhyh," while "Banana" is coded to "Ghyhyh."
Problem 3
Use the Account class from programming problem 1 in chapter 6.
Create a program that maintains a bank account.
The previous balance is in the file balance.txt. Recent transactions are in a file. The
file contains one line per transaction. Every line contains a letter that explains what
type of transaction it is and an amount.
Transaction codes: W for withdrawal, D for deposit.
After the transaction file is treated, the new balance is placed in the file
balance, txt.
Individual transactions that mean the account has a negative balance are all
right. (Change the class Account so that this is possible.) If the net result at the
end is such that the balance is negative, however, the whole transaction file will be
rejected. No transactions will be recorded in this case.
Example: Starting balance: $5,460.70. The transaction file has the following
contents:
W 450
D 567.80
D 4000.00
W 500
Result: New balance is $9078.50.
Problem 4
Suppose that we have two data files of numbers. The numbers are sorted in
ascending order. Create a program that generates a third file where all the numbers
11 Using Data Files and Streams
from both of the files are sorted in ascending order. (We say that we are "merging"
the two files.)
Example:
File 1: -23 12 12 67 678
File 2: 67 676 756
The new file will look like this: -23 12 12 67 67 676 678 756
Problem 5
Make a simple birthday registry. The registry is in a file. The registry will not be
input into the internal memory in its entirety, but will be maintained directly in the
file. For each person, the first name, last name, and date of birth are stored in the
file. For simplicity's sake, you can assume that both the first and last name each take
up 15 characters. Use an array of char, possibly the StringBuffer class.
The user will be able to get the date of birth for a person when she types in the
name. It should be possible to expand the registry by more names. You can assume
that a person's name is unambiguous and that the user enters both the first and last
name.
Learning goals for this chapter
The following concepts have been mentioned previously in the book. We will now
look more closely at what they mean:
The keyword super. The keyword final in connection with classes anci
methods
The difference between classes and interfaces and how you use interfaces
12 Inheritance and Polymorphism
In Section 4.6, you were introduced to the class tree in Java. We made subclasses for
the JPanel and JApplet classes by using the keyword extends. In this
chapter, we will take a detailed look at what making subclasses means
Figure 4.7 shows how the objects that belong to a subclass form a subset of the
objects that belong to the superclass. Another way of saying this is to use the
concepts of "specialization" and "generalization."
The concept of polymorphism is central to class trees and inheritance. It means
that a client object can send the same message to different server objects, and these
objects know all on their own how they will perform the service requested. We have
a simple example when we print a document to different printers. As the user
(client), we send the message "Print this document", and the individual printer
knows how to do the printing all by itself. In practice, the different drivers are
responsible for the job, but for us as users this is hidden.
getName getName
getPricePerM getPricePerRoH
getWidth getLengttiPerRoll
getNoOTMeters getWkJthPerRoll
getTotalPrice
getTotalPrice
Figure 12.1 Classes that describe different types of materials for use in renovation (UML)
12.1 Generalization and Specialization
Material
-name
-price generalization
superclass
+getPricePerUnit
Paint
-noOfCoats specializations,
subclasses
+noOfCoats
Figure 12.2 The material class represents a generalization of the flooring, paint, and wall-
paper classes (UML)
In Figure 12.2, we've collected what these three classes have in common into the
Material class. We say that the Material class represents a generalization
(superclass) of the Flooring, Paint, and Wallpaper classes. On the other
side, Flooring, Paint and Wallpaper classes are specializations (subclasses)
of the M a t e r i a l class. The o p e r a t i o n s g e t N o O f M e t e r s ( ) ,
getNoOf Liters (), and getNoOf Rolls () are collected under the common
name getMaterialReq (). We have made a class tree.
Attributes and operations have a - and + before them respectively. Minus means
a private member. Plus means a public member. This corresponds to the access
modifiers private and public, which we use when we program the classes.
Once we start exploring what the concept of inheritance involves, we will also see
that it's important to distinguish between access levels in the class diagram.
Generalization always expresses an "is-a" relationship. From Figure 12.2, we
therefore read the following in the direction of the arrow:
Flooring is a material.
Paint is a material.
Wallpaper is a material.
We can also, as mentioned earlier, look at the objects that a subclass describes as
a subset of the objects the superclass describes:
12 Inheritance and Polymorphism
Problem
A dentist has many patients. Most of them belong to the category permanent, but a
few are random. Only the permanent patients are grouped by sex. Draw a tree that
shows a generalization/specialization between the classes P a t i e n t ,
Permanent, Random, Male, and Female. Expand the class diagram so that it
also shows that the information about all the patients together makes up an
association between a PatientRegister class and one of the classes above
(which one?).
12.2 Inheritance
Now that we are going to look at the concept of inheritance, it can be beneficial to
consider it from the client side: see Figure 12.2. The client has access to the
members marked with a +.
What are the consequences for the client that the class Flooring is a subclass
of the class Material? This means that the client can send the following
messages to a Flooring object:
12.2 Inheritance
All the messages inherited from the class Material: getName (), get-
PricePerUnit ( ) , g e t T o t a l P r i c e ( ) , and g e t M a t e r i a l R e q ( ) .
All new messages declared in the Flooring class. Here that means that the
message getWidth () will come in addition to the messages mentioned
before.
Hence, a class does not inherit private members of a superclass. However, it's
important to be clear that objects of the subclass have the data contents that these
members represent, but the concept of inheritance is linked to the accessibility of
the members, and the members that are private in the superclass are not directly
accessible in the subclass. For example: an instance of the Flooring class has
name and price information in it, but this information can only be reached through
the methods getName () and getPricePerUnit ().
client
double tongthSurface = aSurface getLength().
double heightSurface - aSurface getWidth().
F calculate the number of heights 'I
mt noOfHeights = (nt) (lengthSurface /widthPerRoll).
double remnant = lengtiSurface % widthPerRoll.
if (remnant >=limt)noOfHeights++.
r calculate the number of rolls */
aWallpaper
inl noOfHeightsPerRoll = (mt) (lengthPerRoll / heightSurface).
if (noOfHeightsPerRoll >0) {
noOfRolls = noOfHeights / noOfHeightsPerRoll.
remnant = noOfHeighs % noOIHeightsPerRoll.
if (remnant >= limit) noOfRoBs**.
) else | // the roll is shorter than one height (rarelyi)
Abstract operations and abstract classes are marked with italics in the class diagram.
Concrete (i.e. non-abstract) operations and classes are written in regular text. All
pertinent implementations of an abstract operation will be shown in the class
diagram.
Problems
In a computer manufacturing company there are several categories of employees:
customer consultants, technical personnel, system developers, and administrative
employees. Some of the last group are secretaries. The following applies:
All employees have the attributes name, position, and telephone number. A
client will be able to get all the data, and it will be able to change the position
and telephone number.
12.3 The Material Class with Subclasses
The salary is calculated for all employees, but the algorithm is different
depending on which category of employee you belong to.
1. Draw a class tree that shows the connection between these classes. Include
attributes and operations. Use + and - to show the level of accessibility for the
different members.
2. Should any of the operations you specified be polymorphous? Explain why and
describe how the polymorphism can be used in this case.
3. Explain what is inherited from one class to another in your model.
We make subclasses using the keyword extends. Classes that are declared
without using extends (for example, the Material class) become direct
subclasses to the java . lang. Object class. This is the reason that we can talk
about one, and only one, class tree in Java. The Object class is always at the top
of the tree. All other classes are subclasses (direct or indirect) of this class.
Let's look at the constructor for the Flooring class:
public Flooring(String initName, double initPrice, double initWidth) {
super(initName, initPrice);
widthOfFlooring = initWidth;
}
Constructors are not inherited. Even if we hadn't given a start value for the width
of the flooring, we would still have had to program the constructor in the
Flooring class. It would have looked like this:
public Flooring(String initName, double initPrice) {
super(initName, initPrice);
}
The keyword super is used to call the constructor for the superclass. The
parameters initName and initPrice are sent along as arguments with the call
for the constructor in the superclass.
If we don't call a specific constructor in the superclass, the constructor with no
arguments will be used. In our example, this will give a compile-time error, since
there is no such constructor. Maybe now is a good time for a little review. If we don't
make any constructors at all in a class, a default constructor will be made
automatically. The default constructor is like a constructor with empty parameter
list and empty body. If, on the other hand, we make our own constructors, which
we usually do, the default constructor is not created automatically. If we want a
constructor with empty parameter list to exist, we have to create it ourselves.
The compiler requires that a possibly super () call must be the first statement
in the constructor body. Little else is new in the rest of the Flooring class. We
only program the things that distinguish this class from the superclass:
The Paint and Wallpaper classes are created the same way as the
Flooring class.
V
class Flooring extends Material {
private static final double limit = 0.02; // limit for one more width
private double widthOfFlooring; // meter
public Flooring(String initName, double initPrice, double initWidth) {
super(initName, initPrice);
widthOfFlooring = initWidth;
}
public double getWidth() {
return widthOfFlooring;
}
/*
* We are going to calculate the amount which is needed to cover one surface.
* The flooring is always placed crosswise relative to the length of the surface.
* If you want to find the amount the other way, you have to change
* width and length in the surface argument.
*/
public double getMaterialReq(Surface aSurface) {
double lengthSurface = aSurface.getLength();
double widthSurface = aSurface.getWidth();
int noOfWidths = (int)(lengthSurface / widthOfFlooring);
double remnant = lengthSurface % widthOfFlooring;
if (remnant >= limit) noOfWidths++;
12 Inheritance and Polymorphism
/*
*Paint.java E.L 20010815
*
V
class Paint extends Material {
private static final double limit = 0.02; // limit to buy 0.5 liters more
private int noOfCoats;
private double noOfSqMPerLiter;
public Paint(String initName, double initPrice, int initNoOfCoats,
double initNoOfSqMPerLiter) {
super(initName, initPrice);
noOfCoats = initNoOfCoats;
noOfSqMPerLiter = initNoOfSqMPerLiter;
}
public int getNoOfCoats() {
return noOfCoats;
}
public double getNoOfSqMPerLiter() {
return noOfSqMPerLiter;
}
/*
* This method calculates the amount of paint required to cover the surface.
* The result is rounded upward to the nearest 0.5 liters.
*/
public double getMaterialReq(Surface aSurface) {
double area = aSurface.getArea();
double noOfLiters = area * noOfCoats / noOfSqMPerLiter;
int noOfLiterslnteger = (int) noOfLiters;
double more = noOfLiters - noOfLiterslnteger;
if (more >= 0.5 + limit) return noOfLiterslnteger + 1 .0;
else if (more >= limit) return noOfLiterslnteger + 0.5;
else return noOfLiterslnteger;
r
* Wallpaper.java E.L. 20010517
*/
class Wallpaper extends Material {
private static final double limit = 0.02; // limit for one more width
private double lengthPerRoll; // meter
private double widthPerRoll; // meter
12.3 The Material Class with Subclasses
See Figure 12.4. The data contents are provided by the instance variables in the
W a l l p a p e r class and in the superclass. The superclass has two instance variables,
name and price. Since these are private in the superclass, we cannot get to them
from the Wallpaper class in any way other than by using the get methods. But
it's important to be clear about the fact that they're there. When we make an
instance of the Wallpaper class, room is also set aside for these variables. We
give them value by calling the constructor in the superclass.
12 Inheritance and Polymorphism
All the methods in the Material class are public. These methods therefore also
become public in the Wallpaper class. For example, we can write:
String name = theWallpaper.getName();
Problems
1. Make a new subclass for the Material class. The class will be called Parquet.
Parquet flooring is delivered in packages, and a package of parquet covers a
given number of square meters. The materials needed for a surface will be the
area of the surface divided by the number of square meters per package, rounded
up to the closest whole number of packages. Make a little test program for the
class.
2. Program the classes from the problem in Section 12.2. To save on the writing
work, you can make do with two categories of employees. The Employee class
will be abstract and have an abstract method calculateSalary (). The
algorithm for calculating salary is different for each individual category. You will
not program these algorithms hereyou will only get ready to program them.
You do this, for example, by having the method for technical personnel print the
12.4 Handling Instances of Subclasses as a Whole
following text: "An algorithm to calculate the salary for technical personnel is
not implemented yet."
3. Change the program so that the text "Salary is calculated in the standard way"
prints out if the method calculateSalary ( ) is not programmed in a
subclass.
4. What messages can a client send to instances of the various classes? Make a client
program that tests this.
All messages that we can send to a material, we can also sent to paint, wallpaper,
and flooring objects.
There are messages declared in the Paint class that have no meaning for
wallpaper instancesfor example, getNoOf SqMPerLiter ( ).
Let's look more closely at the short program in Program Listing 12.2. In the
printout, we do not distinguish between liters and meters. Purely and simply, we
write "units".
12 Inheritance and Polymorphism
class TestPolymorphism {
public static void main(String[] args) {
Material[] materials = new Material[5];
materials[0] = new Paint("Heimdal Super", 20, 2, 10);
materials[1] = new Wallpaper("Brocade77", 50, 12, 0.6);
materials[2] = new Paint("Heimdal Extra", 10, 3, 10);
materials[3] = new Flooring("Wool-Gold", 45, 5);
materials[4] = new Flooring("Soft-Gold", 30, 5);
Surface aSurface = new Surface("testSurface", 4, 5);
for (int i = 0; i < materials.length; i++) {
String name = materials[i].getName();
double req = materials[i].getMaterialReq(aSurface);
double price = materials[i].getTotalPrice(aSurface);
System.out.println("Name:" + name + ", Requirement:
+ req + "units, Price $" + price);
/* Example Run:
Name: Heimdal Super, Requirement: 4.0 units, Price $80.0
Name: Brocade77, Requirement: 4.0 units, Price $200.0
Name: Heimdal Extra, Requirement: 6.0 units, Price $60.0
Name: Wool-Gold, Requirement: 5.0 units, Price $225.0
Name: Soft-Gold, Requirement: 5.0 units, Price $150.0
V
In order to be able to give the right designation, we have to know what type of
material we are dealing with. We can write:
String unit;
if (materials[i] instanceof Flooring) unit = " meters";
else if (materials[i] instanceof Paint) unit = " liters";
else unit = " rolls";
System.out.println("Name:" + name +", Requirement:" + req + unit +", price $" + price);
We covered the instanceof operator in Section 11.10.
What if now we find out that we want to add parquet as a new type of material?
Of course, we have to make a new subclass for the Material class, but we also
have to expand the if -else if list. In this case it's feasible, but it's not hard to
imagine that in larger systems this can be a very complex process.
There is a more elegant solution to this. We have to let the classes themselves
(Flooring, Paint, etc.) assume responsibility for this as well. We don't put the
12.4 Handling Instances of Subclasses as a Whole
printout statements in the classes, but make methods that return suitable strings
that the client can choose to print out or search in, as it wishes.
Material materialRef
materialRef.getName()
materialRef.getPricePerUnitQ
etc.
Wallpaper wallpaperRef
materialRef may refer to
whichever of these objects
Flooring flooringRef
Figure 12.5 A reference can be set to refer to an instance of the class, or to an instance of a
subclass to the class
Problems
Continue working with the employee classes from the previous problems.
1. Make a client program similar to the example in this section. Send the message
calculateSalary () to all employee objects.
12 Inheritance and Polymorphism
Surface
RenovationProject 1 *
-name {frozen}
name: String {frozen} consists of -length {frozen}
-width {frozen}
addNewSurface(
+setMaterial( T
newSurface: Surface) uses
newMaterial: Material)
getSurface(name: String)
getNoOfSurfaces() +getMaterial()
+getArea()
getSurface(index: int)
+getCircumference() 1
addNewMateriaK
newMaterial: Material) Material
getMaterial(name: String)
1 -name {frozen}
getNoOTMaterials()
needs -price {frozen}
getMaterial(index: int)
getTotalPrice() +getTotalPrice(aSurface: Surface)
+getMaterialReq(aSurface: Surface)
Figure 12.6 Class diagram for renovation project with many surfaces and many materials
(UML)
12.5 The Renovation Case with Many Surfaces and Many Materials
In practice, the differences in the program code are small with respect to the
example in chapter 10. We replace references to Paint objects with references to
Material objects. A reference to Material can refer to an instance of any
subclass of Material whatsoever.
Figure 12.7 shows an excerpt of a run of the new version of the program. We see
that three surfaces are entered (ceiling, floor, and walls). The ceiling is painted. We
put flooring on the floor and wallpaper the walls. The currency format is as in
chapter 10 according to the running environment. To us this means Norwegian
crowns (kr). To you it possibly means euros or dollars. If we want to change the
materials for one of the surfaces, we click on it and the window on the right comes
up. All the registered materials are shown here, and we can also enter a new type of
material (new paint, new flooring, or new wallpaper).
We will look at some of the concrete changes in the source code. The classes
Material, Flooring, Paint, and Surface are shown in Program Listing
12.1. Otherwise the following classes are included in the system (for complete
programs see [URL Java book]):
Figure 12.7 User interface with many surfaces and many material types
1. Other uses of the Class class are outside the scope of this book. If you're interested, refer to more
advanced Java literature, for example (Horstmann, Cornell 1999].
12.6 What if Polymorphism Didn't Exist?
example in chapter 10 are minimal, despite the fact that our program now handles
many types of materials. The reason for this is that we are using inheritance and
polymorphism. We are handling all types of materials as a whole by working with
references to the Material superclass.
Problems
The example in this section covers the classes in Program Listing 12.1 and Program
Listing 7.3. In addition, print out the files Surface.Java, RenovationProject.java, and
RenovationChap12.java from chapter 12 at [URL Java book]. Now you will have a
complete program listing of all the classes in the example.
1. Explain the purpose of the constants newPaint, newFlooring, and
newWallpaper.
2. In the method setOptions ( ) (the RenovationChap12 class), we retrieve
the class name for an object in the following way:
theMaterial.getClass().getName()
The chances of your being able to figure out this method on your own might not
be very good. However, it's not so difficult to create program code that does
precisely this job. There are two main ways to do it. What are the two ways and
how does the source code look in those two cases?
3. In a problem in Section 12.3 you made the Parquet class. Where do you have
to make changes in the renovation example to include the material type parquet?
Make the changes and run the program.
Consider one more time if you think you need to use instanceof combined
with an i f - e l s e - i f - e l s e sequence. To do this, evaluate if it is better to make
an abstract method in a common superclass for the classes involved and thus let
every individual class get its own implementation for the method.
Now, of course, we can argue against this test since we know that object 1 is an
instance of the class C, and object2 is an instance of class E. However,
circumstances aren't usually so easy to grasp as in this example, and then the test is
necessary.
The entire program is shown in Program Listing 12.3.
class Testlnstanceof
public static void main(String[] args) {
A object 1 = new C();
A object2 = new E();
object1. method1 ();
object2. method 1();
if (object1 instanceof B) {
B anObject = (B) object1;
anObject.method2();
}
if (object2 instanceof B) {
B anObject = (B) object2;
anObject.method2();
12 Inheritance and Polymorphism
/* Example Run:
C: method 1
B: method 1
E: method2
*/
Problems
1. Download the program in Program Listing 12.2. Change the printout in the loop
such that all the attributes are printed. The printout will differ, therefore,
depending on the type of object. Use the instanceof operator.
2. Make the method toString ( ) for each of the classes Paint, Wallpaper,
and Flooring (see also Section 10.4). How will you solve problem 1 now?
}
public String getName() {
}
The instance variable name is private. We can refer to it only in the Surface class.
The constructor and the method getName ( ) are public. They are accessible from
anywhere, assuming that the class they belong to is public. This is the case in this
example.
If we don't use an access modifier, then package access applies. Then the
member (or the constructor) is accessible in the package the class belongs to:
String name; // for identification purposes
}
String getNameQ {
and all subclasses regardless of package have access to protected constructors and
members.
Figure 12.9 The access for constructors and members declared in the class
See Figure 12.9. This figure shows the access for members and constructors
declared in the class C. Follow the arrows from the access modifier of interest. There
we see, for example, that a member with the modifier protected can be reached
from all locations in package A, and from all subclasses of the class C regardless of
which package they belong to. There is, however, another limitation on using a
protected member or a protected constructor outside the package: we only have
access to this on behalf of an object in the code that is responsible for the
implementation of the object. Let's illustrate this with an example:
TestClass1 is declared in packageA:
package packageA;
public class TestClass1 {
private int a;
protected TestClass1 (int newA) {
a = newA;
public TestClass1() {
TestClass1 is public. In other words, you can basically make instances of the
class wherever you want. It has a protected constructor and a public constructor,
and it has a protected method.
12 Inheritance and Polymorphism
Constants are usually public, but can be private if they are not of interest outside
the class.
As a point of departure, classes have package access (no access modifier). This
also limits the access to public constructors and members of the class. Classes that
will be taken into general use are made public and added to a named package. Then
all public constructors and members will also automatically become public.
Check that the results are reasonable based on what's in the text. Try some of the
statements that are marked "not OK." Try to understand the error messages you
receive.
2. Suppose that we add the following classes to packageA:
package packageA;
class TestClass3 extends TestClass1 {
public TestClass3(int a) {
super(a);
12 Inheritance and Polymorphism
public TestClass3() {}
protected void method3() {
System.out.println("Method 3 in TestClass3");
}
public void method1() {
System.out.println("Method 1 in TestClass3");
class Tests {
public static void main(String[] args) {
TestClass1 obj1 =new TestClass1(20);
obj1.method1();
obj1.method3();
TestClass3 obj2 = new TestClass3(20);
obj2.method1();
obj2.method3();
TestClass3 obj3 = new TestClass3();
obj3.method1();
obj3.method3();
Describe the members of the class TestClass3. Which members are inherited?
One of the statements in main ( ) gives a compile-time error. Which one?
Remove this statement (e.g. by commenting it) and possibly statements that
depend on it. What will be output when the program runs?
Program Listing 12.4 shows the class Flooring2 and the two subclasses. You
will write a short client program as the solution to a problem at the end of this
section.
In the Flooring2 class, as an example, we have placed the modifier final
before the method getWidth ( ). This means that potential subclasses are not
allowed to have their own versions of this method.
Using final methods makes the execution of the program more efficient
because the Java interpreter doesn't need to pay attention to the fact that the
method can be overridden in a subclass.
Material
-name
-price
: Surface)
: Surface)
aSurface : Surface)
FirstSortFlooring
+getTotalPrice(aSurface: Surface)
/*
* FirstSortFlooring.java E.L. 2001-08-18
*
*/
final class FirstSortFlooring extends Flooring2 {
public FirstSortFlooring(String initName, double initPrice, double initWidth) {
super(initName, initPrice, initWidth);
/*
* SecondSortFlooring.java E.L. 2001-08-19
Since final sets limits on what can be done in the subclasses, we should think
about it carefully before we declare a method final. Still, it's usually safe to
declare the simple set and get methods as final.
Both of the subclasses in the example are declared as final in their entirety.
The modifier final is placed first in the class head. That means that it's not
possible to make subclasses for this class. Other examples of final classes are the
wrapper classes Integer, Double, etc.
Constructors are not inherited. Therefore, we have to make constructors in the
subclasses, even if these constructors' only task is to send the parameters on as
arguments for the constructor in the class above.
What happens if we do not create a constructor in the FirstSortFlooring
class? We remember that if we don't make a constructor at all, a default constructor
will be made automatically. This type of constructor will require the existence of an
equivalent constructor (i.e. a constructor with empty parameter list, default or not-
default) in the class above. In the Flooring2 class we do not have such a
constructor, and we'll therefore get a compile-time error.
When creating an instance of the FirstSortFlooring class, we want to
supply information about name, price and width. So the constructor should be as
follows:
public FirstSortFlooring(String initName, double initPrice, double initWidth) {
super(initName, initPrice, initWidth);
}
In the SecondSortFlooring class, we redefine two inherited methods. The
new d e f i n i t i o n s replace the inherited versions for instances of the
SecondSortFlooring class.
The method getTotalPrice ( ) replaces the method inherited from the class
Material through the class Flooring2. This method is based on the
original price and gives discounts depending on how much covering the
customer is buying. The amount of covering is calculated based on the new
version of getMaterialReq ( ) (see below). If the customer buys more than
5 meters of covering, she receives a discount of 70%; otherwise the discount is
50% off compared to the price for first sort covering.
12 Inheritance and Polymorphism
We use the keyword super to call the method as declared on the level above.
Example:
public double getMaterialReq(Surface aSurface) {
double basicReq = super.getMaterialReq(aSurface);
return basicReq * materialAddendum;
}
If we don't use the word super, the method will call itself and the program will
continue to run until the memory is full.
Of course, we can refrain from calling the method declared on the level above
when making a replacement for it. We saw examples of this in Section 10.4, where
we made our own versions of the methods equals ( ) and toString ().
Notice the difference between using super in constructors and methods:
Problems
1. Make a simple client program according to the following specifications:
Make an array with room for three references to Material objects.
Make an instance of the FirstSortFlooring class and two instances of the
SecondSortFlooring class. Set the references in the array to point to these
instances.
Make a Surface instance and send the messages get Total Price ( ) and
getMaterialReq ( ) to the three instances. Check the responses.
2. Make the method toString () for the classes Material, Flooring2,
FirstSortFlooring, and SecondSortFlooring. Let the method in a
subclass call the method on the level above, like this: super . toString ().
Expand the client program from problem 1 to test the new methods.
12.9 Rules and Syntax
/ Java Core
/!
Declaring a subclass
Syntax:
modifiers class nameOfSubclass extends className {
constructors and members
}
modifiers can be public, abstract, and/or final.
The class will be a direct subclass of the className class.
A class can have only one superclass, but many subclasses.
Inheritance
The members of a class are either declared in the class or inherited from the
superclass. A subclass can use the inherited member as it is or make its own version
(overriding or hiding, see below).
The level of access for an inherited member is also inherited.
Subclasses don't inherit private members.
Subclasses in the same package inherit members with package access, protected
members, and public members.
Subclasses in other packages inherit protected and public members.
Constructors aren't members, and therefore they aren't inherited.
The abstract modifier
Example of an abstract class:
abstract class Material {
etc.
It's not possible to make instances of an abstract class.
An abstract class doesn't need to contain or inherit abstract methods.
An abstract method consists of the modifier abstract followed by the rest of
the method head and a semicolon:
abstract methodHead;
A class that inherits, or declares on its own, an abstract method, has to be declared
as abstract.
An abstract class can contain both abstract and concrete methods.
12 Inheritance and Polymorphism
We can use the keyword super in a constructor to call the constructor directly
above in the class tree. The call to super ( ) has to be the first statement in the
constructor we make. The argument list for super () has to be in accordance
with the parameter list for a constructor in the superclass.
Make the class abstract. This is used if the class has or can have subclasses.
Make all constructors private. This is used if the class cannot have subclasses (it
is final, see below), java.lang.Math is an example of a class with only
private constructors.
We can't override or hide a method that is declared final (but we can hide a
variable that is declared final).
12.10 Interface
We encountered the concept of interface in Section 10.7. An interface was
presented there as a collection of method heads. These method heads are abstract
methods, as we have become acquainted with the concept in this chapter. In
Section 10.7 we saw how by implementing the interface java.lang
. Comparable in a class we can use the ready-made sorting methods in the
classes java.util.Arrays and java.util.Collections. This
interface contains only one abstract method, and implementing the interface thus
means implementing the following method:
public int compareTo(Object obj)
Thus, the ready-made sorting methods can use the method compareTo ( ) to
compare objects. If the objects are instances of a class that doesn't implement the
interface, the exception ClassCastException will be thrown.
We are also familiar with the interface Serializable (Section 11.10), which
doesn't contain any methods but is used as a mark to tell that instances of the class
in question can be serialized.
Program listing 12.5 shows two interfaces and a class that implements both of
them. Instead of a common comparison method as in the interface
C o m p a r a b l e , here we have declared three different methods:
greaterThan ( ), lessThan ( ), and equal ( ).
For variables in interfaces, it holds true that the modifiers public, static,
and final are implied and it's not recommended that these modifiers are stated.2
Thus, all variables in an interface should be considered as public class constants (or
"interface constants"). The Constants interface demonstrates a practical way to
use interfaces. Constants that are common for many classes can be collected in an
interface, and classes that need to use these constants implement the interface. Thus
all the constants are automatically accessible through inheritance, and
qualification isn't necessary to get hold of them.
The class FourDigitsNumber implements both of the interfaces. A class can
implement as many interfaces as is desirable.
Interfaces have certain traits in common with classes. However, an interface can
only contain abstract methods and constants. For the class that uses these constants,
they will work as if they were class constants. The same way that we can't make
instances of abstract classes, we also can't make instances of interfaces. A reference
can be of an interface type. In this case, the reference must be set to refer to an
instance of a class that implements the interface:
MyComparable number = new FourDigitsNumber(1000); // ok
MyComparable number = new MyComparable(); // not ok
2. In this book, we include the modifier public in the API reference where interfaces are described.
We do this because we know from experience that it's very easy to forget to write public before the
method in the class that is implementing the interface when you're sitting with a description in front
of you that doesn't say public.
12.10 Interface
Except in Chapter 19, we will make very few interfaces of our own in this book.
Little by little, however, we will start using many of the interfaces that come with
SDK, especially in conjunction with programming graphical user interfaces.
*/
interface MyComparable {
/* public abstract is implied for methods */
boolean greaterThan(Object obj);
boolean lessThan(Object obj);
boolean equal(Object obj);
}
interface Constants {
/* public static final is implied for variables */
int min = 1000;
int max = 9999;
}
class FourDigitsNumber implements Constants, MyComparable {
private int value;
public FourDigitsNumber(int initValue) {
if (initValue < min) value = min;
else if (initValue > max) value = max;
else value = initValue;
}
public int getValue() {
return value;
}
public boolean greaterThan(Object obj) {
FourDigitsNumber number = (FourDigitsNumber) obj;
return (value > number.getValue());
}
public boolean lessThan(Object obj) {
FourDigitsNumber number = (FourDigitsNumber) obj;
return (value < number.getValue());
}
public boolean equal(Object obj) {
FourDigitsNumber number = (FourDigitsNumber) obj;
return (value == number.getValue());
12 Inheritance and Polymorphism
class ExInterface {
public static void main(String[] args) {
FourDigitsNumber number1 = new FourDigitsNumber(700);
FourDigitsNumber number2 = new FourDigitsNumber(1700);
FourDigitsNumber number3 = new FourDigitsNumber(70000);
System.out.println(number1.getValue());
System.out.println(number2.getValue());
System.out.println(number3.getValue());
System.out.println(number1.greaterThan(number2));
System.out.println(number1.lessThan(number2));
System.out.println(number1.equal(number2));
/* Example Run:
1000
1700
9999
false
true
false
V
Java Core
Interface
Syntax:
accessModifier interface interfaceName {
constants
methodHeads
or:
accessModifier interface interfaceName extends superlnterface1 , superinterface2, .. {
constants
methodHeads
}
An access modifier for the interface can be public or it can be left out (package
access).
All the members in an interface are publicly accessible (public). This is
overruled by potential package access for the interface as a whole.
In the constant declarations, the modifiers public, static and final are
implied, and they will not be stated.
The method heads end with a semicolon and the modifiers public and
abstract are implied and will not be stated.
12.10 Interface
or:
modifiers class className extends superclass implements interface 1, interface2, .. {
A class can only have one superclass, but it can implement one or more interfaces.
The class inherits the members of all the interfaces it implements.
A class that implements an interface has to implement all the methods in the
interface, otherwise the class will be abstract.
interface that is presented to the rest of the world. The class, which in addition to
access methods also contains mutation methods, can therefore be reserved for use
by a narrower circle of programmers.
Client programmers, meanwhile, have to use constructors when they are going
to make objects, and these constructors are not located in the interfaces, but in the
classes. If you don't want client programmers to use the constructors, you can offer
instantiation methods through the interfacefor example, createPaint ( ). In
the class, this method will be implemented by the class making an object on its own
and returning this to the client:
public Paint createPaint(String initName, double initPrice, int initNoOfCoats,
double initNoOfSqMPerLiter) {
return new Paint(initName, initPrice, initNoOfCoats, initNoOfSqMPerLiter);
}
These kinds of methods are often called factory methods.
In chapter 19, we will create distributed systems. The client and server will run
on different computers and then the client will work with an interface as described
above.
Problem
In the online API documentation, look up the Cloneable interface. Also read
about the clone ( ) method in the Object class.
1. What are the concepts of deep and shallow copy? Can you demonstrate the
difference by explaining what it means concretely for instances of the class
Surface?
2. What does the standard version (the one that is inherited from Object) of
clone () do?
3. Try the standard version of clone ( ) on instances of the class Surface. What
do you find out?
4. Make your own version of the method clone ( ) in the class Surface. Try it
out.
A method that creates an instance of a class. Clients may use these methods instead
of constructors.
final Keyword that can be used, among other things, as a modifier in a method head (that then
means that the method cannot be overridden in subclasses) or a class head (that means that
the class cannot have subclasses).
generalization (Rumbaugh, Jacobson, Booch 1999, p. 287): "Ataxonomic relationship between a more
general element and a more specific element. The more specific element is fully consistent with
the more general element and contains additional information. An instance of the more
specific element may be used where the more general element is allowed." In our situation,
an "element" is equivalent to a class.
hide a name A name in a subclass may hide an inherited name of a class method or a variable. The class
method must have the same signature as the inherited class method.
inheritance Members that a class inherits from a superclass can be used in the same way as if they were
declared in the class. Inside the very same package, all nonprivate members are inherited.
Outside the package, public and protected members are inherited, protected members
under certain conditions. Constructors are not members and are therefore not inherited.
override a name A name in a subclass may hide an inherited instance method. The method must have the
same signature as the inherited method.
polymorphic An operation with many different implementations. The operation is declared in a class that
operation is a common superclass for the classes with the various implementations.
polymorphism We can send the same message to different types of objects; they know on their own how to
handle the message. The message is a polymorphic operation.
7. What does it mean for the programming that a class inherits members from
another class?
8. How do we use the keyword super?
9. When should we use the operator instanceof, and when should we not use
this operator?
10. Java offers four levels of access for constructors and members in a class. What
four levels are there? How do we declare them? And what do they imply?
11. Explain recommended guidelines for using access modifiers.
12. What type of inherited name can we override in a subclass? What type of
inherited name can we hide in a subclass? What is the difference between
overriding and hiding?
13. How do we declare that a method cannot be overridden in a subclass? Are there
any advantages to this?
14. What does the modifier final do in a class head?
15. What is a Java interface? Describe similarities and differences between
interfaces and classes.
16. Explain how to use the ready-made interfaces we have been through in this
book.
17. Explain what is implied by a class implementing an interface. Can a class
implement more than one interface at a time? Can implementation of an
interface contribute to a class becoming abstract?
r
1
Edition Series SingleBook
^ consists of
The author is always of interest for books. For books that are part of a series, we
will include information about all the publications (date and title of the individual
publication). Single books can come out in several editions. We will stick to
keeping track of the number of editions, and not the year every single edition came
out.
Both the title and publisher must be given to identify any reading material.
Do the following:
(a) Suggest instance variables and possible constants for every single class.
(b) Make a constructor for the class Series. This constructor will take all
pertinent information about a series, as well as information about the first
edition in the series, as arguments.
It should not be possible for a client to register a new series without registering
the first edition in the series at the same time.
(c) Make toString ( ) methods for all the classes in the problem except the
class Register.
(d) Write a method that changes the status to a specific book from a single book
to a series. This book will then become the first in the series. The date and
subtitle will be parameters for the method. The method can also have other
parameters. The method will belong to the class Register.
12 Inheritance and Polymorphism
(e) Write a method that finds information about all periodicals within the same
genre. The genre will be a parameter and the method will return all the
information as a text that it's suitable to print.
(f) Create whatever is necessary in terms of other constructors and methods so
that you can finally make a client program that tests what you have answered in
a) through e).
Problem 3
A doctor's office can be organized such that patients who want it can be called in
for routine checkups once a year. These patients are called "permanent patients".
For all patients, both permanent and nonpermanent, the patient's name,
address, and social security number must be stored.
For permanent patients, test results are stored in the data system. For the sake of
simplicity, we say that test results can be represented with decimal numerals.
Together with each test result, the name of the test and date are stored.
The system you create must provide the following functions:
Make a class diagram and program the system. The client program will be menu-
driven.
Problem 4
A car company wants a registry of its customers. The company has both private and
corporate customers. For all types of customers, they want to register the customer's
name, address, and telephone number. For corporate customers, the name and
telephone number of the contact person will also be stored.
When a car is sold, information about it (sales date, make of car, and price) will
be entered for the right customer, so that the car company has a summary at any
time of all the cars sold to a specific customer. For used cars, the model year and a
short description of the car's condition at sale will also be recorded. Note: For new
cars, the model year is the same as the sales year if the sale occurred in September
or earlier. For sales in October through December, the model year being sold is the
next year's model. Therefore, for new cars, the model year will not be stored, but
calculated when needed.
Pertinent services that the registry can offer:
Record sales
Find the average age of the cars a customer has bought. The age is calculated as
the difference between the sales year and the model year (but it must not be
negative!).
Students only have access during the day, from 7 a.m. to 11 p.m., and then only
to a limited number of doors.
Course participants have access to specific doors during specific time intervals
and on specific dates, but never at night between 11 p.m. and 7 a.m. Over the
course of a day, the course participant has access during only one periodfor
example, from 8 a.m. to 3 p.m.
Find out if a specific person will gain access to a specific door at a specific time
Expand the class diagram with attributes and operations, and possibly new
classes if you need to.
Program the classes. Make simple test programs that test each of the classes.
1
CardRegister Card
consists of
Permanent Course
1
Employee Student
Layout managers
Panels
Inner classes
Create an applet with a user interface that consists of pushbuttons and texts
Handle events that are fired when the user presses a button on the screen, or
when she presses the Enter key after having typed text in a text box
Divide a window into several panels, where every panel has its own layout
manager
Even the smallest GUI program will require you to program event handling.
Thus, that will be the primary topic in this chapter. We will create applets with
pushbuttons and texts and see how we arrange the components in the window.
We create a GUI using the Swing library. This chapter and the next two chapters
discuss some of the possibilities that Swing offers to GUI programmers. If you need
more material, refer to one of the weighty books written about Swing.l There is also
quite a bit on Sun's Web pages on the Internet.
GUI programming requires solid knowledge of most of the things we've covered
up to this point. The GUI library is part of the large class tree that forms the Java
SDK, and using this requires that you understand and are able to use the concept
of inheritance for methods and variables, and you must also be able to use ready-
made interfaces.
1. See, for example, (Eckstein, Loy, Wood 1998| or (Walrath, Campione 1999|.
13.1 GUI Components
Figure 13.2 shows an excerpt of the class tree with the Object class at the top. This
excerpt covers several packages:
The java . lang package: the Object class.
JPane
SDK provides two sets of classes for creating GUI components. The older one is part
of the Abstract Windowing Toolkit (AWT), and these are the classes named
Checkbox, List, Button, etc. All of these classes are under the Component
class. Swing is newer and, to avoid naming conflicts, these classes all have names
starting with a capital J. Most of the Swing components are subclasses of the
JComponent class.
13 GUI Programming and Events
Remember the J!
Remember that most of the classes that describe Swing GUI components have
names starting with a J. It's easy to forget this and then use a class in AWT instead.
Combinations of AWT and Swing components don't always work so well together
in programs.
In this book, the GUI components are depicted for the user according to a standard
for appearance and behavior called "Java look and feel". If you've worked with
window systems on different platforms, you've discovered that they look a little
different and they also behave a little differently. It's possible to indicate that the
graphical user interface you are creating will look like and behave according to
"Motif Look and Feel" or "Windows Style Look and Feel". Try the different choices
in the "Look and Feel" menu in the demo program in Figure 13.1. However, you
will discover that the windows' appearance is always consistent with the platform
you're running on; it's just the contents of the windows that adjust to the "Look
and Feel" you want. "Windows Style Look and Feel" is only permitted on the
Windows platform.
A central concept for GUIs is focus. A component in focus is the active
component. The active component is the one which reacts to our mouse and
keyboard activities. On the screen this is usually indicated in some way or other
for example, with a darker frame around a window, a vertical bar cursor in a text
field or a thicker frame around a button. As users we may shift focus from one
component to another, for example by clicking with the mouse on the other
component.
We use inheritance a great deal when we program GUIs. Therefore, it's
important to have a certain familiarity with the class tree. You'll find this tree when
you search in the online API documentation, and you'll also see which methods
the class in question inherits from classes further up the tree. For example, look up
the JTextField class. You find that this class inherits many methods from
JComponent, Container, and Component.
In this section we will include an excerpt from the API reference for the
Component class. This excerpt is, as with all the classes in this book, and
especially for the GUI classes, not complete.
If you haven't already discovered how useful the online API documentation is,
you certainly will now that you're ready to program GUIs. You will probably
discover that it's indispensable.
13.1 GUI Components
API Reference
It's the HTML code that determines the size of an applet. If you run applets directly
from an editor, all the applets will probably be the same size. The applets that are
presented in this book are adjusted to a suitable size by stretching the window
frame once they are presented by the appletviewer.
What's happening here? What sets everything in motion is the event that fires when
you press the button. Every time you press the button, the same thing happens. The
text "You pushed the button!" is printed to the console.
As users we can initiate many types of events in a GUI program. We can give a
command by pressing a button (as we did here) or we can ask to have a menu
selection carried out; we can leave an input data field or we can close a window, to
mention some typical events. Every single event means that the program reacts in
some way: data is checked when we leave an input data field, a calculation is
performed when we press a button, our document is printed when we make a
menu selection, etc.
The event determines which case block will be performed. The loop runs
"indefinitely" and listens the whole time for new events.
Consider that this loop is running inside the Java interpreter, and we as
programmers only deal with the contents of each individual case block.
In addition to the events that directly affect the contents of our program, we have
all the events that cause the entire screen or portions of it to be repainted (for
example, the event of a window closing). This event also has many other
consequences, including the contents of the window no longer being accessible in
the program. The Java interpreter takes care of almost all of this event handling. We
rarely need to think about it.
To put it another way, a program with a graphical user interface is very
complicated. What is the main difference between the programs we've written up
to this point and programming with a graphical user interface?
The programs we wrote up to this point are characterized by the fact that the
program controls the user's activities. The program asks for data in a specific order,
and the user has to input that data or he won't get any further in the program. The
program can offer the user a limited menu, but it's the program that decides when
the menu will be offered.
push
actionPerformed( )
printing...)
People who work with machines like to feel they control the machine, not the
opposite. A good graphical user interface will give the user this sense. The user can
choose the order of the activities and how (for example, choosing between the
mouse and the keyboard) they will be performed. He has many more choices than
the user of the first type of program. This places much more complicated demands
on us as programmers.
With this in the back of our minds, we'll take a closer look at our little program
with a simple pushbutton. Follow along in Figure 13.4. The button is an object in
the program. It's called myButton and is an instance of the JButton class. By
pressing the button, the user generates an event and this event is also represented
as an object (not shown in the figure). This object is administered by the Java
interpreter and therefore we don't have any name of our own for this object, but
we know that it is an instance of the ActionEvent class. We've left out the
vertical rectangles that represent that an object is active, because that would over-
complicate the presentation here, especially because objects that aren't shown in
the figure are involved.
The button is the source of the event.
In order for something to happen after this event is fired, there have to be objects
that listen to the event. We create these objects in our program and also have to
register that they will listen to events from specific objects. In this example, we have
an object of this type called theButtonListener, and it is an instance of the
ButtonListener class.
When a specific event occurs, the Java interpreter takes care of sending a specific
message to all listeners that are registered. In this case, the Java interpreter sends the
message actionPerformed ( ) to theButtonListener object.
The class the listener is an instance of, therefore, has to implement a method
with this name, and the handling of the event is inside this method. In our example,
the method looks like this:
public void actionPerformed( Action Event event) {
System.out.println("You pushed the button!");
}
A summary of what happens:
1. The user presses the button. The button is the source of an event.
2. The Java interpreter creates an instance of the ActionEvent class.
3. The Java interpreter sends actionPerformed ( ) messages to all registered
listeners.
4. The contents of the actionPerf ormed ( ) method are carried out.
And then the Java interpreter waits for the next event to take place.
Now let's go through the applet's source code. See Program Listing 13.1.
We need two classesone that describes the applet (the PushbuttonApplet
class) and one that describes the listener (the ButtonListener class).
13.2 Pushing a Button
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PushbuttonApplet extends JApplet {
public void init() {
Container guiContainer = getContentPaneQ;
LayoutManager layout = new FlowLayout();
guiContainer.setLayout(layout);
JButton myButton = new JButton("Push here!!"); // creates the button
guiContainer.add(myButton); // puts it in the container
ButtonListener theButtonListener = new ButtonListener(); // creates a listener
myButton. addActionListener(theButtonListener); // links the listener to the button
When you start the applet, the i n i t ( ) method is called. We place the
construction of the user interface in this method. This type of user interface consists
of one or more windows with pushbuttons, text fields, listboxes, etc. We can think
of a window as a container for GUI components.
We always have to start by getting a reference to this container:
Container guiContainer = getContentPane();
Here, the applet sends the message get Content Pane ( ) to itself. This method
is declared in the JApplet class.
Container is a class that belongs to the java . awt package.
The way the different GUI components are laid out in the window is determined
by a layout manager. We will come back to more details on these later; for now we
just have to say that if we don't designate a particular layout manager, our button
will cover the whole window in this case and that's not the idea. Therefore, we set
the layout manager to "flow layout" :
LayoutManager layout = new FlowLayout( );
guiContainer.setLayout(layout);
Now we create a pushbutton and put it in the GUI container:
JButton myButton = new JButton("Push here!!"); // creates the button
guiContainer.add(myButton); // puts it in the container
13 GUI Programming and Events
Note that the method head has to be public and exactly the same as the one
described in the ActionListener interface. Therefore, we also have to include
the parameter even if we don't make use of the information that's in the event
object.
API Reference
Method:
public void setl_ayout(LayoutManager newLayoutManager)
This method determines which type of layout manager will apply for this container,
public Component add(Component comp)
This method places a GUI component in the container. Pertinent GUI components
include buttons, lists, text fields, etc. All of these belong to subclasses of the
Component class. This method returns the reference to the component.
The javax.swing.AbstractButton class
This class is a superclass for, among others, the classes JCheckBox,
JRadioButton, JButton, and various menu classes (see Figure 13.2). Thus
these classes inherit the methods declared in this class.
Methods:
public void addActionListener(ActionListener aListener)
This method registers a listener for the button. The listener is alerted every time the
button generates an ActionEvent. That happens when the user presses the
button.
public void setMnemonic(char mnemonic)
This method sets a "mnemonic" (from Greek: mneme = memory) for the button.
This is a keyboard alternative to pressing the button. The underlined letter is the
"mnemonic"for example, the letter S in Save.
public void setEnabled(boolean open)
If the argument is false the button is lockedin other words, the user can't press
it. An argument value of true enables the button again.
public void setText(String text)
This method sets the text on the button. We use this method if we used the
constructor with no arguments to create the button.
The javax.swing.JButton class
This class is a subclass of AbstractButton and inherits all methods from that
class.
Constructors:
public JButton()
public JButton(String text)
public JButton(lcon icon)
public JButton(String text, Icon icon)
The constructors can create buttons with text and/or icons on them. For an example
of buttons with icons, see Figure 13.9 and Program Listing 13.7.
13 GUI Programming and Events
Problems
In Problems 2-4 you have to use methods described earlier in the API reference.
1. Expand PushbuttonApplet with another button. Link theButton-
Listener object to this button. This listener object is now linked to both of
the buttons. Check that the printout to the console is the same regardless of
which button you press.
2. Create keyboard alternatives for both of the buttons. Check to see that they work.
As a user, you have to hold the Alt key down at the same time as the selected
"mnemonic".
13.3 Inner Classes
3. Test the set Enabled ( ) method with false as a parameter. Check to see that
it works.
4. Test the getActionCommand ( ) method.
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ColorButtonApplet extends JApplet {
public void init() {
Container guiContainer = getContentPane( );
guiContainer.setLayout(new FlowLayout());
JButton myButton = new JButton("Push here!!");
guiContainer.add(myButton);
ButtonListener theButtonListener = new ButtonListener(guiContainer);
my Button.addActionListener(theButtonListener);
13 GUI Programming and Events
The procedure in Program Listing 13.2 is relatively clumsy and now we'll see how
we can use inner classes to simplify the programming.
Often with graphical user interfaces, we don't need listeners in classes other than
the class from which we're administering the user interface. In the example above,
we don't need the button listener outside the ColorButtonApplet class. By
declaring the ButtonListener class inside the ColorButtonApplet class
we gain direct access from the ButtonListener class to all the variables
declared in the ColorButtonApplet class. Therefore we don't need to send,
for example, the GUI container over as an argument for the constructor. On the
other hand, some of the local variables in the init ( ) method are moved out of
the method and become instance variables, so that we can access them in the inner
class.
Program Listing 13.3 shows the alternative version of the applet. The
simplifications with respect to the earlier version are in the implementation of the
ButtonListener class. It can now send messages directly to guiContainer
because it's an instance variable in the applet class.
A class within a class (an inner class) is considered as a member of the class,
similar to variables and methods.
An instance of an inner class always belongs to a specific instance of the outer
class. If we create two instances from the ColorButtonApplet2 class
(something that is very unlikely, since these are applets), these will each have their
own ButtonListener object.
V
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ColorButtonApplet2 extends JApplet {
private Container guiContainer;
public void init() {
guiContainer = getContentPane();
inner Classes
guiContainer.setLayout(new FlowLayout());
JButton myButton = new JButton("Push here!!");
guiContainer.add(myButton);
ButtonListener theButtonListener = new ButtonListener();
myButton.addActionListener(theButtonListener);
}
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
guiContainer.setBackground(Color.red);
Access to the inner class is controlled by any access modifier in the class head. In
this example, the class is private and that will be the case in most of our examples.
In this book, we'll use inner classes in connection with programming graphical
user interfaces. Inner classes also have other applications, but we'll leave it at that
for now.2
Let's look at an example where the user enters her name. Pressing the button
elicits a greeting to the user. See Figure 13.5 and Program Listing 13.4. The figure
shows the window after the user has entered her name and pressed the button.
Let's look at two new classes for generating GUI components:
The JLabel class is used to create objects that contain texts that the program
can print on the screen. The objects nameLabel and greeting are both
instances of this class. The object nameLabel gets its text content when it's
created, while the object greeting doesn't get its value until after the user has
pressed the button.
The JTextField class is used to create a single-line field that the user can
enter a text in. These types of fields are usually called text boxes. The object
nameField is an instance of this class. The length 20 is stated as the argument
for the constructor. It's completely possible to enter texts that are longer. The
V
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class NameApplet extends JApplet {
private Container guiContainer;
private JTextField nameField = new JTextField(20);
private JLabel greeting = new JLabel();
public void init() {
guiContainer = getContentPane();
guiContainer.setLayout(newFlowLayout());
JLabel nameLabel = new JLabel("What's your name?");
guiContainer.add(nameLabel);
guiContainer.add(nameField);
JButton myButton = new JButton("Push here!");
guiContainer.add(myButton);
ButtonListener theButtonListener = new ButtonListener();
myButton.addActionListener(theButtonListener);
guiContainer.add(greeting);
}
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
String name = nameField.getText();
greeting.setText("Hallo," + name + "!");
API Reference
The last parameter in the last constructor makes it possible to justify the text in a
specific way. The standard is left justified. The possibilities are given as class
constants inherited from the SwingConstant s interface. The most common are
CENTER and RIGHT. Remember to qualify these if they are going to be used. For
example, JLabel. RIGHT.
Method:
public void setText(String text)
This method sets a value for the text.
The javax.swing.JTextField class
This class describes a text box. The user can write in the box. However, the program
can block the text box for user input.
Constructors:
public JTextField()
public JTextField(String text)
public JTextField(int noOfColumns)
public JTextField(String text, int noOfColumns)
The number of columns determines the width of the box. If the font is
proportional, a column is about the width of the letter 'm'. The text can be wider
than the box.
Methods:
public void setHorizontalAlignment(int horizontalAdjusting)
public int getHorizontalAlignment()
These methods handle the alignment of the text in the text box. The default is left
justified. Other possible alignments are JTextField. CENTER and
JTextField.RIGHT.
public void setFont(Font newFont)
This method changes the font in the text box.
public void addActionListener(ActionListener aListener)
This method registers a listener for the text box. The listener reacts when the user
presses the Enter key.
This class is a subclass of the JText Component class and inherits all of this
class's methods.
The javax.swing.text. JTextComponent class
Methods:
public String getText()
public void setText(String text)
13 GUI Programming and Events
One more example: see Figure 13.6 and Program Listing 13.5.
Here we've created three buttons, each with its own color. Clicking one of the
buttons will change the color of the text. We link all three buttons to the same
listener. The actionPerformed ( ) method starts by finding out which of the
buttons was the source of the event.
V
JButton buttonRed = new JButton("Red");
buttonRed.setBackground(Color.red);
guiContainer.add(buttonRed);
JButton buttonBlue = new JButton("Blue");
buttonBlue.setBackground(Color.blue);
guiContainer.add(buttonBlue);
JButton buttonCyan = new JButton("Cyan");
buttonCyan.setBackground(Color.cyan);
guiContainer.add(buttonCyan);
/*
* Creates a listener and links all the buttons to the same listener.
V
ButtonListener theButtonListener = new ButtonListener();
button Red.addActionListener(theButtonListener);
buttonBlue.addActionListener(theButtonListener);
buttonCyan. addActionListener(theButtonListener);
guiContainer.add(greeting);
}
private class ButtonListener implements ActionListener {
public void action Performed(ActionEvent event) {
String colorName = event.getActionCommand();
Color color;
if (colorName.equals("Red")) color = Color.red;
else if (colorName.equals("Blue")) color = Color.blue;
else color = Color.cyan;
greeting.setForeground(color);
String name = nameField.getText();
greeting.setText("Hallo, " + name + "!");
Problems
You will need the last API reference to solve these problems. You will make changes
to the program in Program Listing 13.5. Start with the original program when you
begin each problem.
1. Modify the program so that the user can't write anything in the text box after
she's pressed one of the buttons for the first time.
2. Modify the program so that the user can't press the same button more than three
times.
3. Modify the program so that the pushbuttons contain the names of three different
fonts. Clicking one of the buttons will change the font for all the text in the
window.
13 GUI Programming and Events
4. Currently, the program outputs the greeting when the user presses a button.
Modify the program so that the greeting appears if the user presses Enter in the
text box. Then focus will be set to the first of the three buttons.
The left part of Figure 13.9 shows how we can use GridLayout to input data.
Because all the cells are the same size, we choose to right justify the background
texts so they won't be too far away from the text box they belong to.
The figure on the right shows ten pushbuttons with icons on them. The icons are
from jdk1.4/demo/applets/Animator/images.
Figure 13.7 FlowLayout lays the components out from left to right, centered on the lines
*/
import java.awt.*;
import javax.swing.*;
13.4 Managing the Layout
/*
* TestGridLayout2.java E.L. 2001-08-18
*/
import java.awt.*;
import javax.swing.*;
public class TestGridLayout2 extends JApplet {
public void init() {
Container guiContainer = getContentPane();
guiContainer.setLayout(new GridLayout(2, 5, 5, 5));
/*
* The images have to be in the directory Beans,
* and the files have the names T1 .gif, T2.gif, etc.
*/
String nameOflmage = "Beans/T";
for (int imageNo = 1 ; imageNo <= 10; imageNo++) {
String imageFilname
= nameOflmage.concat(imageNo + ".gif");
Imagelcon icon = new Imagelcon(imageFilname);
JButton button = new JButton(imageFilname, icon);
14.3 Choices Using Check Boxes
ButtonGroup Component
Figure 14.5 GUI components for choices: JList, JCheckBox, and JRadioButton
(UML)
Both check boxes and radio buttons generate Action Events. This is the same type
of event we are familiar with from the pushbutton examples earlier. A listener
object therefore has to be an instance of a class which implements the
ActionListener interface (in other words, the actionPerformed ( )
method we know so well).
A list generates a ListSelectionEvent, which we will come back to in our
discussion of lists.
The class tree is shown in Figure 14.5.
Finally, we paint the whole window again with repaint (); see the API
reference for the Component class in Section 13.1.
The default layout manager for applets is BorderLayout, where we can place
components in the north, south, east, west, or center.
The default layout manager for panels is FlowLayout, where the components are
placed line by line, center justified.
Figure 13.10 We divide the container into three smaller containers (panels)
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DrawApplet extends JApplet {
/* These ellipse attributes will be used the first time the ellipse is drawn V
private static final String x = "70";
private static final String y = "50";
private static final String width = "50";
private static final String height = "100";
/*
* The following variables will be used in the init() method,
13.4 Managing the Layout Pff
r
* This class describes the drawing of an ellipse where the ellipse attributes
* may be changed by the user. The class receives the attributes as texts.
* If it is not possible to convert the text into a number, the corresponding
* attribute gets the value 0. A litte message is sent to the console.
V
class Drawing extends JPanel {
private int x;
private int y;
private int width;
private int height;
public Drawing(String initX, String initY, String initWidth, String initHeight) {
x = convertText(initX);
y = convertText(initY);
width = convertText(initWidth);
13.4 Managing the Layout
height = convertText(initHeight);
}
public void setX(String newX) {
x = convertText(newX);
}
public void setY(String newY) {
y = convertText(newY);
}
public void setWidth(String newWidth) {
width = convertText(newWidth);
}
public void setHeight(String newHeight) {
height = convertText(newHeight);
}
public void paintComponent(Graphics window) {
window.fillOval(x, y, width, height);
}
private int convertText(String text) {
try{
return Integer.parselnt(text);
} catch (NumberFormatException e) {
System.out.println("lt's not possible to convert" + text + " into integer.");
return 0;
API Reference
Problems
Modify the program in Program Listing 13.8. Use the original version of the
program for each problem.
1. Modify the program so that getSource ( ) is used instead ofgetAction-
Command ( ). (See the java.util. EventObject class, Section 13.2.)
2. Modify the southern panel so that it uses GridLayout. The user should be able to
choose between all the predefined colors in the Color class. It's most practical
to use arrays when there are so many buttons.
AWT Abstract Windowing Toolkit, the library for graphics and GUI programming from JDK 1.0.
Many of the classes are still pertinent (examples: Color, Font, and the various layout
managers), but we use the Swing library to create GUI components.
event Used in connection with GUI programming about the result of a user activityfor example,
pressing on a button, leaving a data input field, closing a window. The Java interpreter
creates an object that contains information about the event. The object becomes an
argument in a message that is sent to registered listeners. Events can also occur in ways other
than as the result of a user activity.
event-driven A program that is controlled by events. In a GUI, these events are usually initiated by the
program user. Therefore we can also say that the programs are user-driven.
focus A component in focus is the active component. The active component is the one which
reacts to our mouse and keyboard activities. On the screen this is usually indicated in some
way or otherfor example, with a darker frame around a window, a vertical bar cursor in a
text field or a thicker frame around a button.
GUI The different parts that make up a graphical user interface. Most of the GUI components
component belong to a subclass of the Component class. Exceptions are the menus in the AWT library.
GUI container An object that is an instance of the Container class, or a subclass of this class. We can fill
the container with components using the add ( ) method.
inner class A class that is declared inside another class. The inner class is regarded as a member of the
class, and it has direct access to the outer class's variables and methods. An instance of an
inner class always belongs to an instance of an outer class.
layout An object that determines the way the GUI components will be laid out in the window.
manager
listener An object that implements a listener interface. Objects of this type can be registered as
listeners for source objects.
14.3 Choices Using Check Boxes
[^JToggleButton
Figure 14.5 GUI components for choices: JList, JCheckBox, and JRadioButton
(UML)
Both check boxes and radio buttons generate Action Events. This is the same type
of event we are familiar with from the pushbutton examples earlier. A listener
object therefore has to be an instance of a class which implements the
ActionListener interface (in other words, the actionPerformed ( )
method we know so well).
A list generates a ListSelectionEvent, which we will come back to in our
discussion of lists.
The class tree is shown in Figure 14.5.
Problem 2
Create a very simple calculator. The calculator will have a pushbutton for each
individual digit. It will only be able to handle two numbers. It will be possible to
add, multiply, divide, or subtract the numbers from each other. The user will be
able to choose whether she wants to enter the numbers directly into text boxes or
press on the number buttons.
Problem 3
Create an applet that lets the user try to create a magic squares. The square will
consist of 4 x 4 cells. The user enters numbers in the cells. The numbers 1-16 will
be used. Every time the user presses a pushbutton the applet will find out if the
square fulfills the requirements. The requirements for a magic square are that the
sum in the vertical, horizontal and diagonal directions will be the same.
Problem 4
Create a simple reservation system for a concert hall. You can assume that the rows
are all the same length. Let every seat be represented by a pushbutton on the screen.
The pushbutton will have the seat and row number displayed on it. If the seat is
available, the button will be green. The user reserves the seat by pressing on it. Then
it turns red. If the seat is reserved, pressing on it will make it available again.
Learning goals for this chapter
After completing this chapter, you will be able to create:
You will also know when to use the different GUI components to create the best
possible user interface.
Check boxes are used if the user is going to make none, one, or several choices
from a few alternatives.
Radio buttons are used if the user is going to make exactly one choice from a few
alternatives.
List: If there are a large number of alternatives (more than 5-7), we should
consider using lists. Swing provides both single choice and multiple choice lists.
A single choice list will correspond to radio buttons, while multiple choice lists
correspond to a group of check boxes.
14 Text. Choices, and Windows
Most of the examples in this chapter, as in the previous chapter, are applets. At
the end of the chapter, we will look at how we make application windows.
The JText Field class: A one-line text. Pressing the Enter key leads to an
ActionEvent, the same type of event as pushbuttons, but the focus won't move
out of the field. That has to be programmed.
The JTextArea class: A text of several lines. Pressing the Enter key leads to a
new line.
14.1 Text Components and Focus Listeners
The JPasswordField class: The text the user enters here will be hidden by
asterisks. Pressing the Enter key has the same effect as for JTextField.
It's possible to create listeners that will register all potential changes made in text
fields (see DocumentListener in the online API documentation). However,
it's rare that we need this since we usually handle text using menu choices and/or
pushbuttons.
Shortcuts for copying, pasting, and cutting are implemented in the Swing classes.
For Windows and Java Look and Feel the shortcuts are [Ctrl ]+(c], [ctrl]+(v"l, and [Ctrl)+
0.
Figure 14.2 and Program Listing 14.1 show examples of the three types of text
components. The user will enter a username (JTextField) and password
(JPassword). If these are correct, he is permitted to change the text in the large
text area in the middle of the window (JTextArea). The password in the
password field should be checked when this field loses focus. We have to make a
focus listener. This will react by checking the username and password, and setting
focus back to the username field if the contents of either one of the fields is invalid.
If, after having changed the text, the user presses the button marked "Print," the
text will be written to the console.
Pushing the print button gives the following text at the console:
1 Here is the text:
Ok, now I am here, and allowed to enter text. You are allowed tc
enter text here, if you input the correct password.
V
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
public class TextApplet extends JApplet {
private static final String defaultText =
"You are allowed to enter text here, if you input the correct password.";
private JTextField usemameField = new JTextField(15);
private JPasswordField passwordField = new JPasswordField(15);
private JTextArea textArea = new JTextArea(10, 20);
private JButton printButton = new JButton("Print");
public void init() {
Container guiContainer = getContentPane();
guiContainer.setLayout(new BorderLayout(5, 5)); // gaps between the panels
guiContainer.add(new LoginPanel(), BorderLayout.NORTH);
guiContainer.add(new TextAreaPanel(), BorderLayout.CENTER);
guiContainer.add(new Button Panel(), BorderLayout.SOUTH);
usernameField.requestFocus();
}
/* Describes northern panel */
private class LoginPanel extends JPanel {
public LoginPanel() {
setLayout(new GridLayout(2, 2, 5, 5));
add(new JLabel("Username:", JLabel. RIGHT));
add(usernameField);
addjnew JLabel("Password:", JLabel.RIGHT));
add(passwordField);
PasswordListener thePasswordListener = new PasswordListener();
passwordField.addFocusListener(thePasswordListener);
r
* The objects of this class listen for changes in focus.
*
* The program reacts after the user has left the password field.
* Username and password are checked. If ok, focus is moved to the text area,
* and the user is allowed to edit the text. If not ok, focus is moved
* to the usemame field, and the user may re-enter username and password.
*/
private class PasswordListener implements FocusListener {
public void focusLost(FocusEvent event) {
String user = usernameField.getText();
char[] password = passwordField.getPasswordQ;
if (okPassword(user, password)) {
showStatus("Ok. You may edit the text.");
printButton.setEnabled(true);
textArea.setEditable(true);
textArea.requestFocus();
} else {
showStatus("Username/password not valid.");
printButton.setEnabled(false);
textArea.setEditable(false);
usernameField.requestFocusQ;
First, the init ( ) method is performed. After the three panels are laid out in order,
we make sure that the field where the username will be entered gets the focus.
usemameField.requestFocusQ;
The LoginPanel class is constructed in the same way as the northern panel in
Program Listing 13.8. The PasswordListener class describes a focus listener
(more about this class very soon). We make an instance of this class and link this
to the password field:
PasswordListener thePasswordListener = new PasswordListener();
passwordField.addFocusListener(thePasswordListener);
The TextAreaPanel class makes use of the following methods that are
particular to the JText Area class.
The messages setLineWrap (true) and setWrapStyleWord (true)
take care of automatic carriage returns and make sure that words are not broken
between lines when text is entered into the large text field in the middle of the
window. The text field is locked to input until the user has entered a correct
username and password:
textArea.setEditable(false);
If the text is long, we might want a scroll bar on the sides so that the user easily can
move forwards and backwards in the text. In order to accomplish this, we need to
put the text area into an instance of the JScroll Pane class:
JScrollPane scrollPane = new JScrollPane(textArea);
It is this object and not the text object that is placed in the container:
add(scrollPane);
The southernmost panel, the ButtonPanel class, adds a listener for the button:
ButtonListener theButtonListener = new ButtonListener();
printButton.addActionListener(theButlonListener);
We disable the button until later: printButton.setEnabled (false) ;
We have also created a keyboard alternative for the button:
14.1 Text Components and Focus Listeners
printButton.setMnemonic('P');
After the panel classes, there are two inner classes that describe listeners.
The first one is the PasswordListener class: An instance of this class is
registered as a listener to passwordField. A listener of this type has to handle
the messages focusLost ( ) and focusGained ( ) (the contents of the
FocusListener interface). In our case, the focusGained () method is not
of any interest. However, we have to program all the methods in the interface, and
therefore the focusGained () method will be empty. The focusLost ( )
method takes care of checking the password. The getPassword ( ) method
returns the password as an array of char. There are security reasons for the
method not returning a String object. An array of char can be "zeroed" after
the password has been checked. We can't "zero" a String object, since an object
of this type is immutable. Our program is not especially secure anyway, because the
password is sitting in clear text in the source code.
To check the username and password, we have written the okPassword {}
method. Notice that we are using two class methods from the
java.util.Arrays class (Section 9.6).
If the username and password are correct, the following happens:
Figure 14.3 shows how messages are sent to the different GUI components to
have the tasks carried out. Out of space considerations, we have left out the dotted
arrows that show returns from method calls. In professional contexts, it's actually
more common to leave the dotted return arrows out than to include them.
If the username and password are not right, the following occurs:
The disablings are set "for security's sake". Theoretically, after having edited the
text field, we can go back and enter the username and password again (and do it
wrong this time!). It's better to set a block for too many things than for too few.
The second inner class is the ButtonListener class. This contains little new.
If the user presses the button, the text is printed to the window in the console.
14 Text, Choices, and Windows
userriame password
textArea
Field Field
enter "test"!
W;
shift focus
enter "test'i
shift focus i
j focusLost(>
i ; ; okPassword() ;
i i = 1 '
\ i i setEnabted(true)
; jsetEditabte(true);
j ; requestFocusQ
edit the text
; ^
API Reference
Methods:
public void setLineWrap(boolean autoNewLine)
As default, the text is printed without automatic new lines. This is seldom desirable.
Use this method with an argument set to true to get automatic new lines.
public void setWrapStyleWord(boolean wholeWords)
If automatic new lines is turned on, the lines can be broken in the middle of a word
if no message to the contrary is given. Use this method with the argument set to
true to avoid words being split.
14 Text. Choices, and Windows
Figure 14.4 Check boxes and radio buttons from SwingSet2,1 list from Program Listing
14.4
Class names for sources and listeners are given in table 14.1. We can make more
types of listeners than are included in the table.
Table 14.1 GUI components for choices (there are more types of listeners than those listed
here.)
[^JToggleButton
Figure 14.5 GUI components for choices: JList, JCheckBox, and JRadioButton
(UML)
Both check boxes and radio buttons generate Action Events. This is the same type
of event we are familiar with from the pushbutton examples earlier. A listener
object therefore has to be an instance of a class which implements the
ActionListener interface (in other words, the actionPerformed ( )
method we know so well).
A list generates a ListSelectionEvent, which we will come back to in our
discussion of lists.
The class tree is shown in Figure 14.5.
import java.awt.event.*;
import javax.swing.*;
import javax.swing. border.*;
public class CheckboxApplet extends JApplet {
private JCheckBox dinner = new JCheckBox("Dinner");
private JCheckBox lunch = new JCheckBox("Lunch");
public void init() {
Container guiContainer = getContentPaneQ;
/*
* To make the group box around the checkboxes visible,
* we have to put one empty panel in north and one in south.
V
guiContainer.add(new JPanelQ, BorderLayout.NORTH);
guiContainer.add(new JPanelQ, BorderLayout.SOUTH);
SelectionPanel middle = new Selection Panel();
guiContainer.add(middle, BorderLayout.CENTER);
}
/* Describes the panel with the checkboxes */
private class SelectionPanel extends JPanel {
public SelectionPanelQ {
add(dinner);
add(lunch);
CheckBoxListener listener = new CheckBoxListener();
dinner.addActionListener(listener);
lunch. addActionListener(listener);
/* We make a group box by surrounding the boxes with a border, or more correctly:
make a border around the panel which contains the check boxes */
SoftBevel Border border = new SoftBevelBorder(BevelBorder.RAISED);
Border groupBox = BorderFactory.createTitledBorder(border, "Meals");
setBorder(groupBox);
API Reference
Methods:
Problems
Expand the program above as follows:
1. Make a new check box for breakfast.
2. Let the printout appear in the text area under the group box, instead of on the
console.
radio buttons are mutually dependent on each other. Like the preset radio buttons
in old cars, there can never be more than one button pressed in at a time, hence the
name radio buttons.
Radio buttons that go together are linked to an instance of the ButtonGroup
class. To get the buttons into a visible group box, you have to use "borders", as
described for checkboxes.
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class RadioButtonApplet extends JApplet {
private JRadioButton female = new JRadioButton("Female", true);
private JRadioButton male = new JRadioButton("Male", false);
public void init() {
Container guiContainer = getContentPaneQ;
/* The container is constructed in the same way as in the CheckBoxApplet */
guiContainer.add(new JPanelQ, BorderLayout.NORTH); // a little space
guiContainer.add(new JPanel(), BorderLayout.SOUTH); // a little space
SelectionPanel middle = new SelectionPanel();
guiContainer.add(middle, BorderLayout.CENTER);
}
/* Describes the panel with the radio buttons */
private class SelectionPanel extends JPanel {
public SelectionPanel() {
ButtonGroup group = new BurtonGroup();
group.add(female);
group.add(male);
14 Text Choices, and Windows
add(female);
add(male);
RadioButtonListener listener = new RadioButtonListener();
female.addActionListener(listener);
male.addActionListener(listener);
/* We make a group box by surrounding the boxes with a border, or more correctly:
make a border around the panel which contains the check boxes V
SoftBevelBorder border = new SoftBevelBorder(BevelBorder.RAISED);
Border groupBox = BorderFactory.createTitledBorder(border, "Sex");
setBorder(groupBox);
/* Describes listeners, which fires every change in the radio button group V
private class RadioButtonListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
String sex = event.getActionCommand();
if (sex.equals("Female")) System.out.println("Female is selected");
else System.out.println("Male is selected");
API Reference
Method:
public void add(AbstractButton button)
This method links a button to the group.
14.5 Choices Using Lists
Problems
Change the program from before as follows:
1. The middle panel will contain a group box with the title "Type of Residence".
This group box will be in addition to "Sex", and it will contain radio buttons for
apartment, condo, townhouse, and house. Handle the selections the same way
you did for "Sex".
2. We assume that the changes in problem 1 have not been made. Add a
pushbutton in the bottom panel. Move the handling of the choice from the radio
buttons to this pushbutton. When the user pushes the pushbutton, the choice
will be written to the console.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
14.5 Choices Using Lists
API Reference
This method adds a listener that is alerted every time there is a change in selections,
public void setSelectionMode(int selectionMode)
This method decides which type of selections the user will be able to make. The
argument should be SINGLE_SELECTION, SINGLE_INTERVAL_SELEC-
TION, or MULTIPLE_INTERVAL_SELECTION. All of them have to be
qualified by the ListSelectionModel interface name. The last alternative
applies if we don't state anything else.
public void clearSelection()
This method removes the selections that were made. The message
valueChanged () is sent to all registered ListSelection listeners.
public int getSelectedlndexQ
This method gets the index for the selection that was made. If several selections
were made, it gets the index for the first one. If no selection was made, the method
returns -1.
public int[] getSelectedlndicesQ
This method returns an array with indices for the selections that were made. The
indices are in ascending order.
public Object getSelectedValue()
This method returns a reference to the selection that was made. If no selection was
made, null is returned.
public Object[] getSelectedValuesQ
This method returns an array of references to the selections that were made.
public boolean isSelectedlndex(int index)
This method returns true if the line with the stated index was selected.
public boolean isSelectionEmpty()
This method returns true if no selection was made.
public void setSelectedlndex(int index)
public void setSelectedlndices(int[] indices)
These methods make it possible to set one or more selections,
public void setSelectedValue(Object selected, boolean scroll)
This method makes it possible to set a specific object as selected. The last argument
is set to true if the list will scroll, so that the selection comes into view.
public boolean getValuelsAdjusting()
Every selection sends several valueChanged () messages to the listener object.
If it's important for us to handle only one of them, we can use this method. It
14.5 Choices Using Lists
returns true for all messages, except the last one in a selection. For usage example,
see Program Listing 14.5.
The javax. swing .event. ListSelectionListener interface
Method:
public void valueChanged(ListSelectionEvent event)
This message is sent to listener objects when selections are made in the list. The
selection can be made by the user or, for example, using the
setSelectedlndex () method.
The javax.swing.eventListSelectionEvent class
The argument to the valueChanged () method is an instance of this class. The
class inherits the getSource () method from the EventObject class. The
class itself has no methods that are of interest to us.
Now we will see how we can add and remove elements to and from the list.
We have to make changes in what Swing calls the "model" for the list. The word
"model" is used here in a somewhat specialized sense. Pure and simple, it refers to
the data contents of the list. The word writes itself from a theoretical architecture
for user interfaces called the Model-View-Controller architecture (MVC):
View: That same data can be displayed in different ways. Therefore, we can have
several views for the same model.
Controller: The controller decides how the GUI component will handle the
events that occur.
In Swing, View and Controller stick close together. The controller part is in the
listener classes.
We recognize again the same point that we emphasized earlier: It's important to
distinguish the classes that describe the problem area we are dealing with (for
example, wallpaper, paint, renovation) from classes that have to do with the user
interface. This makes it easy to change the user interface, something we have seen
an example of in the renovation project, among other things.
As mentioned, in Swing this principle applies to the user interface itself. For
example, there are many types of buttons: pushbuttons, check boxes, and radio
buttons. All of them have the same data content, but they look different on the
screen. The data content is a boolean value that tells whether or not the button is
selected.
14 Text, Choices, and Windows
We don't normally need to think about the division between data and the
presentation of the GUI components we go through in this book. The exception is
if we're going to change the contents of a list. Then we have to work with the class
that represents the "model", namely the DefaultListModel class. The
methods for handling the individual elements in the list are about the same as for
handling the elements in an array list.
Figure 14.9 and Program Listing 14.5 show an example. The list consists only of
the selection "New name" when it starts. If the user clicks on this choice, a little
dialog box comes up to enter the name in. After the user has written the name and
pressed the OK key, the name shows up in the list. If the user clicks on a name, this
name will be deleted. The message box on the right comes up.3
V
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class ListApplet2 extends JApplet {
private DefaultListModel data = new DefaultListModelQ;
private JList list = new JList(data);
3. The alert "Warning: Applet Window" appears at the bottom of the dialogs. This alert appears if an
applet presents a dialog. This is a reminder to the user that the data she enters will be handled by an
applet, which is usually downloaded from a "foreign" machine.
14 Text. Choices, and Windows
In order to be able to change the contents of the list, we have to make the list based
on the model:
DefaultListModel data = new DefaultListModel();
JList list = new JList(data);
We manipulate the contents of the list by sending messages to the data object:
data.addElement("New name");
data.remove(selection); // selection is the index of the element which will be removed
The following loop prints the contents of the list to the console:
for (int i = 0; i < data.sizeQ; i++) {
System.out.println(data.get(i));
}
This can be useful in debugging.
API Reference
Methods:
These methods correspond to methods with the same signatures in the class
java .util .ArrayList; see Section 10.2.
Problem
The populations of the urban areas in Program Listing 14.4 are as follows:4 Tokyo
28 million, New York City - 20.1 million, Mexico City - 18.1 million, Mumbai -
18 million, Sao Paulo - 17.7 million, Los Angeles - 15.8 million, Shanghai - 14.2
million, Lagos - 13.5 million, Calcutta - 12.9 million, Buenos Aires - 12.5 million.
1. Change the program so that only one city can be selected. The selection will lead
to a dialog box that comes up with population information.
2. We are assuming you've done problem 1. Change the program so that the user
can add more cities and populations.
14.6 Windows
Figure 14.10 shows different types of windows.
A primary window is also called a top-level window. The user's "main window" for
the program will be a primary window. However, there's no reason why an
application should not have many primary windows. The frame around the
primary window always conforms to the platform the program is running on.
What's inside the frame, however, conforms with the "Look and Feel" we have
selected (see Section 13.1). If we are running on a Windows platform, the frame
looks like the one in the figure. A primary window in Windows has a title line
and buttons for minimizing, maximizing, and closing the window. In Swing, a
primary window belongs to the JFrame class.
A secondary window is also shown with a frame that conforms to the platform the
program is running on. A dialog box is an example of a secondary window. A
dialog is an instance of the JDialog class. A secondary window is normally
linked to a parent window. The exception can be in test programs and our use
of the JOptionPane class. The parent window can be a primary window or
another secondary window. If the parent window is closed, all the "child
windows" will also be closed.
We have already made dialogs without parent windows by using the class
methods in the JOptionPane class. The class methods in JOptionPane
hide the JDialog objects to us.
4. According to http://geography.miningco.com/library/weekly/aa072897.htm
14 Text, Choices, and Windows
Internal windows are windows that have to be entirely inside other windows. If
necessary they are clipped when displayed. They belong to the
JInternalFrame class, and have to be used if we are going to make what
are called MDI applications in Windows. MDI stands for Multiple Document
Interface. We have several windows inside a main window. Every window
displays a document. Most word processors and editors are MDI applications.
The opposite of MDI is SDI (Single Document Interface). An SDI application can
only display one document at a time. Windows Notepad is an example of an SDI
application.
We can create plain windows (windows without frames) with the JWindow
class.
Up to this point, we have created applets. The window where we put our GUI
components belonged to the browser. We will now see how we can make
applications with their own primary windows. In the next chapter, we will create
specially adapted dialog windows. We don't cover internal windows in this book.
We also don't create plain windows based on the JWindow class.
Figure 14.11 shows the window classes in the class tree.
5. You'll find the example that shows internal windows by going into the JInternalFrame class in
the online API documentation.
14.7 Making a Window
Window Panel
Figure 14.11 The class tree for the window classes (UML)
Situations like this are common. Therefore, an "adapter class" was created where all
the methods in the WindowListener interface are implemented as empty
methods. We find the WindowAdapter class in the java.awt.event
package:
package java.awt.event;
public abstract class WindowAdapter implements WindowListener {
public void windowOpened(WindowEvent event) {}
public void windowClosing(WindowEvent event) {}
public void windowClosed(WindowEvent event) {}
public void windowlconified(WindowEvent event) {}
public void windowDeiconified(WindowEvent event) {}
public void windowActivated(WindowEvent event) {}
public void windowDeactivated(WindowEvent event) {}
}
Instead of letting our My WindowListener class implement the Window-
Listener interface, we let it be a subclass of the WindowAdapter class. Then
the class will inherit all the empty methods. It can make its own versions of the
methods that will have contents:
private class MyWindowListener extends WindowAdapter {
public void windowClosing(WindowEvent event) {
....Here we may write to data files, etc .....
System. exit(0); // Remember this!
Adapter classes have been made for all the listener interfaces in the
java.awt.event package that contain more than one method.
A little example application is shown in Program Listing 14.6. Try it! Instead of
saving data to a file, we print a little text to the console window. As you see, the GUI
is composed in the JFrame2 constructor. In the next section we are going to take
a closer look at the differences between applets and applications.
import javax.swing.*;
import java.awt.event.*;
class JFrame2 extends JFrame {
public JFrame2() {
Container guiContainer = getContentPane();
guiContainer.setLayout(newFlowLayout());
guiContainer.add(new JLabel("This window handles closing. Close the window!"));
addWindowListener(new MyWindowListener());
}
private class MyWindowListener extends WindowAdapter {
public void windowClosing(WindowEvent event) {
System.out.println("Here we may write to data files, etc.");
System.exit(0); // Remember this!
class TestJFrame2 {
public static void main(String[] args) {
JFrame mySecondWindow = new JFrame2();
mySecondWindow.setTitle("My Second Window");
mySecondWindow.setSize(400, 100);
mySecondWindow.setVisible(true);
API Reference
Figure 14.11 shows the relationship between the classes described in this API
reference. Remember the inheritance of members!
The javax.swing. JFrame class
Constructors:
public JFrame()
public JFrame(String title)
To start with, the window is invisible.
Methods:
public Container getContentPane()
This method returns a container that can be filled with GUI components.
public void setDefaultCloseOperation(int operation)
This method determines what will happen when the user closes the window by
pressing on the close button in the upper right corner. The default is for the window
14.7 Making a Window
Problems
1. Which listener interfaces have we gone through up to this point? Which one of
these, in addition to WindowListener, has an ancillary adapter class?
Change one of the earlier examples so that you try this adapter class.
2. Create JFrame3 as a subclass of JFrame. The constructor for JFrame3 will
take the size and location of the window as arguments, in addition to the
window's title line. Write a little program that tests the new class.
3. You find out that JFrame3 can be useful in many contexts. Make the changes
that are necessary so that you can put the class into myLibrary.
An applet must be a public class. The most practical thing to do when we make
applications is not to let any of the classes be public. This limits the use of the
classes to the package where they are declared, but usually that's fine. If classes
are going to have uses beyond this, they should be placed in a named package.
In the applet, the construction of the user interface is in the init () method.
In the application, it's in the constructor.
The browser (or applet viewer) takes care of starting the applet. To start an app-
lication, we have to program main (). In the example, main () contains four
statements:
figure 14.2
class TestColorButtonApplication {
public static void main(String[] args) {
ColorButtonApplication myWindow
= new ColorButtonApplicationfMy Window");
14 Text. Choices, and Windows
myWindow. pack();
myWindow.setVisible(true);
myWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Problem
Change the program in Program Listing 14.4 into an application with a primary
window.
The class that describes the applet implements Act ionListener on its own.
In this way the applet itself becomes the listener, and it is registered as a listener
object:
myButton.addActionListener(this);
An anonymous class
We often have only one listener per object, but there's also nothing wrong with
making one listener for each object that will be listened to. In that case, it's not
unusual to let the listener be an instance of an anonymous class. An anonymous class
is a class without a name. Study the source code below and Figure 14.14.
public class ColorButtonAppletAnonym extends JApplet {
private Container guiContainer;
public void init() {
guiContainer = getContentPane();
guiContainer.setLayout(new FlowLayout());
JButton myButton = new JButton("Push here!!");
guiContainer.add(myButton);
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
guiContainer.setBackground(Color.red);
myButton.addActionListene^iewActIonLIstener()i
public void actionPerformed(ActionEvent event) {
guiBeholder.setBackground(Color.red);
adapter class Among other things, used of classes that implement all the methods in a listener interface as
empty methods.
anonymous class A class without a name. There can't be more than one instance of the class. This instance is
also without a name. Anonymous classes are especially used in connection with registering
listener objects.
check box See Figure 14.4. A check box is an object of the JCheckBox class. None, one, or several of
the check boxes shown can be pressed in at a time. The boxes can be collected in a group
box, but they don't need to be.
group box A border around a collection of GUI components. In Java, the components usually are
collected in a panel. To make the border we use the classes in the package
javax. swing. border. A group box often has a name.
internal window Internal windows (class JInternalFrame) are windows that have to be entirely inside
other windows. If necessary they are clipped when displayed.
list (GUI) In Figure 14.8, the cities are displayed underneath each other in a list. The list is a GUI
component that allows the user to select one or more alternatives. It is an instance of the
class JList.
MDI Multiple Document Interface. Window's own name for a user interface that consists of a
primary window with many internal windows.
model "Model" classes in Swing describe the data content behind a GUI component.
MVC Model-View-Controller. A theoretical architecture for programming user interfaces. For our
purposes, it's sufficient to recognize the principle behind it. The principle is to distinguish
between how a GUI component looks (view) and the data content of the component
(model). The controller portion will be in the listener classes.
primary window An application window with a title line and buttons for minimizing, maximizing, and
closing the window. The window is programmed as an instance of the class JFrame.
radio button See Figure 14.4. A radio button is an instance of the JRadioButton class. The buttons have
to be collected in an instance of the ButtonGroup class. The buttons can but don't have to
be in a group box. Only one of the buttons in a group of radio buttons can be "pressed in" at
a time.
scroll bar See Figure 14.8. The list has a scroll bar on the right-hand side. The user can see the whole
list by clicking on the up and down arrows and the field in between. A scroll bar can also be
horizontal. We expand a GUI component with a scroll bar by inserting it into an instance of
the class JScrollPane.
SDI Single Document Interface. Windows' own name for a user interface that doesn't use
internal windows.
14.11 Review Problems
secondary- A window that normally has another window as a "parent" (for example, a dialog box). If
window the parent is closed, the secondary window is also closed. A dialog box is programmed as an
instance of the JDialog class. A number of standard dialogs can be made using class
methods in the class JOptionPane.
be most elegant if the colors (and the buttons, too) are in an array. Because of the
drawing, it may be difficult to get pack ( ) to work. Use setSize ( ) to set the
size of the window.
When you've accomplished this, you will make a list of all the colors. The user
will choose whether she wants to use the radio buttons or the list. Test whether you
can synchronize the choices so that if the user chooses "red" on the list, the radio
button marked "red" is also selected.
Problem 2
Make an applet to convert your own currency into several other currencies. Let the
user choose a currency from a list. The user will also be able to expand the list by
adding new currencies. Use the standard dialogs to communicate with the user.
Problem 3
Change the program in Program Listing 14.1 into an application. The text will be
read from a file. If the user has permission to change the text, the modified text will
be saved into the file when the user presses "Print". Try to distinguish the classes
that handle the file as much as possible from the user interface classes.
Problem 4
Make a user interface for maintaining two lists, one list with groups, the other with
persons. Every person can exist in several groups (for example, "member of the
soccer team" and "member of the basket ball team").
The most important part of the user interface is two lists:
List A will show the groups. The user will be able to choose a group in this box.
If the user hasn't chosen a group, the group "All" will be selected.
At all times, list B will display the contents of the group (the persons) that is
selected in box A.
Button 2 will make it possible to add a new group. The user will choose which
members the group will have by selecting all the applicable names from list B.
The user interface will consist of only one window. New groups and new persons
will be input by using methods in JOptionPane.
It's sufficient that the data be stored in the list's "models".
Learning goals for this chapter
After completing this chapter, you will be able to:
Make modal dialog windows that edit data that belongs in the parent window
Now we've covered the most common GUI components and also studied the most
common event types.
This chapter contains several techniques that will make it possible to create
"real" graphical user interfaces for a program.
The chapter will end with the last version of the renovation case. We'll replace
the user interface from chapter 12 with a proper GUI.
You will get a deeper understanding of the point of differentiating between
classes that have to do with the problem we're going to solve and classes that
communicate with the user. You'll know how these two groups' objects are
connected,
15.1 Menus
We can create many different types of menus in Java Swing. Look up the JMenu
class in the online API documentation and click on "How to use menus." Menus
can have submenus. A single menu item can contain an icon in addition to or
instead of a text. It can also consist of a radio button or a check box with
accompanying text. We distinguish between dropdown menus and pop-up menus.
A simple dropdown menu is shown in Figure 15.1. A pop-up menu is a menu that
appears when the user, for example, right clicks with the mouse.
15 Creating User Interfaces
JMenu ______________________
\BPPHPVHiPIHHiM|
-JMenuBar
[ VMMM
I RM
JMenultem
Program listing 15.1 shows the source code that makes the window with the Color
menu. Clicking on one of the menu entries changes the color of the window.
We have to use three Swing classes (see Figure 15.2) in order to make a menu:
1. Every single dropdown menu is an instance of the JMenu class:
JMenu theMenu = new JMenu("Color");
2. Every single menu item is an instance of the JMenuItem class. These instances
are linked to the right menu using add ():
JMenultem menultem = new JMenultem("Yellow");
theMenu.add(menultem);
3. The menu bar is an instance of the JMenuBar class. Every single menu has to
be linked to this instance:
JMenuBar menuBar = newJMenuBar();
menuBar.add(theMenu);
Finally, the menu bar has to be linked to the window:
setJMenuBar(menuBar);
Notice that we send the message set JMenuBar ( ) to the window and not to
guiContainer. The set JMenuBar ( ) method is declared in the JFrame
class. The method is also declared in the JDialog class. Therefore, we can make
menus in both primary and secondary windows.
We have to create an object that can listen for the user's menu choice. The event
that occurs with the choice is an ActionEvent, and the message that is sent is
actionPerformed ( ). This is familiar from beforerefer to the program listing
for further details on the listener class.
15.1 Menus
*/
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class WindowWithMenu extends JFrame {
private Container guiContainer;
public WindowWithMenu( ) {
setTitle("MenuTest");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
guiContainer = getContentPane( );
Menu Listener theListener = new MenuListener( );
JMenu theMenu = new JMenu("Color");
JMenultem menultem = new JMenultemfYellow");
theMenu.add(menultem);
menultem. addActionListener(theListener);
menultem = new JMenu ltem(" Red");
theMenu.add(menultem);
menultem. addActionListener(theListener);
menultem = new JMenultem("Blue");
theMenu.add(menultem);
menu Item. addActionListener(theListener);
JMenuBar menuBar = new JMenuBar( );
menuBar.add(theMenu);
setJMenuBar(menuBar);
}
private class MenuListener implements Action Listener {
public void actionPerformed(ActionEvent event) {
String command = event.getActionCommand( );
if (command.equals("Yellow")) guiContainer.setBackground(Color.yellow);
else if (command. equals("Red")) guiContainer.setBackground(Color.red);
else guiContainer.setBackground(Color.blue);
class MenuTest {
public static void main(String[] args) {
WindowWithMenu window = new WindowWithMenu( );
window.setSize(300, 200); // pack() gives a very little window!
window.setVisible(true);
15 Creating User Interfaces
JMenuttem J Button
Figure 15.2 An excerpt from the class tree with classes for menus and toolbars (UML)
API Reference
Constructor:
public JMenuBar( )
Method:
public JMenu add(JMenu newMeny)
This method adds a new dropdown menu to the menu bar.
Constructor:
public JMenu(String text)
Methods:
public JMenultem add(JMenultem menultem)
public JMenultem add(String text)
These methods add a new menu item to the menu. The latter method generates an
instance of the JMenuItem class and is actually a shortened form for creating new
menu entries.
public void addSeparator( )
This method adds a line as a division in the menu.
The javax.swing.JMenultem class
This class manages an item in a menu.
Constructors:
public JMenultem(lcon icon)
public JMenultem(String text)
public JMenultem(String text, Icon icon)
public JMenultem(String text, int mnemonic)
A menu item can consist of a text or an icon, or both. We can also add a mnemonic
to go along with the menu choice. In the menu, the mnemonic character will be
underlined.
The class is a subclass of the AbstractButton class and inherits all the
methods from this class (see Sections 13.2 and 14.3).
The java.awt.Frame class
Method:
public void setMenuBar(MenuBar menubar)
This method positions the menu bar in the window.
See Section 14.7 for more methods in the Frame class.
Problems
1. Modify Program Listing 15.1 so that all the standard colors are shown. With so
many choices, it's practical to use arrays to make the menu and handle the
selections.
2. Expand Program Listing 15.1 with a dropdown "Help" menu. The menu will
have two entries: "Help" and "About the program". The first item will print out
15 Creating User Interfaces
a message about what the program does, and the second will print out the date
and author.
15.2 Toolbars
Figure 15.3 and Program Listing 15.2 show the same example as above, but now
the menu is replaced by a row of buttons, a so-called toolbar.
JButton JToolBar
class ToolbarTest {
public static void main(String[] args) {
WindowWithToolbar window = new WindowWithToolbar( );
window.setSize(300, 200);
window.setVisible(true);
guiContainer.add(toolbar, BorderLayout.NORTH);
And then we should not forget to register a listener for the buttons:
ButtonListener theListener = newButtonListener();
yellowButton.addActionListener(theListener);
We let the same object listen for all the buttons. The actionPerformed( )
method handles the event and sets the right background color.
Here we've used get Source ( ) instead of getActionCommand ( ) to find
the source of the event. The reason for this is that we only have an image on the
buttons, and not a text which we need when we use getActionCommand ( ).
(Alternatively, we could have set this text by sending the message
setActionCommand ( ) to the buttons.)
It's usually safer to use getSource ( ) than getActionCommand ( ). But
it's a little more labor-intensive and maybe a little more difficult to understand. The
reason that getSource ( ) is preferable is that it requires that we compare
variable names and not strings. We write
if (button == yellowButton)...
and not
if (source.equals("yellow"))...
If we write the variable name yellowButton wrong, we get an error message
from the compiler. We don't get any message if we write "yellow" differently
here than when we defined the button. A good solution if we prefer to use
getActionCommand ( ) is to store all the pertinent strings in an array. Then we
avoid the inconsistency problem (cf. naming constants, Section 2.5).
Notice that a menu bar is placed directly in the window (setMenuBar ( )), while
a toolbar is placed in the GUI container ("content pane") the same way that other
GUI components are, using the add ( ) method.
API Reference
Method:
public void setFloatable(boolean floats)
15.3 Dialog Windows
The default is for a toolbar to "float", in other words, the user can move it. It then
becomes a window like the one shown at the bottom of Figure 15.3.
public void addSeparator( )
This method adds a separator to the toolbar.
This class is a subclass of the JComponent class and inherits, among other
things, the add ( ) method from there.
Problems
Make the following changes to Program Listing 15.2:
1. Test the addSeparator ( ) method. What does the separator between the
buttons look like?
2. Link tool tips to each individual button. Use the online API documentation to
find out how to do that.
3. Replace the icons with texts and mnemonics.
/ *
The new name is entered The name is edited, and the result
and sent to the primary window / is sent to the primary window
Figure 15.4 A parent window with dialogs for changing data in a database
15 Creating User Interfaces
We're already familiar with the standard dialogs in the JOPtionPane class.
These are well suited for short messages and user responses to an individual
question.
We make dialog windows in much the same way that we make other windows.
An important difference that we have to keep in mind, however, is the
communication with the parent window. The parent window controls when the
dialog window is shown. Once the user has entered his data and closes the window,
the data usually has to be sent back to the parent window. Figure 15.4 shows a
parent window with a name registry. The user can maintain the name registry by
pressing one of the buttons. The "New" command results in a dialog box with no
data coming up on the screen so that the name of a new person can be entered. The
"Edit" command displays the selected name so that the user can modify it. In the
last part of this section, we'll program and test the little name dialog while
postponing programming the parent window until chapter 20, where we'll connect
this user interface to a database.
The most basic dialog window
The most basic situation of all is shown in Figure 15.5. The parent window comes
up with a push button. The user presses this and the little dialog window is shown.
The user presses the OK button and the dialog window disappears.
15.3 Dialog Windows
The source code is shown in Program Listing 15.3. Many classes are involved.
We'll start at the bottom of the source code:
The MiniDialog class, like all dialog windows, is a subclass of the JDialog
class. It describes the dialog box with two pushbuttons and an inner listener
class.
2 push
3 actionPerfomeid()
4 showDia loo()
setVisible true)
5
push ^ j ^
6 action Perforrjj Bd()
7
se> Visible(false)
8 i
9
println( OK pressed,..")
10 \e*"
no rtman*B the message
setVisiW<fatse) is sent to
the dialog box
Figure 15.6 The Course of Events from the Displaying of the Parent Window on the Screen
until the Printout Appears on the Console (UML)
We'll go through the source code details by looking at what happens if the user runs
the program and presses the OK button. Follow along with the sequence diagram
in Figure 15.6 as well (the numbers below refer to the numbers on the left of the
figure):
15 Creating User Interfaces
class TestMiniDialog {
static public void main(StringQ args) {
ParentWindow parentWindow = new ParentWindow();
parentWindow.setSize(300, 200);
parentWindow.setVisible(true);
The boolean variable ok keeps track of whether the data the user has entered
should be saved or should be ignored. The variable has both a set and get
method to be used in subclasses.
The class has a method called okData ( ). It returns true. It's not very exciting,
but the point of the method is that subclasses that require control of the input data
can create their own version. If the data is not all right, focus is typically shifted to
the input field where the error occurred. We will see examples of this later in this
chapter.
The constructor calls the superclass's constructor. Then a window listener is
registered. As opposed to Program Listing 15.3, here we have to manage closing the
window. What does the user mean when she wants to close the window? Does she
mean OK or Cancel? If she means OK, the data has to be checked with the
okData ( ) method. Let's look at the WindowsClosingListener class:
If the user tries to close the window by pressing the x in the upper right corner,
a Yes/No box comes up: "Do you want input data to be saved?". If the user says
"Yes," the window is only closed if the okData ( ) method returns true. Hence,
we control the window's closing ourselves. We do this by sending the message
setDefaultCloseOperation( ) to the window with DO_NOTHING__ON
_CLOSE as its argument.
The panel contains two buttons. A listener object is linked to the buttons. If the
OK button is pressed, the validity of the data is checked using the okData ( )
method. If this method returns true, the variable ok is set equal to true. In all
other cases, it is set to equal false. Then the dialog window is closed and the
program control goes back to the parent window (see the CommandListener
class).
Acceleration keys are linked to the buttons. These are not the same as the
mnemonics we looked at earlier. A mnemonic is an underlined letter in the
command. To issue the command, the user presses the letter together with the Alt
key. It's unusual to use mnemonics in conjunction with OK and Cancel keys. It is,
however, common for OK to be associated with the Enter key and for Cancel to be
associated with the Escape key. We've programmed the dialog so that the OK key
has to have the focus for the Enter key to work. The Escape key, on the other hand,
works whether the Cancel key has the focus or not.
We won't go into the details of defining acceleration keyswe'll just take a quick
look at the source code for this example:
Keystroke escapeKey = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
cancelButton.registerKeyboardAction(buttonListener, "Cancel", escapeKey,
JComponent.WHEN_IN_FOCUSED_WINDOW);
15 Creating User Interlaces
First we have to instantiate an object that describes the acceleration key. This object
is from the javax. swing. Keystroke class. The names of the different keys
(for example, VK_ESCAPE) are defined in the java . awt. event. KeyEvent
class. The other argument for get Keystroke ( ) can be a button that is pressed
together with the first one, for example InputEvent. SHIFT_MASK or
InputEvent.ALT_MASK.
Then we send the message registerKeyboardAct ion ( ) to the button. In
order, we send the following as arguments: the listener object, the command linked
to the button, the acceleration key, and finally the condition for this key to work.
For the Enter key, we used WHEN_FOCUSED, for the Cancel key,
WHEN_IN_FOCUSED_WINDOW. For further documentation of classes and
methods involved in this process, refer to the online API documentation.
"Do you want input data to be saved? ", "Closing the Dialog"
JOptionPane.YES_NO_OPTION);
if (answer == JOptionPane.YES_OPTION) {
if (okData()) { // closing requires ok data
ok = true;
setVisible(false);
}
} else { // the window is closed without saving
ok = false;
setVisible(false);
Data is transferred from the parent window to the dialog and back.
Starting with the latter of those two: it's most practical to have the data that will
be sent back and forth in an object. Usually we create a dialog for each class in the
problem area we're dealing with (for example, person, account, loan, etc.). Then we
already have the classes in place. In this example, we need the Person class, which
is shown first in the program listing.
Let's look at the PersonDialog class. The constructor takes the parent
window as its parameter and sends this on to the superclass with the title of the
dialog:
super(parent, "Person");
Then we position the components throughout the window. We put the
buttonpanel at the bottom.
The showDialog ( ) method is now relatively comprehensive. It takes a
person object as its argument. The data in this object is presented in the dialog. The
user can choose to change this data. The dialog doesn't have its own ok variable,
but maintains the one that belongs to the MyDialog class.
Just as before, the program control is waiting in the setVisible (true)
method. It will wait until setVisible ( f a l s e ) is called. This happens in the
MyDialog class, and the next step is to check the value of ok. If the user pressed
OK, change the data contents for thePerson object:
15.3 Dialog Windows
if (isOk()) {
thePerson.setFirstName(firstNameField.getText());
thePerson.setLastName(lastNameField.getText());
return true;
}
return false;
We want to check that the user enters both a first and a last name, and this check is
placed in the PersonDialog class's own version of the okData () method.
JOptionPane,
this box is displayed if user
clicks the X in the upper
right corner
The parent window is described in the ParentWindow class. There isn't much
new here, aside from the fact that the person object has to be sent with the call for
showDialog () , and it also has to be handled after the call. Here, we'll stick to
printing a text to the console.
Finally, we'll mention that it's possible to find out how a dialog looks without
linking it to a parent window. The following little program shows the name dialog:
static public void main(String[] args) {
PersonDialog test = new PersonDialog(null); // "null" as argument
test.setLocation(500, 500);
test.setVisible(true);
System. exit(0); // remember this when there is no parent window!
* The class is mutable. First name and last name may be changed.
V
package myLibrary;
import java.io.Serializable; // needed in chapter 19
public class Person implements Serializable {
private int persldent;
private String firstName;
private String lastName;
public Person(int initPersldent, String initFirstName, String initLastName) {
persldent = initPersldent;
firstName = initFirstName;
lastName = initLastName;
}
public void setFirstName(String newFirstName) {
firstName = newFirstName;
}
public void setLastName(String newLastName) {
lastName = newLastName;
}
public int getPersldentQ {
return persldent;
}
public String getLastNameQ {
return lastName;
}
public String getFirstName() {
return firstName;
}
public String toString() {
return persldent + ": " + lastName + ", " + firstName;
/*
* PersonDialog.java E.L. 2001-08-23
*
V
package myLibrary;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.text.*;
public class PersonDialog extends MyDialog {
private JTextField persldField = new JTextField(8);
private JTextField firstNameField = new JTextField(15);
private JTextField lastNameField = new JTextField(15);
public PersonDialog(JFrame parent) {
super(parent, "Person");
Container guiContainer = getContentPane();
guiContainer.add(new JPanel(), BorderLayout.NORTH); // a little space
guiContainer.add(new DataPanel(), BorderLayout.CENTER);
guiContainer.add(getButtonPanel(), BorderLayout.SOUTH);
pack();
}
private class DataPanel extends JPanel {
public DataPanel() {
setLayout(new GridLayout(3, 2));
add(new JLabel("Person ident.: ", JLabel. RIGHT));
add(persldField);
persldField.setEditable(false); // the ident. cannot be edited
add(new JLabel("First name: ", JLabel. RIGHT));
add(firstNameField);
addjnew JLabel("Last name: ", JLabel.RIGHT));
add(lastNameField) ;
return true;
/*
* TestPersonDialog.java E.L. 2001-08-23
*
V
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import myLibrary.*; // Person and PersonDialog
class ParentWindow extends J Frame {
private Person aPerson = new Person(100, "Ann", "Brown");
private PersonDialog personDialog = new PersonDialog(this);
private Container guiContainer;
public ParentWindow() {
setTitle("Testing Dialogs");
setDefaultCloseOperation(JFrame.EXIT_ON__CLOSE);
guiContainer = getContentPane();
guiContainer.setLayout(new FlowLayout());
JButton button = new JButton("Push here!");
guiContainer.add(button);
button.addActionListener(newButtonListener());
personDialog. setLocation(550, 550);
}
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
if (personDialog.showDialog(aPerson)) System.out.printin("OK is pressed....");
else System.out.printin("Cancel is pressed....");
System.out.printin(aPerson); // toString() is used
class TestPersonDialog {
static public void main(String[] args) {
ParentWindow test = new ParentWindow();
15.3 Dialog Windows
test.setSize(300, 200);
test.setLocation(500, 500);
test.setVisible(true);
API Reference
Problem
Modify Program Listing 15.3 so that MiniDialog contains a text field the user
can write in. Modify showDialog () so that it returns this text as a string to the
parent window if the user presses the OK button. If the user presses the Cancel
button, the method will return null. The parent window will print the text out
right under the pushbutton.
15 Creating User Interfaces
Figure 15.8 The renovation case: A parent window with dialogs. Only one of the dialogs is
shown at a time.
At the top right of the parent window is a small Help menu. The menu has two
choices: "Help" and "About the Program". Both of the choices print texts in text
boxes.
The toolbar in the parent window offers the following functions:
Combine a surface with a material (only possible if a line in each of the lists is
selected)
Exit
The large list on the left is an instance of the JTable class. It works more or less
like a regular list, but we can set the data up in columns with their own column
headers. We will come back to this type of GUI component later.
Figure 15.9 The parent window divided into cells for use by gridbaglayout
The list on the right is a JList type, which we're familiar with from before.
The total sum is printed out at the bottom: a regular background text followed
by a regular text box.
We'll use the most general of all the layout managers to create the primary
window. The layout manager is called GridBagLayout. It is different from the
other layout managers in that it requires detailed planning. It's not suited for the
trial and error method. There are many parameters and an error in one of them can
yield unpredictable results.
We'll begin by creating an outline of the window. Use pen and paper! Then we
divide the window up into cells using horizontal and vertical lines, such that each
cell contains no more than one component. But a component may well cover
several cells: see Figure 15.9. Notice that columns and rows don't necessarily have
a uniform width.
15 Creating User Interfaces
Based on this figure, we'll set up the requirements for each individual
component. The requirements for one component are stored in an instance of the
GridBagConstraints class. This class has a set of public instance variables that
we assign values to directly, without using set methods. We'll go through these
variables in an API reference.
API Reference
Here we are asking for five pixels in each direction. The order of the arguments for
the Insets constructor is: top, left, bottom, right.
public int anchor
Here, if the component doesn't fill its space completely (see the f i l l variable
above), we tell which direction it should be "anchored" in: CENTER, NORTH,
NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST, or
NORTHWEST. All of these values are class constants in the GridBagCo-
nstraints class.
public double weightx
public double weighty
These are the most difficult variables to assign values to. They are useful if the user
changes the size of the window. Then the size of the components should change in
an equivalent fashion. The variables will have a value between 0.0 and 1.0. The
consequences of the different values are beyond the scope of this book.1 Here, we
use the value 0.5 for both variables. We can also avoid problems by setting it so that
the user cannot change the size of the window by sending the message
setResizable ( f a l s e ) to the window.
gridx 0 0 3 1 2
gridy 0 1 1 2 2
gridwidth 4 3 1 1 1
gridheight 1 1 1 1 1
Now let's use this for the renovation window. We can set up an outline as shown
in Table 15.1. In the constructor that lays out the GUI components, we have to
program it this way:
Container guiContainer = getContentPane();
guiContainer.setLayout(new GridBagLayout()); // don't forget this!
All of these methods take an instance of the java. awt. Dimension class as
their argument. The constructor for this class takes two argumentsthe
component's width and height, respectively. For example:
list.setPreferredSize(new Dimension(500, 300));
The table has a fixed number of columns with fixed column names.
The user can adjust the width of the individual columns in the table. This results
in the other columns becoming narrower.
The user can't adjust the size of the table (the overall width and height of the
table).
The program can insert and delete rows in the table. In order to change the data,
the program can delete a row and insert a new row in its place.
The user can select individual rows in the table. The program determines
whether or not multiple rows can be selected, just as with lists.
The program handles the selection by having the user push a pushbutton, not by
listening to row selections.
Most people will be able to make do with this type of table for quite a while. A
dialog window can be used if the data is going to be changed.
15 Creating User Interfaces
Unfortunately, the default versions of the data model under JTable require
that the user be able to edit the data directly in the table cells. Managing this
requires programming that we're choosing to avoid. Instead, we have to make sure
that the user can't edit the data. To accomplish this, we have to create our own data
model class. This may sound difficult, but doesn't require anything other than
creating a subclass of the DefaultTableModel class and programming our
own version of the isCell Editable () method there. We also have to make a
constructor that goes with DefaultTableModel. We call it MyTableModel
class and put it in the myLibrary package (see Program Listing 15.6).
API Reference
This only includes the few constructors and methods that are used in the
renovation example in the next section. There are many more: refer to the online
API documentation and textbooks devoted to Swing.2
The javax.swing.JTable class
Constructor:
public JTable(TableModel data)
The argument has to be an instance of a class that implements the TableModel
interface, for example myLibrary .MyTableModel (see Program Listing
15.6).
Methods:
public int getSelectedRow()
This method returns the index for the selected row.
public void setSelectionMode(int mode)
See the method with the same name under the JList class in Section 14.5.
public void setPreferredScrollableViewportSize(Dimension size)
This method sets the size of the area the table will be displayed in. The parameter
is an instance of the java. awt. Dimens ion class and may be created as follows
(the width and height are indicated in a number of pixels): Dimension dim =
new Dimension(width, height);
public void setRowSelectionlnterval(int fromlndex, int includinglndex)
This method sets the indicated interval as selected. It throws an IIlegal-
Argument Except ion if the index is invalid.
2. [Horstmann, Cornell 2000], [Walralh, Campione 1999], (Eckstein, Loy, Wood 1998)
15.5 The Table GUI Component (the JTable Class)
The Dialogs.java file contains a dialog window for each of the "main objects" in
the problem: Surf aceDialog, PaintDialog, WallpaperDialog, and
FlooringDialog.
The Constants.java file contains an interface with many of the constants used in
the different windows. Example constants are the names of commands, menu
items, and the lengths of text fields. By collecting the constants that are used in
several classes into an interface, classes that need the constants can access them
by implementing the interface.
length = numberFormat.parsePositivDouble(lengthField.getTextQ);
width = numberFormat.parsePositivDouble(widthField.getTextQ);
} catch (ParseException e) {
JOptionPane.showMessageDialog(null,
"Number input could not be converted, Try again!");
widthField.requestFocus();
return false;
}
return true;
}
public Surface showDialog() {
nameField.setText("");
widthField.setText("");
lengthField.setTextC"1);
setOk(false);
setVisible(true);
nameField.requestFocus();
if (isOk()) return new Surface(nameField.getText(), length, width);
else return null;
/* The other dialogs are constructed in the same way, see the file Dialogs.java */
Finally, let's take a look at the primary window (see Program Listing 15.9). This is,
of course, a very large and comprehensive class with many instance variables, two
inner listener classes, and several private help methods. Let's start at the beginning
and go through the different parts of the program listing.
Instance variables
Many of the GUI components are instance variables. That means that we may
refer to them from multiple methods. There's also a reference for each
individual dialog. And, perhaps most important of all, there's a reference to the
theProject object that is an instance of the RenovationProject class.
This is the important link between the user interface classes and the classes that
describe the problem we're going to solve.
Notice that the init Project reference is a parameter for the constructor.
Skim to the very end of the program listing for a second. There you'll find the
statements that bind an instance of the RenovationProject class to an
instance of the Project Chap 15 class:
15 Creating User Interfaces
RenovationProject myProject
= new RenovationProject("The last version of the Renovation Case!");
ProjectChap15 window = new ProjectChap15(myProject);
There's little new in the rest of the constructor. Notice that we set the layout
manager to GridBagLayout.
The ButtonListener class describes objects that can listen to the buttons in
the toolbar. After finding the index for the command, we let a switch
statement determine which operations will be executed. Every single case-
block, except for "Cancel", communicates with theProject object. The
models behind the lists in the window (surfaceData and
materialData) are also updated. Choices 0-3 display the right dialog
window and receive a new surface or a new material from this window. The new
object is registered in theProject object. Choices 1-3 use the help method
recordMaterial (). This is a private method in the ButtonListener
class. Choice 4 combines surface and material.
The MenuListener class describes objects that can listen to the menu choices
"Help" and "About the program...."
* The surface data are displayed in the surfaceList object, which is an instance of
* the JTable class. The model behind is named "surfaceData" and is an instance of
* myLibrary.MyTableModel.
*
* Information about the materials is displayed in the materialList object, which is
* an instance of the JList class. The model behind is an instance of the
* DefaultListModel, and it is declared as materialData.
* The row numbers in the displayed lists should be the same as the indexes in
* "theProject".
*
import java.awt.event.*;
import javax.swing.*;
import myLibrary.*;
class ProjectChap15 extends JFrame implements Constants {
private Container guiContainer;
private JToolBar toolbar = new JToolBar();
private JButton[] button = new JButton[buttonCommand.length];
/* Material data 7
private DefaultListModel materialData = new DefaultListModel();
private JList materialList = new JList(materialData);
private JScrollPane scrollMaterialList = new JScrollPane(materialList);
/* Surface data */
private MyTableModel surfaceData =
new MyTableModel(columnNames); //from myLibrary
private JTable surfaceList = new JTable(surfaceData);
private JTextField sum = new JTextField(fieldLengthSum);
private SurfaceDialog theSurfaceDialog = new SurfaceDialog(this);
private PaintDialog thePaintDialog = new PaintDialog(this);
private FlooringDialog theFlooringDialog = new FlooringDialog(this);
private WallpaperDialog theWallpaperDialog = new WallpaperDialog(this);
private RenovationProject theProject;
public ProjectChap15(RenovationProject initProject) {
setTitle("Renovation");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theProject = initProject; // N.B.! the link to the problem domain object
guiContainer = getContentPane();
initListsQ;
createToolbar();
createMenu();
guiContainer.setLayout(newGridBagLayout());
layoutGUI();
theSurfaceDialog.setLocation(dialogX, dialogY);
thePaintDialog.setLocation(dialogX, dialogY);
theFlooringDialog.setLocation(dialogX, dialogY);
theWallpaperDialog.setLocation(dialogX, dialogY);
setLocation(windowX, windowY);
setResizable(false); // the user is not allowed to change the size of the window
}
/* This class describes the listeners to the toolbar buttons */
private class Button Listener implements ActionListener {
public void actionPerformed(ActionEvent event) {
String command = event.getActionCommand();
15 Creating User Interfaces
break;
case 5:
System. exit(0);
break;
default:
System. out.println("The program control should not enter this point!");
break;
}
if (surfaceData.getRowCount() > 0 && materialData.size() > 0) {
button[combinelndex).setEnabled(true);
/* This private method creates a row with data customised to the surfaceData object */
private java.lang.Object[] createRowData(Surface theSurface) {
java.lang.Object[] columns = new Java.lang.Object[columnNames.length];
columns[0] = theSurface.getName();
columns[1] = outputFormat.format(theSurface.getWidth());
columns[2] = outputFormat.format(theSurface.getLength());
Material theMaterial = theSurface.getMaterial();
if (theMaterial != null) {
columns[3] = theMaterial.getClass().getName() +":" + theMaterial.getName();
columns[4] = outputFormat.format(theMaterial.getMaterialReq(theSurface));
columns[5] = outputFormat.format(theMaterial.getPricePerUnit());
columns[6] = outputFormat.format(theMaterial.getTotalPrice(theSurface));
}
return columns;
}
/* This private method initiates the surfaceList and materialList objects*/
private void initLists() {
/* A non proportional font */
Font defaultFont = surfaceList.getFontQ;
Font newFont = new Font("Monospaced",
defaultFont.getStyle(), defaultFont.getSize());
surfaceList.setFont(newFont);
sum .setFont(newFont);
surfaceList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
materialList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
/* The size of the window in which surfaceList is shown*/
surfaceList.setPreferredScrollableViewportSize(sizeSurfaceListWindow);
/* Heading for the material list */
JViewport jvp = new JViewport(); // see the online API documentation
jvp.setView(new JLabel("Materials"));
scrollMaterialList.setColumnHeaderQvp);
}
private void createToolbar() {
toolbar.setFloatable(false);
ButtonListener theButtonListener = new ButtonListener();
for (int i = 0; i < buttonCommand.length; i++) {
Icon icon = new lmagelcon(iconDirectory + iconfile[i]);
button[i] = new JButton(buttonCommand[i], icon);
button[i].setToolTipText(buttonDescription[i]);
button[i].setMnemonic(buttonMnemonic[i]);
button[i].addActionListener(theButtonListener);
toolbar.add(button[i]);
}
button[combinelndex].setEnabled(false);
15.6 GUI for the Renovation Project
class RenovationChap15 {
public static void main(String[] args) {
RenovationProject myProject
= new RenovationProject(The last version of the Renovation Case!");
ProjectChap 15 window = new ProjectChap15(myProject);
window.pack();
window.setVisible(true);
Problem
The classes in the Dialogs.java file have a great deal in common. Propose a class
structure that uses inheritance. Make a class tree starting with the MyDialog class.
Make new versions of the dialog classes. Test the classes by replacing the Dia-
logs.java file with the new classes. Remember to recompile.
dialog window A dialog window is a secondary windowin other words, it's connected to a parent
window. A dialog window is an instance of the JDialog class.
dropdown The menu appears when the user clicks on the menu name. Normally the menu is shown
menu under the menu name (hence the designation dropdown menu), but if there's no room
there, it's shown above the menu name.
menu In this book, we're only including dropdown menus. A dropdown menu is an instance of
the JMenu class.
menu bar See Figure 15.1. A menu bar is an instance of the JMenuBar class.
menu item See Figure 15.1. A menu item is an instance of the JMenuItem class.
modal dialog window A dialog window that doesn't allow the user to access other windows as long as it's open.
The modal dialog itself can open its own dialogs.
nonmodal dialog A dialog window where the user has unrestricted access to all other windows in
window the application.
toolbar A collection of pushbuttons. The buttons are gathered into an instance of the JToolBar
class. The toolbar is displayed at the top of a window, but can also be presented in its own
window.
Remove a product (here you have to expand the class from Chapter 9 with a
suitable method)
Problem 2
Start with programming problem 1, Chapter 10.
Create a GUI that shows all the information about all the employees. Use an
instance of the JTable class.
The primary window will also show the number of employees and the average
salary.
The window will have a pushbutton that makes it possible to register a new
employee. A dialog window to register all the data must appear and the pertinent
data in the primary window has to be updated once the new employee is registered.
Problem 3
In problem 4, Chapter 13, you made a simple reservation system for seats in a
concert hall. Link this user interface to data stored in a file.
You can assume that there's enough room in the internal memory for all the data
in the file.
The file will contain data about several different shows. There will be many
performances of each show. You can assume that it's possible to reserve seats seven
days in advance. Every time the program starts, data that is older than today's date
will be removed.
Create a suitable class that communicates with the data file (use serialization).
The user interface in turn will communicate with this class.
Hint: use the MyDate class from programming problem 1, Chapter 8 (you'll
find the solution at [URL Java book]).
15.9 Programming Problems
Problem 4
Start with programming problem 2, Chapter 10, and make a GUI to maintain the
registry. Decide on the design yourself.
Problem 5
Start with programming problem 5, Chapter 12, and make a GUI to maintain the
cardkey registry. Decide on the design yourself.
This page intentionally left blank
Learning goals for this chapter
After completing this chapter, you will understand the meaning of:
Context switch
process 1 process 3
process 2 thread 1
thread 1 thread 3
thread 2 thread 1
[Jl [Jl thread 2
threads that run concurrently. In our context, that means that in a single Java
program, we can have many small jobs that run at the "same" time. Many operating
systems include threads as an integral component, and Java lets us make use of this.
Figure 16.1 illustrates the concept. Think of the time axis as being oriented
downwards so that the boxes' different heights indicate that processes and threads
start and stop at uneven intervals. Each process can correspond to a Java program
that is running its own interpreter.
The fact that we have numbered the processes is close to reality: in most systems,
all processes are allotted a PID, Process ID. An important difference between a
thread and a process is that the processes have their own version of a larger amount
of information and resources. Both threads and processes have their set of
variables, objects, and the like that are uniquely their own, but the processes have
a great deal more. For the processes' part, this is information that has to be stored
away every time there's a context switch. When the processor is going to finish
spending time on one process and start on another, it needs to remember what the
first one was doing when its turn comes around again. There's a similar problem
for threads, but the point is that threads in a process usually have less of their own
information and share more of the process's resources. Hence, a thread is
sometimes referred to as a lightweight process, an LWP. Threads make it relatively
easy and efficient for us to program multitasking in a program.
In many systems there is a distinction between system processes and user
processes, and user threads and kernel threads, but we will not go into that.
For certain UNIX type operating systems, the process-thread model has been
adjusted so that context switching for threads actually takes longer than context
switching for processes, but we're sticking with a thread as a conceptual "small"
process within a process.
All Java programs have at least one thread. For example, when we program GUIs,
we use several threads without even knowing it. There is a single thread that keeps
track of events that happen in the GUI, to name one. So, even if we program
without threads, the final program can have several.
Threads in UML
The activity diagrams in UML can be used to visualize parallel jobs like this. If we
imagine that at a given point in time a thread starts a new thread that it will later
have to wait for, this can be visualized in UML as shown in Figure 16.2.
Figure 16.2 shows a thread that performs different activities (boxes). At a given
time, thread number two is started and performs an operation before that side
finishes. The time axis is vertical. The thick horizontal lines are an "intersection"
where the program execution divides itself up into several threads, or where one or
more threads end. The line where the program execution divides itself is called a
fork line, fork being the designation for what is happening internally in an operating
system when one process turns into two. We don't run into this concept in Java, but
we'll see join soon. That is also the name of the line where two threads combine
together into one. As a rule, this happens when one is waiting for the other to finish.
16 Threads
thread 1
fork line
join line
new operations
If we look at a platform where the Java interpreter does not have the same
mechanism, such as in UNIX earlier, then it's dependent on the fact that all the
16.3 Example of Threads in Use
threads cooperate on their own by giving up the baton at regular intervals. What
happens if we have a thread that wasn't written with this in mind? Well, if it doesn't
let others have a chance on its own, and the Java interpreter doesn't force it to, other
threads don't get to run. As simple as that. The thread can be called selfish. Thread
switching can occur now and then. For example, if one of the interpreter's internal
system threads (which might be able to get priority over ours) has to run, one of
ours can take its turn once it's done.
Java makes it straightforward for us to program threads that aren't selfish. We'll
come back to that. It will be necessary to do this when we don't know what kind of
platform our program will be used on.
*/
class NumberPrinter extends Thread {
private int numberToPrint;
public NumberPrinter(int number) {
numberToPrint = number;
}
public void run() {
while (true) {
System. out.print(numberToPrint);
System.out.print(" ");
class ShowerOfNumbers {
public static void main(String[] args) {
NumberPrinter printerl = new NumberPrinter(l);
NumberPrinter printer2 = new NumberPrinter(2);
NumberPrinter printers = new NumberPrinter(S);
NumberPrinter printer4 = new NumberPrinter(4);
NumberPrinter printers = new NumberPrinter(5);
printer1 .start();
printer2.start();
16 Threads
printer3.start();
printer4.start();
printer5.start();
API Reference
What happens when the program runs? We (and possibly you) get a printout
similar to this:
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 5 4 1 2 5 4 1 2 5 4 1
2 5 4 1 2 5 4 1 2 5 4 1 2 41 2 41 2 41 2 41 2 41 2 41 2
41 2 412 5 12 5 12 5 12 5 12 5 12 5 12 5 12 5 12 5 12 5
16.3 Example of Threads in Use
12 5 12 5 12 5 12 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 213 4 213 4 213 4 23
4 23 4 23 4 23 4 23 4 23 4 23 4 23 4 23 4 23 4 23 4 23 4
1 34 1 34 1 34 1 34 1 34 1 34 1 34 1 34 1 34 1 34 1 34 1
34 1 34 1 34 1 41 41 41 41 41 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1
This is an excerpt from the output data for this program after it has run for a while.
The first thing we notice is that this must have been run on a system where the
interpreter is forced to divide time between the selfish threads. If not, we would
only have seen thread switches very rarely, and it's quite possible we would only
have seen one number.
The other thing we can observe is that there's no discernible system in the hail
of numbers, and that illustrates an important point when we're working with
threads: as long as we haven't set things up for the threads to cooperate, we can
never assume anything about what kind of order the threads will run in. In
principle, for example, there's no guarantee that the thread that writes "1" gets to
run first, then the one that writes "2", and so on. We also never know when each
thread will be terminated to make it the next one's turn. The only thing we can
assume is that these five threads get to run for about the same amount of time once
they've started, assuming that the Java interpreter divides the time. We have to pay
attention to this when we are writing programs with threads.
The method the NumberPrinter objects are running writes its number and
then a blank space. Based on the sample printout above, we can also observe that
the threads don't necessarily get to run the method they are in to completion when
they are interrupted. In a few spots, several numbers appear in a row without blank
spaces between them. This means a thread was terminated between the statement
that writes the number and the one that writes the space.
The example also illustrates the quality of threads that we pointed out in our
introduction; the threads have their own data (like objects always have), but they
also share the accessible portions of the program's dataother variables. The
NumberPrinter objects' instance variables belong solely to the threads, in this
example numberToPrint. Common data used by the threads is System, out,
which is an instance variable of the System class. All the threads send the
message print In () to out.
16 Threads
A Thread can be created with another object as its argument for the constructor.
Then this object's run () method is used, and the Thread object's run () isn't
used for anything. The object we send in as an argument has to be an instance of a
class that implements the Runnable interface.
From the point of view of many programmers, the main purpose of Runnable
will be the following. If our thread objects are going to inherit from another class,
we have problems, because then they can't inherit from Thread. We solve that by
implementing the Runnable interface instead of subclassing Thread.
Runnable contains the method run (), but not the rest of the methods we have
seen, and classes that implement the interface are not threads. Therefore, they need
to contain a Thread object, which is started. But as we've mentioned, these
Thread objects can be created with another object as their argument, so that this
object's run () method is called. Thus we have a connection between the thread
that is started and our class. Study Program Listing 16.2.
class OurThread {
public static void main(String[] args) {
TheThread thr = new TheThread();
Here we see a very simple skeleton example. The TheThread class inherits from
a superclass, Superclass, so it can't also inherit from Thread. Instead it
implements Runnable and has a Thread object thread inside. This is created
with this as its argumentin other words, the pertinent instance of the class
TheThread. That assures that it is this object's run () that is started when the
thread is started. The rest of the examples in this chapter use the first method we
learned, where we inherit from Thread directly.
API Reference
Problem
Modify Program Listing 16.1 so that Runnable is used to actually print out the
numbers.
New: This is the state the thread is in before and while we are starting it by calling
start (). Once we have created the Thread object, the thread is in this state.
It can't do anything-we haven't started it yet. And we can't do anything other
than call start () . Once start () is finished and run () begins, the thread
leaves this state and changes over to Runnable.
16 Threads
Runnable: The thread is alive and will run when it can. It's worth pointing out
that this state doesn't necessarily mean that the thread is working and running.
It can also be a thread that's able to run and which is thus a candidate for being
started when a context switch occurs. So, both a thread that's running and a
thread that has been stopped "against its will" by the interpreter are Runnable.
The name of this state has no strong connection to the Runnable interface.
Blocked (not Runnable): We will come back to the fact that threads can give
themselves a break with the message sleepO or by sending the message
wait () to any object. In addition, the thread enters this state if it, for example,
has to wait for the user to enter something in a stream; this is generally called
blocking IO (input/output).
Dead: A thread enters this state when the run () method finishes on its own.
When the thread is dead, it cannot be started again. A new Thread object has
to be created. There is one big difference between a dead thread and a thread that
is in the state New, and that is that the latter can be started.
suspend (), resume (), and stop () from the java. lang. Thread class
should not be used, but you may encounter them in programs written for earlier
versions of the Java API.
current thread a break for a certain length of time. This can be a good way of
adjusting the speed of a graphic animationthe thread sleeps a little before the next
image is drawn.
We also have a method that can be used if a thread needs to wait until a certain
other thread dies. The method is called j o i n ( ) , and now it's important to
distinguish between the thread we are sending the message from and the thread we
are sending the message to. If we find ourselves in a method in thread threadl
and call thread.2 . join (), threadl will wait until thread2 dies. The whole
thing reminds us that the two threads are combined into one at an intersection.
threadl only continues when thread2 is finished. In the activity diagram in
Figure 16.3, we have tried to illustrate this with some explanatory text inside the
activity boxes.
thread 1 thread 2
_y
thread 1 centimes, join()
refurned
finished
So, what if we call join () on the same thread that we are in? Then the thread is
waiting for itself to die, so we are risking that it might have to wait a very, very long
time.
16 Threads
API Reference
the same method in the common object, but it cannot be assumed that everything
is working properly there, because another thread has been stopped in the middle
of a method.
In Figure 16.4 we have illustrated three threads that all send messages to the
same object. We have called the method they are calling printSequence ()
because we will use it in an example shortly. It's possible for thread 2 to call the
method before it's finished running for thread 1, and the classic synchronization
problem (in Java form) is that the common object is in such a condition when
thread 1 is interrupted that things are completely wrong after all the threads have
finished with the method. In other words, the method won't tolerate being
interrupted and having other threads in turn send the same message to the object.
thread 1 thread 2
method call
class SequencePrinter {
public void printSequence() {
System.out.print("1 ");
16 Threads
System.out.print("2 ");
System.out.print("3 ");
System.out.print("4 ");
System.out.print("5");
class ShowerOfNumbersSync {
public static void main(String args) {
SequencePrinter aPrinter = new SequencePrinter();
NumberPrinter printer1 = new NumberPrinter(aPrinter);
NumberPrinter printer2 = new NumberPrinter(aPrinter);
NumberPrinter printer3 = new NumberPrinter(aPrinter);
NumberPrinter printer4 = new NumberPrinter(aPrinter);
NumberPrinter printer5 = new NumberPrinter(aPrinter);
printer1 .start();
printer2.start();
printer3.start();
printer4.start();
printer5.start();
Program Listing 16.3 shows program code for another shower of numbers. Once
again we have five threads. What's new is that they use a common instance of the
SequencePrinter class. This class has a method that writes the numbers 1 to
5 in order. It does this with five calls to System . out . print ( ) . We will avoid
doing the obvious (collecting this into a single call) to illustrate the point. When
running this, the outcome will be similar to that below. We have extracted part of
the job output after the program has run for a while. The very first number can be
expected to be the number 1 .
4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1
2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4
5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2
16.6 Locks and Synchronization
3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3
4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1
2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4
5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2
3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 2 2 1 1
5 3 3 2 2 1 4 4 3 3 2 5 5 4 4 3 1 1 5 5 4 2 2 1 1 5 3 3
2 2 1 4 3 3 2 5 4 4 3 1 5 5 4 2 1 1 5 3 2 2 1 4 3 3 2 5
4 4 3 1 5 5 4 2 1 1 5 3 2 1 4 3 2 5 4 3 1 5 4 2 1 5 3 2
1 4 3 2 5 4 3 1 5 4 2 1 5 3 2 1 4 3 2 5 4 3 1 5 4 2 1 5
3 2 1 4 3 2 5 4 3 1 5 4 2 1 5 3 2 1 4 3 2 5 4 3 1 5 4 2
1 5 3 2 1 4 3 2 5 4 3 1 5 4 2 1 5 3 2 1 4 3 2 5 4 3 1 5
4 2 1 5 3 2 1 4 3 2 5 4 3 1 5 4 2 1 5 3 2 1 4 3 2 5 4 3
1 5 4 2 1 5 3 2 1 4 3 2 5 4 3 1 5 4 2 1 5 3 2 1 4 3 2 5
4 3 1 5 4 2 1 5 3 2 1 4 3 2 5 4 3 1 5 4 2 1 5 3 2 1 4 3
2 5 4 3 1 5 4 2 1 5 3 2 1 4 3 2 5 4 3 1 5 4 2 1 5 3 2 1
4 3 2 5 4 3 1 5 4 2 1 5 3 2 1 4 3 2 4 3 5 4 1 5 2 1 3 2
4 3 5 4 1 5 2 1 3 2 4 3
We see that little by little, the number sequences become incorrect, and now we
know why. The threads are being interrupted in the middle of their calls to
printSequence () and other threads are coming in and starting again. Now,
what if this was serious? If it is critical that the program only outputs 1 2 3 4 5 in
the correct order, then the problem is clear. What we have to do is ensure that the
method gets to run all the way to the end before other threads can call it, and the
modifier synchronized takes care of this. If we put synchronized before
the method, we are ensured that it will get to run to completion before any other
thread can call the same method or any of the object's other synchronized
methods.
One thing that's important to remember is that synchronized does not
guard against the method being interrupted by a context switch. That can happen.
What we are protected from is the method being interrupted and started again from
another thread, or starting another of the object's synchronized methods.
When a thread gets a turn and is able to run a synchronized method, we say that
it has the object's lockit locks everything that is synchronized in the object to other
threads.
If we synchronize the printSequence () method in our example, we get the
output we want:
public synchronized void printSequence() {
System.out.print("1 ");
System.out.print("2 ");
System.out.print("3 ");
System.out.print("4 ");
16 Threads
System.out.print("5");
Java Core
Synchronizing methods
Syntax:
accessModifiersynchronized retumType methodName() {
contents
When a thread comes to this block, it has to have the specified object's lock
before it starts. Usually the block will perform operations on the same object, but
this isn't any kind of requirement. It will be the same as if the contents of the block
were in a method that belonged to the specified object.
Problem
Modify Program Listing 16.3 so that you use block synchronization instead of
synchronizing the method.
API Reference
A thread that has called wait () for an object is not automatically awakened
when no other threads are working with the object, so notify() or
notifyAl 1 () must be called.
The methods are declared in java. lang.Object, and are consequently
inherited by all classes.
wait () throws an InterruptedExcept ion, which has to be caught. We
will come back to this shortly.
Why is notifyAl1 () necessary when only one can take the object's lock
anyway? A typical situation is that several threads are waiting for the object's lock,
but not for the same reason. One thread has sent the object the message wait ()
anticipating one change in the object, another thread has sent the message for
another reason. We can imagine that in due course all the newly awakened threads
check on whether the thing they are waiting for has been fulfilled, and a thread that
already has what it wants will continue.
When a thread calls wait (), as we've mentioned, it's usually because it needs
to give other threads a chance to change the object's condition. So, it's natural that
as soon as it's awakened it checks yet again whether this condition has changed,
and if not uses wait () again. This is the case in the example we have illustrated
this with. It's still a meaningless output example, this time with a text. If you study
the example carefully, you will be in a position to understand the use of the
mechanisms wait () and notify ().
The example in Program Listing has five threads of the TextPrinter class
and one instance of the Printer class. The threads share this one instance as
before. The Printer class has a method that prints a text. The user can input what
the text will be, and it is set by a method newTextFromUser ().
/* Printout from this program is nothing, until the user has entered a
* text in the dialog box. After that, that text is printed time and again.
V
Informally, we can summarize the program execution this way:
All five of the threads send the message printText () to the object
aPrinter all the time. However, that method is written such that nothing is
written as long as the registered text is empty, "". Therefore, we have a while loop
that checks whether the text is different from "". As long as it is, wait () is called
so that the thread waits.
It does that until something calls notify () or notifyAll (), and that
doesn't happen soon in this example. So what probably happens first is that all five
of the threads go right into wait (), because the object aPrinter is initiated
with "" as its text.
Finally, at the same time, in main () we call the method in aPrinter that
inputs a new text. A dialog box will appear on the screen. As soon as the input is
done, the method does a notifyAll () . That wakes up all the threads, which
each continue in their own while loop, but they immediately find out that now
the object has a text that is not equal to "", if the user didn't enter an empty text
again.
With that, the threads get started, writing this text over and over again. Even if it
doesn't show in the output, it's one thread at a time that gets a chance in the
aPrinter object. When one is finished outputting, notifyAll () is called to
alert the others and give another one a chance.
Interrupting waitQ, sleep(), and join()
We remember that these methods threw an InterruptedException, which
we have to catch. All three calls have in common the fact that we can easily think of
cases where the threads get stuck for a long timemaybe longer than we'd like, and
therefore all the threads have a method called interrupt (). If it's called, the
thread ends up in a type of substate, interrupted. The thread that receives the
interrupt () message can either wait in a wait (), sleep () , or join (),
or not.
If the thread is waiting in a wait (), sleep (), or join (), the waiting is
interrupted and an InterruptedExcept ion is thrown. This leads to the
thread immediately leaving the interrupted state again. Effectively, what we've
done is to wake the thread up from a deadlocked condition.
When it receives interrupt () (if the thread doesn't wait in one of the three
methods, but continues working as usual), it still ends up in the interrupted state.
If that's the case, we can check whether anything else has called interrupt ()
and put the thread in the interrupted state by calling the thread's
islnterrupted (). We can also check whether the thread that's running right
now is interrupted using the interrupted () class method. It is only the latter
that sends the thread out of the interrupted state. If we send a thread the message
islnterrupted () to check, it remains interrupted.
16.8 Peeking at the Threads with JOB
In connection with the calls to sleep (), wait (), and join (), we add code
in the catch statement in the usual way to handle the exception that the threads
are interrupted. If we use interrupt () in our programs, it is important that we
make sure that the threads that are interrupted bear the consequences of this.
API Reference
besides looking at threads, which is what we are going to do now. JDB is a text-
based tool, but integrated development tools often have a graphical debugger,
where we can follow along line by line where the program is in its run. With JDB,
we can start by running a class exactly as when we are running a program the usual
way. Then we can start and stop the program along the way, look at what kinds of
threads are running, and much more. Let's take an example, point by point, and
assume that we are running in an MS-DOS window:
1. We start debugging ShowerOf Text by running JDB on the class we are going
to work with:
c:\javaprogrammer> jdb ShowerOfText
2. Notice how similar this is to starting the program in the usual manner. The
program will send a message that it has been initiated and then produce this
output:
Oxaa:class(ShowerOfText)
>
3. That means that the class is loaded, and that JDB is now waiting for input from
you. If you write help or ?, you get a help text about legal commands for JDB.
Try it.
4. Run the program with run. In a while the dialog box will come up as it would if
you were running the program normally. It's not so strange that it's going so
slowlyafter all, the whole run is taking place in the framework of JDB.
5. When you see the dialog box, go into the JDB window and write threads to see
which threads are running then and there. Those last two steps give a printout
like this:
> run
run ShowerOfText
running ...
main[l] threads
Group ShowerOfText.main:
1. (sun.tools.agent.MainThread)Oxel main cond. waiting
2. (Java.awt.EventDispatchThread)Oxe4 AWT-EventQueue-0
cond. waiting
3. (sun.awt.PostEventQueue)Oxe6 PostEventQueue-0 cond.
waiting
4. (Java.lang.Thread)Oxe7 AWT-Windows running
5. (TextPrinter)0xe9 Thread-1 waiting in a monitor
6. (TextPrinter)0xea Thread-2 waiting in a monitor
7. (TextPrinter)0xeb Thread-3 waiting in a monitor
8. (TextPrinter)0xec Thread-4 waiting in a monitor
9. (TextPrinter)0xed Thread-5 waiting in a monitor
16.9 New Concepts in This Chapter
context switch When the computer changes from one process to another, or from one thread to another.
debugger Utility for running a program during development while at the same time keeping an eye
on the values of variables, which threads are started, and many other things. You can also
start and stop the program along the way.
fork When a process creates a new one, so that we end up with two.
interrupted State when a thread receives the message interrupt (), as a request that it should stop
waiting for other threads or sleeping. If desirable, it can also be interpreted as a request for
the thread to stop running. The thread itself then has to take responsibility for this.
join When two threads/processes "meet," one waiting for the other one finish. Done by sending
the message join () to a thread in Java.
lock A logical concept for something a thread gets when it gains access to a synchronized
resource. Only one thread can have the lock at a time.
multitasking When a computer seems to do many things at the same time. Often the lone
microprocessor in a small computer does all this by changing from task to task.
PID Process ID. An identification number that all processes are allotted by the operating system.
preemptive An external mechanismlike, for example, the computer's operating systemcontrols the
multitasking distribution of time between the threads and/or processes.
16 Threads
selfish thread A thread that never voluntarily lets other threads have a chance.
synchronization In this context: to implement a mechanism such that only one thread has access to a
resource at a time.
synchronized Modifier that indicates that a method will be synchronized. That means that as soon as a
thread calls the method, no other thread can call it or any of the other synchronized
methods for the object in question, synchronized can also be used before a block of
code that is delimited by { and }. Then the block will be synchronized.
thread A small process inside a process. Inside a Java program we have many threads, and we can
make our own too. See also the table of concepts at the end of chapter 1.
Be able to recognize the following data structures: graphs, lists, and trees as well
as simple algorithms for them
Know what the Java API gives you to work with in this context
17.1 Graphs
In the Java language, we operate with primitive variables, arrays, classes, and
objects. As a point of departure, this is what we have to work with for storing data
in the memory, and we do fine with it thanks to encapsulation in classes. A given
object can contain quite a bit of strange data that, from the outside, you avoid
knowing the details of, but simply send the object the defined messages. Array lists
illustrate this point: a array list is an object that serves as a container for many other
objects, and putting data into it and extracting data from it presupposes that we can
use the ArrayList class. However, array lists are usually used as "internals" for
classes that we then use in our program. We have illustrated a scenario like this in
Figure 17.1.
Figure 17.1 shows a client object that is happy to avoid having to use an
ArrayList. That is done inside the classes for the employee and customer
directories. We see that the client object simply sends a few "nice" messages to the
objects in question.
17.1 Graphs
The data structures we will look at now will be somewhat similar to array lists
slightly elaborate things that nonetheless have qualities that will make them useful
to us.
Definition of graphs
A graph is formally defined as a collection of vertices and edges. The edges connect
the vertices so that the graph becomes a network. The vertices are also called nodes.
Graphs are easy to visualizethat's one of their great advantages.
vertex
edge
Figure 17.2 shows a simple graph with six vertices and five edges. This simple data
structure has countless applications. We will name just a few:
Logistics. We can view the vertices as cities and the edges as roads between them.
A transport company would be interested in knowing the shortest path between
two cities.
Normally we add more elements to the very simple data structure we just
presented. The graph is often defined as directed, which is to say that the edges have
a direction, which we represent visually with arrows. Be careful not to confuse this
with the arrows in UML. Some of the figures in UML can be viewed as graphs, but
in this chapter, we are illustrating graphs in general. In a directed graph, an edge
represents a unidirectional connection between two vertices. If the connection is
going to be bi-directional, we use two edges, one for each direction.
It's also possible to use a value for each edge, called a weight. It could be a
number that represents time use in the data communication, the distance between
the cities, etc. When we introduce these additions, the graph might look like Figure
17.3.
vertex
edge
When we go to work with graphs in practice, the vertices and edges will also need
some type of identifiers.
17.2 Lists
We looked at arrays and array lists earlier. These are data structures for data that can
be ordered sequentially one after the other. With arrays, we also had
multidimensional casesfor example, two-dimensional arrays. But that was an
array where every element was a new array.
For every data structure of this type, there are some operations that it makes
sense to perform:
17.2 Lists
We want to add data into the data structure, be it first, last, or in a specific
position. With arrays, this was easy. It was just a matter of using an index to
specify a position in the array.
In addition, we can imagine wanting to sort the data structure by one criterion
or another. In that case it would be appropriate to put an element in the right
place in terms of the sorting.
One such data structure or graph form you often encounter in programming is
lists or linked lists. These are graphs that can be drawn in a straight line and are used
as storage for data. The data is inside the vertices in this graph and it is no great
secret that in practical terms they are objects in Java. The storage size is variable as
are the number of vertices. Here we can see clear similarities with arrays and array
lists. But there are some differences that are significant to performance.
We have chosen to call the vertices in a linked list "elements" to be consistent
with much of the other literature and the term we use in conjunction with arrays.
Furthermore, the links in a linked list can also be referred to as references when we
implement them in Java as references between objects.
single-linked list
double-linked list
to
The links in this type of list tell us something about how we can move when we deal
with the list. Namely, we can't get hold of a given element directly in a linked list
the way we can in arrays. As a rule, we will only know where the start and maybe
the end are, since seen from the outside, we have a reference to where the first and
possibly the last element are.
17 Data Structures and Algorithms
Adding a new element to the list. If we want to add an element to the end, the
current final element also needs a reference (a new arrow in Figure 17.4) to the
new one. If it's a double-linked list, the new element needs a reference back to
the preceding element.
Deleting an element from the list. When this happens, the references have to be
manipulated such that you link "around" the element that's going to be
removed. This operation will typically be quick in linked lists, because we are
only moving some references and not moving or copying objects.
Searching for a given element in the list. A possible result from a search will be
a reference to the right element if it's found, null otherwise. We may instead
want a boolean value as a result to indicate whether or not the element we
were searching for was found in the list.
Sorting the list by, for example, last name, if every element is an object that
contains a String lastName.
How will we do this with the references between the objects in practice? Here is
an example of that for a single-linked list. First we need a class for each one of the
elements the list contains, then a class that comprises the list itself.
NameElement
next
name
getName
getNext
set Name
setNext
Figure 17.5 shows a class diagram for one such class, NameElement. Every
element in the linked list will be an instance of this class. The source code is shown
in Program Listing 17.1.
17.2 Lists
class NameElement {
private NameElement next;
private String name;
public NameElement(String initName) {
name = initName;
next = null;
The class contains only two instance variables: a text name, which is the data that
is linked to each element, and a reference to a new instance of the NameElement
class. In addition, we have get and set methods, as well as a small selection of
constructors. What may seem surprising here is that we have a reference to an
instance of the same class that the reference is in, but that's fine. Every object has
data, in this case a text, and a reference to the next element in the list. For the last
element in the list, the next value is null. It stops there. Figure 17.6 shows how
the reference next points on to the next element in the list.
17 Data Structures and Algorithms
So where does the whole thing start? How does the class that surrounds the whole
list come to be? We show it in Figure 17.7 and Program Listing 17.2.
NameList
firstElement
toString
insertNameAtEnd
findName
deleteName
class NameList {
private NameElement firstElement;
/*The method returns the contents of the list in textual form. */
public String toString() {
String listText ="";
NameElement auxReference = firstElement;
while (auxReference != null) {
listText = listText + auxReference.getName() + "\n";
auxReference = auxReference.getNextQ;
17.2 Lists
return listText;
}
public void insertNameAtEnd(String newName) {
NameElement auxReference = firstElement;
NameElement auxReferenceRightBehind = null;
/* We start by moving to the end of the list. V
while (auxReference != null) {
auxReferenceRightBehind = auxReference;
auxReference = auxReference. getNext();
}
if (auxReferenceRightBehind == null ) {
/* This happens if the list was empty from before. */
firstElement = new NameElement(newName);
} else {
/*
* This happens if there was at least one element in the list
* from before. auxReferenceRightBehind is now referring to
* the last element.
*/
auxReferenceRightBehind.setNext(new NameElement(newName));
auxReferenceRightBehind.setNext(auxReference.getNext());
} else {
firstElement = auxReference.getNext();
}
auxReference = auxReference.getNext();
} else {
auxReferenceRightBehind = auxReference;
auxReference = auxReference.getNext();
The NameList class has a very simple set of operations. We can print out all the
elements in the list, add a new name to the end of the list, search to find out if a
specific name is in the list, and remove all occurrences of a specific name from the
list.
Most of the operations on lists like this take place using a help reference of the
same type as the elements in the list. Using that, we jump from element to element
by using getNext ( ) on the objects.
Also notice that a while loop is being used because we don't know the number
of elements in advance. With arrays, we usually know the number of elements and
then we use for.
There's a test program for the class in Program Listing 17.3.
class NameListTest {
public static void main(StringQ args) {
NameList aList = new NameList();
System.out.println("Printout of empty list:");
System.out.println(aList.toString());
aList.insertNameAtEnd("Larry");
aList.insertNameAtEnd("Winston");
System.out.println("Printout of two men:");
System.out.println(aList.toString());
System.out.println("ls Bucky in the list:" + aList.findName("Bucky"));
System.out.println("ls Larry in the list:" + aList.findName("Larry"));
System.out.println("ls Winston in the list:" + aList.findName('Winston"));
System.out.println("lnserts an extra Larry...");
aList.insertNameAtEnd("Larry");
17.2 Lists
/* Example Run:
Printout of empty list:
Printout of two men:
Larry
Winston
Is Bucky in the list: false
Is Larry in the list: true
Is Winston in the list: true
Inserts an extra Larry...
Printout with two Larries:
Larry
Winston
Larry
Deleting Larry and Winston...
Printout of empty list:
V
So, you may ask yourself what the point to a linked list is, when we have arrays and
array lists with approximately the same functionality. It is a matter of efficiency, in
specific situations. Take the operation of deleting an element from the middle of
the list. For a array, first you have to remove the element you're going to get rid of,
then the ones that come after it have to be copied back into place. This is because
the elements are located next to each other in the computer's memory.
To remove an element from a linked list, we just adjust the next reference for
the previous element to point past the one that is being removed. This is
significantly faster and that can be important if there is a large amount of data.
On the other hand, if we are going to access an element in the list frequently
from a specified position, then it actually goes quite slowly since all we can do is
keep moving forward until we come to the right one. So if the performance is
important for the operation of accessing element number n, an array list will be a
far more suitable data structure.
It's not easy to understand the type of reference manipulation that the
NameList class makes by simply studying the program list, so we recommend the
following problems.
17 Data Structures and Algorithms
Problems
1. Use a pen and paper and sketch what happens when we remove an element from
a linked list. Remember that it's a matter of "linking past" the element that's
being removed.
2. Use a pen and paper. Start with a sketch of the list like the one in Figure 17.4 and
draw in where the references auxReference and auxReferenceRig-
htBehind point to at each point during the run of the methods in the
NameList class. At any rate, do this for the methods insertNameAtEnd ( )
and deleteName ().
3. Expand our example so that the list is double-linked. Every element then has to
have a reference to previous. The deleteName ( ) method changes. Make
this change.
Possibility of adding an element first in the list, or to a specific position in the list
We could have done some of these expansions in our example relatively easily.
Others would have taken more time. We will use the time to look at the Java API's
possibilities instead. Even if we're tying the classes and interfaces to our example
here, they have many other applications.
Collection
We find the Collection interface in the java.util package. Classes that
implement this interface have the characteristics of a collection of elements of
different types. In and of itself the interface doesn't say anything about how this
collection is organized or what types of objects it consists of. The interface dictates
some methods that this type of collection of elements must provide.
Such collections of elements can theoretically be divided into four, depending
on two parameters: whether several objects in the collection can be the same or not,
and whether the collection is ordered in any way. "Ordered" means that the
elements can be viewed in a specific order.
In Figure 17.8 we see that there are four different "outcomes" when we have
these two parameters. We have mentioned one type of collection for each outcome.
We'll come back to what a hashtable is.
17.3 The Solution: Collection, List, and LinkedList
Hashtabte (the
Duplicates not table itself in Set
allowed many cases)
Figure 17.8 Collections that are ordered or not ordered, and with and without duplicates
The Java API's own Collection interface is so general that it fits in all the
variants. Of course, the collection may not contain multiple references to precisely
the same object since it's either going to contain this element or not. Furthermore,
it may be that you can't add a reference to an object that has identical data as an
object that is already in the collection from before. When this is the case, then
typically newObject. equals (anObject) will be true where newO-
bject is the object we're trying to add a reference to, and anObject is some
object or other that was in the collection from before. This presupposes that
equals ( ) is implemented for the applicable classes. The result is that the
collection contains only different elements. On the other hand, it may be
applicable to permit duplicates of this type.
API Reference
List
A list is a sub-interface of Collection. In other words, it retains the
requirements that Collection dictates and adds additional requirements.
What's new in List is that there is an ordering of the elements. The elements will
17.3 The Solution: Collection, List, and LinkedList
API Reference
Lists will typically permit us to have multiple objects with identical data. If we have
a strip of data where everything has its position, it doesn't seem so strange that
some elements have the same data. Note that the interface itself cannot dictate this.
It depends on how the add () method is implemented. For example,
ArrayList permits this and even multiple references to the same object.
LinkedList
Now we've reached the class we are going to use. This class is in the j a v a . u t i l
package and implements, among other things, List and therefore
Collection. In other words, the class bears the mark of being a collection of
elements arranged in an order, and that obviously fits into the linked list data
structure.
17 Data Structures and Algorithms
We are allowed to insert all kinds of objects into a LinkedList; the class takes
care of the rest (i.e., the references between the objects). The documentation says
that the class has the performance one expects from a double-linked list. We can
assume that that means that deleting an element from the list goes relatively
quickly, while accessing an element number n goes a little more slowly than for a
array list.
API Reference
Problem
Rewrite Program Listing 17.3 so that it uses LinkedList instead of our
"homemade" list class.
a tollbooth. Two central events will be that a car enters the line of waiting cars and
that the car leaves the line. Then, it may be of interest to calculate the average length
of the line or the length of the line during rush hour.
FIFO queue
A line of cars waiting to go through the tollbooth is an example of a FIFO queue,
First In, First Out queue. It gets that name because the first car into the line is the
first car to leave it. FIFO queue is sometimes used synonymously with queue. In a
data program, a data structure for a FIFO queue has to provide two operations:
taking out and putting in an element. We see an operation to find out the number
of elements in the queue in a possible support operation.
The LinkedList class is flexible enough that we can use it as the basis for a
queue data structure. We've seen that LinkedList has methods for inserting
data first and last in the list. A natural thing to do is to compose a class for a queue
that encapsulates a LinkedList object, and makes use of a couple of its
methods. That is a very short bit of code:
class FIFOQueue {
private LinkedList list = new LinkedList();
public void insertElement(Object anObject) {
list.addLast(anObject);
}
public Object removeElement() {
return list.removeFirst();
}
public int findNumberOfElements() {
return list.size();
1
}
The Java API doesn't provide a class for a queue and when you see how easily we
can make one ourselves with the existing class for a linked list, you'll understand
why. Actually, you're asked to do it this way in the documentation for
LinkedList. Our class FIFOQueue can have all types of objects in the queue
since Object is a parameter for the methods.
Stack
A stack is also called a LIFO queue, Last In, First Out queue. A stack is also a queue,
but it has the characteristic that the element we take out will be the last one that was
put in. Picture a stack of plates. The first plate we put into the stack will be the last
to leave it, if it's taken out at all. A stack is First In, Last Out in addition to Last In,
First Out. Just as easily as with a FIFO queue, we can construct a data structure like
this using LinkedList:
class Stack {
private LinkedList list = new LinkedList();
17 Data Structures and Algorithms
Again we see that it has to do with a simple limitation on a linked list. Putting an
element into a stack is also called pushing, and retrieving and deleting an element is
called popping. There is also a stack implementation in the API, see
java.util.Stack.
A very common application for stacks is in calculators and other adding
machines. Suppose the adding machine is going to find the value for this
expression:
(34 + 5) x 56
(5 x89) + (9-3)
This is long division, with compound expressions above and below the fraction
line. We can imagine that the adding machine first calculates the expression under
the fraction line and that this is stored on a stack. Then the machine calculates the
expression over the fraction line and possibly stores this on the stack as well. Then
the calculation can be completed with the division involving the two uppermost
numbers on the stack.
Problem
In the last example with the compound expression, it would also be natural for the
same stack to be used when the expressions above and below the fraction line are
going to be calculated together. Explain how.
17.5 Recursion
Before we continue and look at more data structures, we will go through the
programming technique called recursion.
It happens that we can effectively solve a problem by starting at one end, solving
a little bit of the problem there, and then doing precisely the equivalent operation
to the rest of the problem. Finally there's nothing left of the original task, and the
problem is solved.
A normal technique for doing this is for a method to call itself, and that's what
recursion is. This is how it might look:
void myMethod() {
/* Some lines of code ...*/
17.5 Recursion
myMethod();
/* Maybe some more ... */
}
In the middle of the myMethod () method there's a new call to myMethod () ,
How can this work well? The first thing you think is that if this is permitted at all in
the first place (which it certainly is), then this program bit must get stuck
indefinitely. The key is recursion's stop condition. If the method unconditionally
calls itself in all situations, it will get stuck and stop only when the program cannot
use any more memory, and an OutOfMemoryError is thrown. An error is more
serious than an exception, but makes itself known in a similar way. We may catch
them with try and catch (see Section 8.5). But it's so serious that we can't
handle them the way we handle an exception. If our program throws a subclass of
Error, generally there's no hope left for a continued reasonable program run.
Back to recursion. For this to stop somewhere, the method has to have a
condition that determines that now the method will not be called again. Then the
recursion stops. We illustrate this with an example where we calculate the value n!,
n factorial for an integer n. n factorial is defined as: n! = 1 * 2 * 3 * ... * n. For
example, 3! equals 6. The following method calculates n! recursively:
public int factorial(int n) {
if (n <= 1) return 1;
else return n * factorial(n-l);
}
What happens? If we call the method with a negative number as an argument, then
it returns 1, something that is mathematically wrong. Our method is only correct
for non-negative numbers.
If we call the method with an argument of 0, it returns 1, which is correct since
0! is specially defined to be 1.
If we call it with an argument of 1, it returns 1, which is correct.
If we call the method with the argument of 2, then the method goes to the else
statement and returns 2 * factorial(l), which is to say, an extra call to the method.
That call returns 1, and the answer will be 2 * 1, which is equal to 2.
Notice how small and elegant the solution is (although in practice it can be
relatively slow, depending on the Java interpreter). We'll see the same thing in the
chapter on trees, where searches are performed recursively.
Problems
1. Go through the factorial ( ) method step by step for the argument 3, and
check that it returns the correct value, which is 6.
2. Make a method that takes a text as its argument. The method will return true if
the text is a palindrome, otherwise false. A text is a palindrome if it reads the
same forward and backwardfor example, "Otto" or "A man a plan a canal
Panama." Ignore blank spaces and capitalization. Use recursion.
17 Data Structures and Algorithms
17.6 Trees
We're familiar with the idea of a class tree from before. Now we will look at trees
as a data structure and one special instance of a graph. A tree in this context is a
graph with some additional characteristics. A tree cannot contain cycles or round
trips in the graph. Figure 17.9 illustrates this.
Furthermore, we require that the graph sticks together, that there aren't several bits
of it. Note that this means that there is always exactly one path between two
vertices. As a rule, we operate with a vertex that is designated as root. The tree
spreads outwards from this vertex and there is always exactly one path from a
vertex home to the root. We have drawn the root at the top of the tree in Figure 17.9,
but note that all the other vertices could have been the root (just turn the book a
little bit). So the root has to be defined. A subtree is a smaller tree that makes up part
of the entire tree.
Binary search trees
This is a very familiar and much used version of trees. Like lists, the key is data
storage with quick operations. Here we set up the following rules:
Every vertice except the root have a vertex that is called the parent.
Every vertice can have up to two more vertices that they are the parent for. These
are called children. The children comprise the root in the left and right subtrees.
A vertex without a child is called a leaf. Figure 17.10 illustrates these terms.
17.6 Trees
root
The data structure we have just defined is called a binary tree because there's a
maximum of two children, but we don't stop there.
Data belongs to all the vertices and the data is located in the tree such that every
vertex's left child's data is "less than or equal to" the parent's, and the right
child's data is "greater than" the parent's data. "Less than or equal to" and
"greater than" can have many types of meanings, even if a few are quite obvious.
In addition to a vertex's child having these characteristics, all the other vertices
in the right and left subtrees will also have the corresponding characteristics.
Figure 17.11 shows a binary search tree, with the root at the top and the children
below. We see that the condition that the child on the left will have a lower value
and the child on the right will have a larger one is fulfilled, so this is a valid tree
when "greater than" has the usual mathematical meaning. It won't be permissible
to place 16 as the right child to 14, since this is wrong with respect to 15.
The Java API provides a class java.util.TreeMap that implements this
data structure. Before we go through it, we will present a homemade example that
is very simple. We have chosen to implement the data structure itself with two
classes, BinarySearchTree and SubTree. Every vertex is a SubTree object,
but the objects contain methods that take care of the whole subtree from the
subtree's root vertex down. Data in every vertex is an integer.
17 Data Structures and Algorithms
V
class BinarySearchTree {
private SubTree root;
public String toString() {
if (root != null) {
return root.toString();
} else {
return null;
Program Listing 17.4 shows the BinarySearchTree class which is the one
clients will use. The class encapsulates the whole tree. The class diagram in Figure
17.12 shows that we will implement the functionality of inserting a new value in
the tree, retrieving a textual description, and searching for a value in the tree.
root
toString
tnsertValue
searchForValue
We've left out the function of deleting a value from the tree. The reference root
points to the root of the tree, if there is one. If it has the value null, of course the
tree is empty. You'll find a class diagram for the SubTree class in Figure 17.13.
We note that the operations are the same. Wouldn't that mean that we could
have dropped the whole BinarySearchTree class, and used a SubTree
object to represent the whole tree? We could have. But in the
BinarySearchTree class, we are dealing with the special cases where the tree
exists, but doesn't contain a single vertex. Then we get a special case in the
operation for search and insert a new value. When we come to the comparable
operations in the SubTree objects, we know that every object contains data.
17 Data Structures and Algorithms
You'll find the source code for SubTree in Program Listing 17.5, and here we get
recursion.
SubTree
rightTree
leftTree
parent
value
toString
insert Value
searchForValue
class SubTree {
private SubTree rightTree = null;
private SubTree leftTree = null;
private SubTree parent = null;
private int value = 0;
public SubTree(int initValue) {
value = initValue;
/* If the value for this node is larger than the new value, the new
* value is going into the left subtree.
*l
if (value >= newValue) {
if (leftTree != null) {
leftTree.insertValue(newValue);
} else {
leftTree = new SubTree(newValue, this);
}
} else {
if (rightTree != null) {
rightTree.insertValue(newValue);
} else {
rightTree = new SubTree(newValue, this);
/*
* The method traverses the tree infix, and returns a text with the
* contents, separated by spaces.
*/
public String toString () {
String returnText = "";
if (leftTree != null) {
returnText = leftTree.toString() + " ";
}
returnText = returnText + value;
if (rightTree != null) {
returnText = returnText + " " + rightTree.toString();
}
return returnText;
* The method returns true if the given value exists in the tree.
*/
public boolean searchForValue(int valueToFind) {
if (valueToFind == value) return true;
if (value > valueToFind) {
if (leftTree != null) {
return leftTree. searchForValue(valueToFind);
} else {
return false;
}
} else {
if (rightTree != null) {
return rightTree.searchForValue(valueToFind);
17 Data Structures and Algorithms
} else {
return false;
toString () does this, and it's called infix traversing when the method handles
its own data (in this case, a text is added) in between the two recursive calls. Postfix
traversing is when the handling of its own data occurs after both the recursive calls,
and with prefix traversing the calls come as the end.
We test the classes we've made with the test program in Program Listing 17.6.
class BinarySearchTreeTest {
public static void main(String[] args) {
BinarySearchTree tree = new BinarySearchTree();
tree.insertValue(5);
tree.insertValue(3);
tree.insertValue(1);
tree.insertValue(2);
tree.insertValue(4);
tree.insertValue(7);
System.out.println("The tree in sorted order: " + tree.toString());
System.out.println("ls 2 in the tree: " + tree.searchForValue(2));
System.out.println("ls 6 in the tree: " + tree.searchForValue(6));
/* Example Run:
The tree in sorted order: 1 2 3 4 5 7
Is 2 in the tree: true
Is 6 in the tree: false
*/
Problem
1. Sketch a binary search tree on paper, like the one in Figure 17.11, or sketch in the
book. Picture two calls for the searchForValue ( ) method with the
arguments 14 and 23. For each of the two calls, go through the method in your
head and use your pencil to point to which subtree is under the magnifying glass
at each point in time. Remember that there are several calls to the same method
inside each other.
Creating a method that removes a value from our data structure will be a
programming assignment at the end of the chapter, since it's a little more
comprehensive.
17 Data Structures and Algorithms
The point of a binary search tree is that it speeds up searching for a specific value.
As a rule, it's slower to enter data into a binary tree than a double-linked, unsorted
list.
API Reference
The class that implements a binary search tree is called TreeMap. The numbers we
used as examples of data in each vertex would have been keys in TreeMap. So,
having an object connected to every vertex in the search tree gives us a clear bonus
in functionality.
A minor obstacle is that the keys in a map have to be objects. In our homemade
tree structure, we used variables of the type int. We have to be in a position to
compare them for the search tree to be of any use. Luckily, the wrapper class
Integer implements the Comparable interface (see Section 10.7). TreeMap
requires this and uses the interface's methods. So we use Integer objects instead
of variables as keys and then we're on target.
TreeMap also uses a mechanism called red-black ordering2 to ensure that the
tree is always reasonably well balanced. We won't go into how this is accomplished
here, but the mechanism costs us a little extra time when we go to insert data into
the tree.
is - API Reference
Example
In the example in Program Listing 17.7, we use key values from Figure 17.11, and
some names as data values. The names are String objects.
import java.util.*;
class TreeMapTest {
public static void main(String[] args) {
TreeMap treeExample = new TreeMap();
treeExample.put(new lnteger(15), "Rick");
treeExample.put(new lnteger(10), "Rob");
treeExample. put(new lnteger(28), "Melissa");
treeExample.put(new Integer(3), "Harry");
treeExample. put(new lnteger(14), "Ted");
treeExample.put(new lnteger(20), "Mildred");
treeExample. put(new lnteger(16), "Edina");
treeExample.put(new lnteger(21), "Patsy");
System. out.println("Contents of the tree: " + treeExample.toString());
String test = (String) treeExample.get(new lnteger(1 1));
if (test == null ) System.out.println("1 1 is not there");
else System. out.println("1 1 is there: " + test);
test = (String) treeExample.get(new lnteger(10));
if (test == null ) System.out.println("10 is not there");
else System.out.println("10 is there: " + test);
System. out.println("Lowest key value: " + treeExample.firstKey());
System.out.println("Highest key value: " + treeExample. lastKey());
/* Example Run:
Contents of the tree: {3=Harry, 10=Rob, 14=Ted, 15=Rick, 16=Edina, 20=Mildred,
21=Patsy, 28=Melissa}
11 is not there
10 is there: Rob
Lowest key value: 3
Highest key value: 28
*/
Problem
Implement our simple binary search tree using TreeMap.
17.8 Hashtables
A hashtable is also a data structure for storage and searches. It distinguishes itself
from binary search trees by having essentially no order in the elements in the table.
It distinguishes itself from a linked list in that the search goes faster.
Among other things, hashtables are used behind the scenes in many operating
systems to keep track of files in a directory.
There are a number of slots in a hashtable. When we go to store an element in the
table, we have to calculate the right slot for the element. The slots are usually
ordered, and duplicates are not permitted. There has to be a hash function, which
17 Data Structures and Algorithms
can take the element as an argument, and tell us which slot it should go in. The
point is that when we search for an element, we use the hash function to decide
which slot such an element will be in if it's in the table. Then we have to search
through the slot to see if it's there. It's a fairly small job in relative terms compared
to searching through all the elements in the data structure. There is a sample
hashtable in Figure 17.14.
Elements in our hashtable are integers of random size. There are ten slots,
numbered from 0 to 9. It's not an absolute requirement that the number of slots be
constant, but we'll assume that here. We haven't used any complicated math or
logic as our hash function. A value hashes to the slot that corresponds to the last
digit in its value. It should be quick to find the last digit in an integer, so this is a
fast hash function.
Several numbers remain in every slot. We have to be able to have numbers that
end in the same last digit in the data structure. There are different technical ways to
solve this. For example, we can envision a linked list belonging to each of the slots,
containing the elements in the slot.
If we're going to search for the number 35, we proceed this way:
1. Calculate the right slot with the hash function. That will be slot 5.
2. Search through slot 5 for the value. This takes a relatively short amount of time.
We find the value as element number 2 in the slot's list.
17.8 Hashtables
API Reference
Constructors:
public Hashtable()
public Hashtable(int capacity)
public Hashtable(int capacity, float loadFactor)
Methods:
public Object put(Object key, Object data)
This method adds a key-value pair to the table. The location is determined by the
key. This is where the data object goes. The return value is the object this key was
connected to before, or null if the key is new to the hashtable.
public Object get(Object key)
This method searches for this key's data in the hashtable. If it finds it, the data-
object is returned. If not, null is returned.
public Object remove(Object key)
This method removes the object that is connected to this key in the hashtable. At
the same time, the object reference is returned.
Example
In the example in Program Listing 17.8 we set up a hashtable like the one in Figure
17.14. We use some names as String objects as the accompanying data values
for every element in the table.
*/
import java.util.*;
/* The class Ident describes the hash function used in figure 17.14. */
class Ident {
private int value;
public ldent(int initValue) {
value = initValue;
}
/* Gets the last numeral in the value */
public int hashCode() { // redefines the hashCode() inherited from Object
int power = 10;
17.8 Hashtables
class HashTest {
public static void main(String[] args) {
Hashtable hashExample = new Hashtable(10); // to fit the figure
hashExample.put(new ldent(2), "Matt");
hashExample.put(new ldent(11), "Tony");
hashExample.put(new ldent(16), "Celine");
hashExample.put(new ldent(18), "Baldrick");
hashExample.put(new ldent(31), "Arnie");
hashExample.put(new ldent(35), "Vinnie");
hashExample.put(new !dent(55), "Quentin");
hashExample.put(new ldent(85), "Alexander");
hashExample.put(new ldent(94), "Pat");
hashExample.put(new ldent(108), "Put");
System.out.println("The contents of the hashtable: " + hashExample.toString());
String test = (String) hashExample.get(new ldent(11));
if (test == null ) System.out.println("11 is not there");
else System. out.println("11 is there: " + test);
test = (String) hashExample.get(new ldent(6));
if (test == null ) System.out.println("6 is not there");
else System.out.println("6 is there: " + test);
/* Example Run:
Value 2 gives code 2
Value 11 gives code 1
Value 16 gives code 6
Value 18 gives code 8
Value 31 gives code 1
Value 35 gives code 5
Value 55 gives code 5
17 Data Structures and Algorithms
ordering When elements have a mutual order because greater-than and less-than have a meaning.
postfix traversing Treating a binary tree by treating the left subtree first, then the right subtree and finally
the root vertex's data.
prefix traversing Treating a binary tree by treating the root vertex's data first, then the left subtree, and
finally the right subtree.
queue A data structure where elements can be added and removed according to a given system.
recursion Programming technique where a method calls itself and this typically repeats itself until
a condition is fulfilled.
root Vertex defined as the top of a tree (or the bottom of a tree, if we draw them the other way).
stack A type of queue. When something leaves the queue, it's the one that most recently
entered it.
traversing a tree Going through a tree by treating data for each vertex, in addition to recursive calls to
each subtree.
weighted graph A graph where the edges have an associated numerical value.
difficult problem. To remove a vertex, you have to find it first. Once you've found
it, there are four possibilities: 1.) the vertex has no children; 2.) the vertex only has
a child on the left; 3.) the vertex only has a child on the right; 4.) the vertex has
children on the left and right. For possibilities 1-3, it shouldn't be a problem. For
possibility 4, it's a little more complex.
Problem 2
Experiment with taking out and putting in large quantities of data in a linked list
and a binary search tree. Look at the difference in time. One way of measuring time
is to call System. currentTimeMill is ( ) when you start and stop, and then
take the difference.
! *
Malicious logic
9
An applet's security model
Program more advanced applets that communicate with the browser they are
running in, read parameters etc.
We used applets earlier in the book as examples of programs with graphical user
interfaces. In this chapter we will build on what we've covered up to this point
about applets and the Web. Appendix E gives a brief introduction to using applet:;
in HTML documents. The goal here is to prepare the user to try out a few applets.
updated through an external program that the server calls up. Even more useful is
the JSP/Servlet technology which you can read about in chapter 21.
Regardless of what the server does every time a client asks about something, an
operation is executed, and then the request is forgotten by the server. We say that
the Web server is stateless. We might compare this to the Web server being an object
without any variables. There are a number of mechanisms to make up for this
statelessness, but the point is that the HTTP protocol, which the Web uses, has this
quality. When you're sitting and working on the Web, there's a long series of
questions about data and responses sent between you and the various Web servers.
Data that you receive from a Web server will often be passive information such
as text documents and images. (It may be a result of computations by the server,
though: see chapter 21.) Your Web client presents this to you in more or less the
manner it was intended. The idea behind a Java applet is that data retrieved via the
Web is an active bit of code that starts its own operations on the client side. This is
an example of distributed processing. The total amount of operations to be performed
is divided between several machines. Processing on the Web is already distributed
as wellthe clients have the considerable task of visualizing Web documents with
images and layout. In an applet context, we can think of the client machine taking
an even greater part of the overall job in that it's the one running the applet. Java
applets are not the only technology of this kind developed for the Web. One
example is ActiveX from Microsoft, which is a framework that allows smaller
Windows programs and program segments to be downloaded via the Web and run.
Another related technology is Shockwave Flash. Many Web pages, especially
those that emphasize visually striking presentations, use ready-made Flash objects.
Similar to Java applets, they are small programs integrally linked to the Web
document that are downloaded and run. Animation and sound are in the seat of
honor here.
18.2 Security
One problem has to be solved, or at least pointed out: when you distribute
programs the way applets are distributed on the Web, the danger is what we call
malicious logic. This is a general, collective term for programs or parts of programs
that do things we don't want and don't know about.
Most people using computers today are using some version of Microsoft
Windows. Windows 95/98 are essentially single-user systems: When you turn on
your computer and load your operating system, you have access to all areas on your
hard disk right away (for example, C:\Windows where the operating system is
installed). As a consequence of this, all the programs you start will also have access
to these important directories. If a program you click on wants to damage
important files on your PC, there's not much standing in its way. Security is based
on the idea that of course the programs we start up will be useful and not harmful.
And in the vast majority of cases, this is not a problem.
18.2 Security
Other operating systems, like all UNIX variants and Windows NT/2000, are
based on the idea that everyone using the machine will have a user identity and
must log in with a password before anything can take place. Each user only has
access to a clearly defined portion of the machine's diskstypically a home
directory with subdirectoriesand the access control is strict. Ideally, it will be
impenetrable, and in practice it often is. There is also a user called the
administrator, the root, or something similar. Only this user has access to all areas
on the machine's disk, including the important sections where the operating
system and shared software is located. Regular users can run the shared software,
but often cannot overwrite the program files. It is important that only experienced
individuals use the administrator-user so that accidents don't occur, hostile
programs aren't run, etc. If one of the regular users were to run malicious programs,
they would only affect the user's own files and programs, and not threaten the rest
of the computer.
In spite of this, Windows NT/2000 is most often used as a single-user system. In
other words, everyone who uses the same machine uses the same user identity and
has access to the entire hard disk. It is extremely common for Windows
applications to save configuration files in the hard disk's system directory, and then
the applications must be able to access these files.
Viruses are a widely reported type of malicious logic. They are small program
segments that manage to attach themselves to normal programs, inflict some kind
of damage or other, and also spread themselves to other programs. Viruses are
almost uniquely found on single-user systems like Windows 98 or Amiga. To a
large extent, this is due to the fact that there the worst viruses can destroy the entire
disk if that's their goal (as far as that goes, something so drastic would prevent
spreading) and otherwise there are few limitations on their access to the machine.
In addition, it's obvious to assume that the danger of viruses increases with the
popularity of the operating systems.
It wasn't unusual that when Java applets were launched most people
immediately thought of the possibility of malicious applets. Should you just let
your Web browser run a program you stumbled across on the Web, with everything
that might imply? Sun's developers solved this with the sandbox model. The applet
can run, but mechanisms in the Web browser will prevent it from gaining any
access at all to files on the machine it's running on. This is called the sandbox
model because the applet gets to play in a little sandbox by itself, and ideally it has
impenetrable walls. Figure 18.1 shows how a potentially damaging applet only
gains access to the machine it's running on through some limited classes,
interfaces, and objects. For example, it can't access a directory on the hard disk.
The browser is responsible for implementing the sandbox, and this is done
through Java's security model.
A running Java program can have a security manager installed, in the form of an
instance of the SecurityManager class. When a method is going to perform an
operation that might be a security risk, it will ask the security manager if it has
permission to do so. So, the ready-made classes that, for example, read files, create
18 More about Applets
C Windows
Ipt1
System. out
AppietContext
/ect/passwd
Figure 18.1 The suspicious applet does not gain access to many resources on the computer
Every thread running in Java has a set of objects which are instances of
Permission subclasses. When the thread attempts an operation that it might not
have permission for, the installed SecurityManager (if there is one) always
checks the thread's permissions for the operation in question.
We can send messages to the installed security manager, and we can also install a
new one. So, you may ask yourself if it's possible for hostile Java code to set up a
security manager of its own that is much more liberal than the original one. That
won't work since one permission has to do precisely with inserting one's own
18.3 Programming an Applet
security manager. It's not surprising that an applet doesn't have permission to do
this. An applet cannot change the security manager that governs it.
A violation of the installed security rules will lead to an exception of the
SecurityException type being thrown. This is the security manager's way of
saying "no".
API Reference
Problem
Go through the API documentation for SecurityManager and look over what
types of permissions can be checked against.
HTML file, the browser will expect to find a class that is a JApplet or an Applet
there, or a subclass. If this is not the case, the browser will issue an error message.
Most browsers have a little text window you can look at, called the Java console.
Text messages appear there. An applet's System, out will also be sent to this
window.
An applet is also a subclass of the GUI classes Component, Container, and
Panel (see Figure 13.2). We make a mental note of two things:
1. An applet is not a subclass of the Frame class. In other words, it doesn't have
the traits that a JFrame or JWindow has. For example, we cannot send an
applet the message setResizeable (true) .This is all because an applet is
visually inside a Web document and not its own window. See Section 14.9.
2. Swing is not supported by very many browsers. This will hopefully change.1 For
this chapter at [URL Java book] you have the choice between applets with and
without Swing. We don't cover GUI programmingand, as part of that, applets
without Swing in this book.
The life cycle of an applet is slightly more complicated than a normal GUI
application. If you've worked with the Web, you know that you look up a
document, click through to a new page and then maybe go back to the first one
using the Back button. The browser, among other things, will send messages to the
applet every time the user goes into or out of the document where the applet is. The
applet keeps running in the browser, even if the user leaves it. Thus, for example, it
makes sense that it doesn't care about displaying anything when the user isn't
actually looking.
The messages the applet receives from the browser in this context are as follows:
start ( ) is called when it starts to run, and every time it gets going again after
having been stopped.
stop () is called when the user, for example, leaves the Web document the
applet is on.
We make our own versions of these methods if we have our own operations
to do when the applet is removed or loaded, or if a user leaves the document or
returns to it. We illustrate the life cycle of an applet in Figure 18.2.
start()
stop()
We see that the first time an applet is loaded into the browser, the browser sends
the message init ( ) to the applet object. (The identity of this object is given
implicitly; the object is instantiated by the browser, as an instance of the class that
is linked to in the Web document.) When the user clicks in and out of the applet's
Web document, the applet gets the messages start ( ) and stop ( ). It also gets
start ( ) the first time it's startedit's sent immediately after init ( ) .When you
quit the browser, the applets that are active will receive the message destroy ( ),
so that they can undertake any terminating operations that are necessary, stop ( )
always comes before destroy ( ). The methods are summarized below.
API Reference
memory. Therefore, we add code to this that will be executed one time during the
applet's life cycle.
public void start( )
This method is called by the browser every time the applet is to start running,
including right after init ( ).
public void stop()
This method is called by the browser when the applet is not up in a visible Web
document; in practice, the user has clicked away from it.
public void destroy( )
This method is called by the browser at the end of the applet's lifefor example,
when the browser is quit.
We use an instance of the JPanel class as a painting surface for the applet inside
the browser. This is placed in the applet's "content pane." Every time the window
is painted graphically, the message paint Component ( ) will be sent to the
painting surface so that the applet is painted. So, if we have permanent graphics
that will appear in the applet's window, we could well draw them here. We do the
same thing in Program Listing 18.1, and in addition, we've defined the methods we
just went through.
<object > in HTML is a generalization of the older < applet >. If you have an
old browser (for example, Netscape 3), you'll have trouble looking at the applets
at URL Java book]. We recommend that you use a newer browser.
18 More about Applets
Problem
What happens if you press Reload in your browser to get the Web document again?
Look at the Java console when you do this.
import javax.swing.*;
import java.awt.*;
import java.io.*;
public class Suspicious extends JApplet {
private RandomAccessFile fileToBeDamaged;
private Container contents = getContentPane();
public void init() {
contents.add(new Drawing());
try{
fileToBeDamaged = new RandomAccessFile("C:\\config.sys", "rw");
} catch (Exception e) {
System.out.println(e.toString());
}
try{
fileToBeDamaged.writeChars(The suspicious applet has been here!");
} catch (Exception e) {
System.out.println(e.toString());
/*
Typical printout in Java Console:
java.security.AccessControlException: access denied
(java.io.FilePermission C:\config.sys write)
java.lang.NullPointerException
*/
In Program Listing 18.2 we see that the applet, when it's initialized, tries to gain
access to read and write to config.sys using RandomAccessFile. Both
instantiating an object like this and writing text to it throw exceptions that we catch
here and print out to see what happens. If you go to [URL Java book] and try this
applet, or download it and run it with appletviewer, you'll see that a
Security Except ion is thrown when we try to instantiate the
RandomAccessFile object. When we try to write to the file, a
NullPoint erExcept ion is thrown because the object was never instantiated
in the first place.
The wording of the exceptions that are thrown will vary somewhat from Java
interpreter to Java interpreter, but the consequences of what happens are the same.
In Program Listing 18.3 we see an applet called Sly, which tries to set its own
security manager to null. We catch possible exceptions that this attempt leads to
(there is reason to expect them), and print out information about the exception.
Program Listing 18.3
/*
*Sly.javaVBH 2001-08-21
import javax.swing.*;
import java.awt.*;
public class Sly extends JApplet {
private Container contents = getContentPane();
public void init() {
contents.add(new Drawing());
try{
System.setSecurityManager(null);
} catch(Exception e) {
System.out.println(e.toString());
18 More about Applets
When you try this, the Java console will immediately report that a
SecurityExcept ion has occurred. You should be pleased about this, because
it would have been risky to work on the Web if the browser had not ensured this.
API Reference
2. Here we use the word "parameter" in a slightly different way than other places in the book.
18 More about Applets
import java.awt.*;
import javax.swing.*;
public class Parameter extends JApplet {
private Container contents = getContentPane();
private String name;
private String telephone;
public void init() {
name = getParameterfname");
telephone = getParameter("telephone");
contents.add(new Drawing(name, telephone));
/*
* This JPanel is told the parameters the applet has got, through the
* constructor.
V
class Drawing extends JPanel {
private String name;
private String telephone;
public Drawing(String appletName, String appletTelephone) {
name = appletName;
appletTelephone = appletTelephone;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("Name sent into the applet: " + name, 5, 50);
g.drawString("Phone number sent into the applet: " + telephone, 5, 65);
API Reference
Problem
Expand the example in program listing 18.4 so that the applet can add two
numbers. You'll send the numbers in as parameters and the applet will print out
the sum. Remember that the parameters are text; the type has to be converted.
<applet> and <object> The old and new HTML tags that link to an applet. <object > is also intended to be
used for other distributed program segments besides applets.
applet context An object that represents the Web document that the applet is running in. Its class
varies from browser to browser.
applet parameter A value that is sent into the applet from the HTML document. A parameter has a
name and a value.
AWT applet An applet made with the old AWT graphics system.
CGI Common Gateway Interface. Interface for sending data from a browser, via the Web
server, to an external program on the server machine.
malicious logic Computer program or section of a program that intentionally inflicts damage when
it runs.
sandbox model A virtually blocked-off area in a computer from which programs can't gain access to
important resources.
security manager Object that a Java program can have "installed". It decides what the program has
permission to do.
virus A segment of a computer program that can attach to other computer programs on
the same machine to spread itself. They also usually cause damage.
already drawn, when actually it isn't. Therefore, it's beneficial to call the sync ()
method in a Toolkit object to bringyour program into synchronization with the
windows system. See the java . awt. Toolkit package for details. Take note of
getDefaultToolkit().
Problem 3
Create a continuation of the applet in problem 1 of Section 13.7, with exchange
rates and currencies as parameters. It should thus be able to convert between
different currencies, as specified by the HTML document where the applet is.
This page intentionally left blank
il ,
Socket
Remote object
Callback object
Perform simple socket programming using the class java . net. Socket and
streams
It receives queries from other programs, and it sends queries to other programs.
Compare this to collaboration between objects in Chapter 7.
In this chapter, we will look at how we make client and server programs and how
we get them to communicate with each other.
19.1 Sockets
Computers communicate with each other when data is sent from one machine to
another over a network. A protocol is a set of rules that tells how this data stream will
be sent from the sender and interpreted by the recipient. The Internet Protocol (IP)
describes how computers will communicate with each other over the Internet.
For machines to be able to communicate with each other, they have to be
identifiable. Computers connected to the Internet are identified using an IP address.
Examples of IP addresses are 186.45.34.100 and 156.76.50.237. To avoid
dealing with these numbers, a machine usually also has a name. Examples of
names are java.sun.com and mary.marysHome.dk. If we use the name, the network
software in the computer will look up the corresponding IP address on the
Internet's name service. A database matching names and IP addresses is distributed
on the Internet, and the individual machines know where they should turn for this
type of material.
A socket consists of an IP address and a port number, usually separated by a
colon (for example, mary.marysHome.dk: 100). We use the port number to identify
a specific server application that is running on the machine. Thus, a port in this
context is not a physical port but an entrance to a specific program that is running
on a machine. Familiar server applications like Web servers and database servers
run on specific ports.1
Figure 19.1 shows how a client program sends data to a server program on
another machine. The network operating system gets the stated IP address and thus
finds its way to the machine that is running the server program. The port number
further identifies the program that the data will be sent to.
We will write a very simple server program that communicates with an equally
simple client program. The programs each run on their own machines. The goal is
to show that text the user enters on the one machine can be displayed on the screen
of the other machine. The functionality is as follows:
1. The server program is started on machine A. It waits for queries from a client
program.
2. The client program is started on machine B. It contacts the server program.
3. The server program sends an introductory message to the client program, which
the client program displays on the screen of machine B.
1. Examples of so-called "well-known port numbers" are 80 for Web servers (HTTP), 21 for FTP (file
transfer protocol), 23 for Telnet, and 1521 for Oracle databases. On a UNIX machine, port numbers
under 1000 are reserved for the "super user" roota regular user cannot use these.
19.1 Sockets
4. The client program runs in a loop on machine B, and the user inputs lines of text.
Every individual line of text is sent as a string to the server program. The server
program outputs the text on the screen on machine A.
We use these same classes (InputStrearnReader, etc.) when a program is
going to send and receive data over a network as when it writes and reads data to a
data file.
data
160.99.54.340
Figure 19.1 A client program sends data to a server program over a network
The link between client and server programs is created by instantiating an object of
the java . net. Socket class. Just as with file handling, we link streams to the
Socket object. A program that is going to send data writes to the stream. A
program that is going to receive data reads from the stream.
Program Listing 19.1 shows the server and client programs previously described
(see also Figure 19.2). Notice that the whole program is inside a try-catch
block. This is necessary because quite a bit can go wrong when programs running
on different machines communicate. For example, it can happen that the server
19 Distributed Systems with Socket Programming and RMI
program that the client wants to contact isn't running at all, or maybe the machine
isn't even turned on.
During a test phase, client and server programs can each run in their own Java
interpreter on the same machine. In practice, the machine has to have a network
card installed since the software connected to this is also used when both of the
programs are running on the same machine.
To test the programs, first you should run them both on the same machine.
When that functions perfectly, you should run the two programs on each machine.
Nothing in the source code has to be changed.
Server
Client
Figure 19.2 Server and client programs communicate with each other (UML)
When running on the same machine, the two programs each have to run in their
own window. We assume in the following section that the console window is an
MS-DOS window. If you start the programs from an editor, they will probably start
in their own windows on their own. If you start them from the command line, you
have to write the following to get a separate window to open for the server program:
19.1 Sockets
/*
* SocketClient.java E.L. 2001-08-25
*/
import java.io.*;
import java.net.*;
class SocketClient {
public static void main(String[j args) {
try{
/* Input will be read from the console, see Section 11 .7 */
InputStreamReader readingConnToConsole = new lnputStreamReader(System.in);
BufferedReader fromConsoleReader =
new BufferedReader(readingConnToConsole);
/* Inputs name of the server machine from the user*/
System.out.print("The name of the machine where the server program is running: ");
String serverMachine = fromConsoleReader. readLine();
/* Contacts the server program */
Socket connection = new Socket(serverMachine, 1250);
System.out.println("Now the connection to the server program is established.");
/* Opens streams to the server program */
InputStreamReader readConnection =
new InputStreamReader(connection.getlnputStream());
19.1 Sockets
2. The loop structure for handling multiple clients is derived from (Horstmann, Cornell, 2000 J, page
159. A complete example of this type of server program is also included there.
19.2 Objects That Collaborate over a Network
First we will see what the programs look like, then we will take a look at what
happens behind the scenes and how the relevance to the socket programming
becomes clear. For now, much of what happens at the lower levels will happen
automatically for us so that we can concentrate on objects and messages the way
we're used to.
Every method in the interface has to be able to throw a java. rmi . Remote-
Exception or an exception higher up in the class tree. The reason for this is that
errors can occur at any time in a distributed system, independent of the source
code we write.
If the class is mutable, its methods should be synchronized. In this way there
won't be conflicts if several clients are dealing with the same object.
The default constructor is not sufficient in such a class. All constructors have to
be able to throw RemoteExceptions.
An instance of such a class is automatically given its own thread, to keep the
object alive indefinitely (or until the program that the object belongs to is
aborted). The object is a server object that waits for queries from potential
clients.
A client that is going to send messages to an object has to know the interface for the
object. An interface is specified in a Java interface (cf. Section 12.10). At the
very beginning of Program Listing 19.2, we find the interface that specifies the
counter in Figure 4.4. The implementation (the class) comes immediately
thereafter. Notice the names: the interface is called YesNoCounter, while the
implementation is called YesNoCounterlmpl. In each of the methods, we have
inserted a print statement that gives us a server-side printout each time a client does
something with an instance of this class. When developing distributed systems, it's
always sensible to insert many print statements so that you can trace the activity
precisely on both the server side and the client side.
19 Distributed Systems with Socket Programming and RMI
*/
import java.rmi.*;
interface YesNoCounter extends Remote {
void increaseNumberOfYes() throws RemoteException;
void increaseNumberOfNo() throws RemoteException;
void increaseNumberOfYes(int increase) throws RemoteException;
void increaseNumberOfNo(int increase) throws RemoteException;
int getNumberOfYes() throws RemoteException;
int getNumberOfNo() throws RemoteException;
}
/*
* YesNoCounterlmpl.java E.L. 2001-08-25
V
import java.rmi.*;
import java.rmi.server.*;
class YesNoCounterlmpI extends UnicastRemoteObject implements YesNoCounter {
private int numberOfYes = 0;
private int numberOfNo = 0;
public YesNoCounterlmpl() throws RemoteException {
}
public synchronized void increaseNumberOfYes() throws RemoteException {
System.out.println("The number of yes votes was increased by 1");
numberOfYes++;
}
public synchronized void increaseNumberOfNoO throws RemoteException {
System.out.println("The number of no votes was increased by 1");
numberOfNo++;
}
public synchronized void increaseNumberOfYes(int increase) throws RemoteException {
System.out.println("The number of yes votes was increased by " + increase);
numberOfYes += increase;
}
public synchronized void increaseNumberOfNo(int increase) throws RemoteException {
System.out.println("The number of no votes was increased by" + increase);
numberOfNo += increase;
}
public synchronized int getNumberOfYes() throws RemoteException {
return numberOfYes;
19.2 Objects That Collaborate over a Network
Program Listing 19.3 shows the server program and a very simple client program.
As mentioned earlier, its own thread keeps the object counter active for the
present. A client that sends a message to this object has to locate the object. RMI
provides a bootstrap (= start-up, which makes it possible to start something else
afterwards) registry service for this purpose. For simplicity's sake, we call this registry
the RMI registry.
Once the client has found one object, it can instantiate more objects by sending
messages to the first object. We can also register more than one object in the
bootstrap registry.
Now we will run these programs. Download the whole subdirectory
YesNoCounter from [URL Java book] chapter 19. Open a console window (assume
in the following that this is an MS-DOS window), and move into this directory.
Compile all the programs. The easiest thing to do is to enter:
>javac *.j'ava
Before we run the server program, we have to start the registry service. Enter the
following:
>start rmiregistry
Rmiregistry is a program located in the same directory as Java and javac. Be careful
that the program is started from the same directory where you have all the
YesNoCounter files.
19 Distributed Systems with Socket Programming and RMI
A separate window opens. And nothing else appears to happen. But the program
RMI registry is running in this window without outputting anything. The RMI
registry is running on port 1099.3
Then you can start the server program. You can either do that from the editor,
the way you're used to doing it, or continue to work in the console window:
>start Java CounterServer
As in socket programming, it is important to start the server program in its own
window, since this program's main task is to handle queries from any possible
clients. The output from the program looks like this before any client has
connected:
We'll make a server object
Now it's made!
Now we are just waiting for someone to increase our
counters...
While the thread is what the object counter is running in so that the program
doesn't stop by itself, the following statement is what registers the object in the
bootstrap registry:
Naming.rebind(MCountingsLtd", counter);
The name "CountingsLtd" (note: no spaces) is linked to the counter object by
using the rebind () class method in the Naming class. If the name was
previously linked to another object, this link is terminated. We could also have
used the method bind (). It would have thrown an exception if the name was
used before.
Now we can run the client program:
>java CounterClient
The output from the client program will be:
Number of Yes: 1 Number of No: 1
Number of Yes: 11 Number of No: 21
At the same time, there is more output in the window where the server program is
running:
The number of yes votes was increased by 1
The number of no votes was increased by 1
The number of yes votes was increased by 10
The number of no votes was increased by 20
The client program gains access to the object by looking up the name
"CountingsLtd" in the registry on the machine that is running the server program.
Here it is "localhost", but any machine name or IP address at all can be entered. The
object's complete name in our case is "rmi://localhost/CountingsLtdw.
3. You might also state the port numberfor example, start rmiregistry 1098.
19.2 Objects That Collaborate over a Network
Run the client program several times. What happens? If there are problems, it's
safest to restart both the server program and the registry. In an MS-DOS window,
you stop a program by pressing [CtrlHcl or by closing the window.
/* Example Run:
We'll make a server object
Now it's made!
Now we are just waiting for someone to increase our counters...
The number of yes votes was increased by 1
The number of no votes was increased by 1
The number of yes votes was increased by 1 0
The number of no votes was increased by 20
*/
/*
* CounterClient.java E.L. 2001-08-25
V
import java.rmi.*;
import java.rmi.server.*;
class CounterClient {
public static void main(String[] args) {
String url = "rmi://localhost/";
try{
YesNoCounter counter = (YesNoCounter) Naming.lookup(url + "CountingsLtd");
counter.increaseNumberOfYes();
counter.increaseNumberOfNo();
System.out.println("Number of Yes: " + counter.getNumberOfYes() +
" Number of No: " + counter.getNumberOfNo());
19 Distributed Systems with Socket Programming and RMI
counter.increaseNumberOfYes(10);
counter. increaseNumberOf No(20);
System.out.println("Number of Yes: " + counter.getNumberOfYes() +
" Number of No: " + counter.getNumberOfNo());
} catch (Exception e) {
System.out.println("Error: " + e);
/* Example Run:
Number of Yes: 1 Number of No: 1
Number of Yes: 11 Number of No: 21
V
API Reference
they're being called by a program that is not running on the same machine as the
registry.
public static void unbind(String name)
throws RemoteException, NotBoundException, MalformedURLException
This method takes an object out of the RMI registry.
public static StringO list(String url) throws RemoteException, MalformedURLException
This method returns an array with the names that are registered in the RMI registry.
The argument has to be in the same form as for the method lookup () before.
Problems
1. Change the server program from before so that two counters are registered in the
RMI registry.
2. Make a client program with a graphical user interface that does the following:
The names of all the registered counters (use the method list () in the class
Naming) will be displayed in a list. The user will be able to choose which
counter he wants to update by a certain number of votes. After an update, the
program will retrieve the total number of registered yes and no votes for this
counter. The user interface can, for example, look like the one in Figure 19.3. The
number of votes can be input using a standard dialog.
Run several versions of this client program, and pay attention to the change in
the number of yes and no votes.
The contents of the familiar methods are very strange. For example:
The message invoke () is sent to the object ref. This method takes care of
sending the necessary data to the machine where the object is located. The process
of converting a method call into a form that can be sent over a network is called
marshalling. The word "marshalling" means ordering or arranging. Here we can talk
about the fact that method calls and arguments are ordered or arranged in series
and sent over the network. Conversely, we have a process called unmarshalling. The
series is dismantled, and the actual method call is performed on the real object.
The method invoke () waits for a server-side response ($result). The
method will not return before the server side has sent this value over the network
(cf. the programs from Section 19.1). When this response has come, it is converted
to an integer and thus becomes the return value from the method
getNumberOfYes().
Passing arguments
If client and server are running in the same Java interpreter, the argument values are
always passed in a method call (Section 7.4). Accordingly, values are returned from
a non-void method. If the data type is a primitive data type, the method will work
with a copy of the argument. If the data type is a reference type, the method will get
a copy of the reference but not of the object itself. Therefore, the method can
change this object, which generally has its home in the client program.
This works differently when the arguments are passed from one Java interpreter
to another:
Here we see that we can pass both remote and non-remote objects from one Java
interpreter to another. It is then natural to ask the following question:
The interface Member describes a remote object where a client can change and
retrieve name and address. Parameters and return types are of the classes
Person and String. None of these classes are remote classes. Both of the
classes implement java . io . Serializable, and the objects will therefore
be passed by copies being sent over the network using serialization.
The goal of the interface Member Factory is to make it possible for the client
to make server-side objects. The factory method instantiateMember ()
returns a reference to Member. Here the real object will be a remote object, and
the method therefore returns a proxy object. Here, serialization is not used.
V
import java.rmi.*;
import myLibrary.Person;
interface Member extends Remote {
Person getPerson() throws RemoteException;
void setPerson(Person newPerson) throws RemoteException;
String getAddress() throws RemoteException;
void setAddress(String newAddress) throws RemoteException;
}
interface MemberFactory extends Remote {
Member instantiateMember(Person initPerson, String initAddress)
19.3 How Does Communication Between the Objects Occur?
throws RemoteException;
}
/*
* Memberlmpl.java E.L 2001-08-25
* This class is mutable. All data may be changed.
*/
import java.rmi.*;
import java.rmi. server.*;
import myLibrary.Person;
class Memberlmpl extends UnicastRernoteObject implements Member {
private Person thePerson;
private String theAddress;
public Memberlmpl(Person initPerson, String initAddress) throws RemoteException {
thePerson = initPerson;
theAddress = initAddress;
}
public synchronized Person getPerson() throws RemoteException {
return thePerson;
}
public synchronized void setPerson(Person newPerson) throws RemoteException {
thePerson = newPerson;
}
public synchronized String getAddress() throws RemoteException {
return theAddress;
}
public synchronized void setAddress(String newAddress) throws RemoteException {
theAddress = newAddress;
/*
* MemberServer.java E.L. 2001-08-25
V
import java.rmi.*;
import java.rmi. server.*;
19 Distributed Systems with Socket Programming and RMI
class MemberServer {
public static void main(String[] args) {
try{
MemberFactory factory = new MemberFactorylmpl();
Naming. rebind("MemberFactory", factory);
System.out.println("Waiting for someone asking for Member objects...");
} catch (Exception e) {
System.out.println("Error: " + e);
/* Example Run:
Waiting for someone asking for Member objects...
V
/*
* MemberClient.java E.L 2001-08-25
V
import java.rmi.*;
import java.rmi.server.*;
import myLibrary. Person;
class MemberClient {
public static void main(String[] args) {
String url = "rmi://localhost/";
try{
MemberFactory factory = (MemberFactory) Naming.lookup(url + "MemberFactory");
Person person"! = new Person(100, "Anne", "Smith");
Member memberl = factory.instantiateMember(person1, "7001 Trondheim");
personl .setl_astName("Johnson"); // does not change thePerson variable in
// memberl
Person person2 = memberl .getPerson();
System.out.println(person2.getFirstName() + " " + person2.getLastName());
person2.setLastName("Nilson"); // does not change thePerson variable in memberl
memberl .setPerson(person2); // does change thePerson variable in member1
Person persons = member1 .getPerson();
System.out.println(person3.getFirstName() + " " + person3.getLastName());
} catch (Exception e) {
System.out.printlnfError: " + e);
/* Example Run:
Anne Smith
19.3 How Does Communication Between the Objects Occur?
Anne Nilson
*/
4. The word "deploy" means "to spread out, utilize, or arrange especially strategically" |URL Merriam-
Webster].
A component can be replaced with another component that supports the same
interface.
Our examples are small; therefore the components in our examples are also
relatively small.
Figure 19.4 shows an excerpt of the notation that is used in a deployment
diagram. With the exception of the uppermost box, this notation is also used in
other types of diagrams in UML
component
"...realizesthe interface..."
Figure 19.5 shows a deployment diagram for our simple distributed system.
"CountingsLtd" is the component with an interface declared by YesNoCounter.
We draw the other programs we have to run for our system to work as objects. They
have no particular interface for us to deal with.
The dependence (the arrows) between the components and the objects is
important. We read the following from the figure:
6. A component doesn't need to consist of objects at all. In that case it's usually source code written in
a non-object oriented language that is "wrapped in" as a component.
19 Distributed Systems with Socket Programming and RMI
The application on the client PC assumes that both "CountingsLtd" and the RMI
registry exist.
This tells us something about the order the different programs have to be started
up in. It also tells us whether some of the parts can be removed without this having
consequences for the other parts in the system. These are parts that none of the
others depend on. In this case, it is only the application on the client PC.
: Internet
Figure 19.5 A client PC communicates with an RMI register and the component "Count-
ingsLtd" on the machine server.xxSoft.com (UML)
Problem
Expand Figure 19.5 with a client PC that is running an applet for "CountingsLtd"
The applet is considered to be an object inside the browser object.
19.6 A Distributed System with Callback
The server-side program now has to keep track of which clients are connected.
Therefore, a client must always begin by registering itself. When the server receives
increases in the number of yes or no votes, it has to send a message to all clients
about this.
We could have expanded the interface and implementation from Section 19.2.
However, we are choosing to keep the class YesNoCounter "pure" and instead
make a new interface on the server side, the interface YesNoCounterFront. An
implementation of this interface uses an instance of the class YesNoCounter
from Chapter 4 to keep track of the votes. We don't need to use the "remote"
variant from Section 19.2, since the class YesNoCounterFront takes care of all
communication with the clients.
The first part of Program Listing 19.5 shows the interface for the client-side
object. The server uses this object in the following way:
The message getName () is used to find the name of the client such that, for
example, the text "Now Anne is registered" can be displayed in the server
window.
19 Distributed Systems with Socket Programming and RMI
* Here is the interface of the client object. The counter addresses its request to such
19.6 A Distributed System with Callback
* objects, when all clients are to be alerted about changes in the number of votes.
*/
import java.rmi.*;
import java.rmi.server.*;
public interface Client extends Remote {
String getName() throws RemoteException;
void printStatus(String status) throws RemoteException;
}
/*
* YesNoCounterFront.java E.L. 2001-08-25
The class Client Implimplements the interface Client. Every time a client
connects, an instance of this class is created. The instance runs on the client side.
import java.rmi.*;
import java.rmi.server.*;
import javax.swing.*;
public class Clientlmpl extends UnicastRemoteObject implements Client {
private String name;
private StatusWindow theStatusWindow = new StatusWindowQ;
public Clientlmpl(String initName) throws RemoteException {
name = initName;
theStatusWindow.setVisible(true);
}
public String getName() throws RemoteException {
return name;
/*
* YesNoCounterFrontlmpl.java E.L. 2001-08-25
*
* Here is the "front" implementation at the server side. The clients communicate with
* instances of this class. These instances forward the messages on to instances
* of the YesNoCounter class from ch. 4. The YesNoCounter class is not known
* to the clients.
*/
import java.rmi.*;
import java.rmi.server.*;
import java.util.*;
class YesNoCounterFrontlmpI
extends UnicastRemoteObject implements YesNoCounterFront {
private YesNoCounter theCounter = new YesNoCounter();
private ArrayList allClients = new ArrayList();
19.6 A Distributed System with Callback
/* Resigns a client. Nothing happens if a client with the given name doesn't exist. */
public synchronized void resignMe(String clientName) throws RemoteException {
boolean found = false;
int clientlndex = 0;
while (clientlndex < allClients.size() && Ifound) {
Client thisOne = (Client) allClients.get(clientlndex);
if ((thisOne.getName()).equals(clientName)) {
found = true;
allClients.remove(clientlndex);
System.out.println("Now " + clientName + " is removed.");
} else clientlndex++;
/*
* CounterServer.java E.L. 2001-08-25
*
Naming.rebind(counterName, counter);
System.out.println("Now we're just waiting for someone to update our counters...");
} catch (RemoteException e) {
System.out.println("Error in main() at the server side:" + e);
} catch (java.net.MalformedURLException e) {
System.out.println("lnvalid URL: " + counterName);
/*
* Constants.java E.L. 2001-08-25
*/
interface Constants {
String counterName = "MarysCountingOffice";
int locationStatusWindowX = 200;
int locationStatusWindowY = 500;
int widthStatusWindow = 500;
int heightStatusWindow = 80;
int locationCountWindowX = 200;
int locationCountWindowY = 200;
}
Let's look a little more closely at the client side. We have already gone through the
interface Client and its implementations. Let's start with the main program. It's
shown in Program Listing 19.7. The program starts by letting the user enter the
name of the machine where the server is running. It's easy to enter the wrong
machine name. Therefore, we have been extra careful with exception handling
here, and we also let the program run in a loop until we successfully contact the
server. Then the client will enter its own name. These two dialogs are shown in
Figure 19.6.
Further on, we create an instance of the class Clientlmpl:
Client thisClient = new Clientlmpl(clientName);
The server will use this object when it goes to send messages back to the client. We
don't need to register this object in any RMI registry. We will send it over to the
server as an argument when we register ourselves there:
counter. registerMe(thisClient);
Therefore, in this distributed system it's sufficient that an RMI registry is running
on the machine where the server program is running, even if we also have remote
objects on other machines.
Finally, in main ( ) we get the registration window as shown in Figure 19.7.
Program Listing 19.8 shows the two classes that handle the user interface. The
classes don't contain anything new. However, we program the window closing
ourselves:
setDefaultCloseOperation(WindowConstants.DO__NOTHING_ON_CLOSE);
The closing event is handled as follows:
In the class CounterWindow, closing will lead to the client exiting the registry
that the counter maintains. Then the whole program is stopped with
System.exit(0);
In the class StatusWindow, nothing will happen if the user tries to close the
window. The user has to quit the program by closing the counter window.
/*
* StatusWindow.java E.L. 2001-08-25
* This window is used at the client side for showing status information,
* received from the server side. It's not possible to close the window. The user has to
* exit the application by closing the CounterWindow, then he is disconnected
* from the server, too. And this window is closed.
*/
import javax.swing.*;
import javax.swing. border.*;
import java.awt.event.*;
import java.awt.*;
class StatusWindow extends J Frame implements Constants{
private JLabel text = new JLabel("No message from the server yet.");
public StatusWindow() {
setTitle("Status");
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
Container guiContainer = getContentPane();
text.setForeground(Color.black);
guiContainer.add(new JLabel(), BorderLayout.NORTH);
guiContainer.addjtext, BorderLayout.CENTER);
guiContainer.add(new JLabel(), BorderLayout.SOUTH);
setl_ocation(locationStatusWindowX, locationStatusWindowY);
setSize(widthStatusWindow, heightStatusWindow);
}
public void setStatus(String newStatus) {
text.setText(" " + newStatus);
19 Distributed Systems with Socket Programming and RMI
Problems
1. Expand the functionality of the programs in this section so that a client can access
the names of all connected clients. Test this in the simplest way.
2. In addition, make it possible for a client to send a message to another client. Test
this in the simplest way.
callback An object on the client side that makes it possible for the server to send messages back to
(object) the client.
component A UML component is in many ways "bigger" than an object It forms a physical unit that,
together with other components, makes up a larger system. It can be replaced by another
component that supports the same interface.
deployment A UML diagram that shows the lines of communication between the different machines
diagram (the nodes) in a distributed system, and how the different programs, objects and
components that run these machines are dependent on each other.
IP Internet Protocolthe protocol that applies for transferring data between machines on the
Internet.
IP address A series of numbers separated by periods that identifies a machine in the large network
that forms the Internet.
marshalling To package object identification, method calls, and arguments so that they can be sent
over a network.
name service A service that makes it possible to use names instead of numbersfor example, to identify
the different machines on the Internet.
port A number that can be used from outside to identify a program that is running on a
machine.
protocol A set of rules that for example tells how a data stream will be sent from the sender and
interpreted by the recipient.
proxy (object) This is an object that is used on the client side to send method calls and arguments over to
the real object on the server side. The object is created automatically, and whoever is
programming the client can deal with the proxy as if it were the real object.
RMI Remote Method Invocation. A technique in Java that makes it possible to let objects
communicate with each other over a network.
RMI registry The registry runs as a server program and contains references to named remote objects. It
is usually used to identify an object that makes it possible for a client to access this and
other objects over a network.
socket Consists of an IP address (or name) and a port number; identifies a program that is
running on a machine in a network.
unmarshalling Unpacking the object identification, the method call, and the arguments that have come
in over a network; the opposite of marshalling.
A client will be able to connect to a running server program and choose between
printing out the whole file and inserting new names.
Let the server program run in an endless loop, where each run-through waits for
a client to connect. Test what happens if several clients try to connect at the same
time.
Problem 2
Adapt the class Calculator from Section 5.1 so that it can run on the server side
in an RMI system. Make whatever is necessary to test the class.
Problem 3
Make a simple lending system for books. Use RMI.
A book is identified by its ISBN, and we can have several copies of each book.
The class that describes the book will also contain the title and author.
We need to have a book registry on the server side.
For the sake of simplicity, we will not have an author registry or a registry of
borrowers.
Make a separate client program to register new books and new copies of books
that are already registered.
Make another client application that takes care of lending out and returning
books:
When a book is loaned out, the librarian will enter the ISBN, copy number, and
name of the borrower. If the book is already out on loan, the librarian will get
a message about this. The book can be reserved by one person. Note that the
reservation is made for the book and not for a specific copy of it.
When a book is returned, the librarian will enter the ISBN and copy number. If
the book is reserved, information will come up about that so that the client can
set the book aside.
Assume that reserved books are not sitting out, available for borrowing.
Problem 4
Make a chat program using RMI.
The server program will keep track of who is participating in the conversation
and send out information to the individual client about what the others are saying
(use callback).
A user that wants to participate in the conversation starts the client program and
registers with a name.
The client program has to quit the conversation before the program exit.
19.9 Programming Problems
Problem 5
Make a distributed system using RMI. The system will make it possible to play
Mastermind over a network.
You will make a server program that can play Mastermind with several clients at
the same time. A client program will also be created, preferably with a graphical
user interface.
Database driver
JDBC
Three-layer architecture
Send SQL statements for database queries and updates, and interpret what you
get back
Use the right Java data type compared to the SQL data type used
Quite a few of today's software systems work with one or more databases. Users
retrieve data, modify data, and add new data. Systems like this almost always use
what we call Database Management Systems (DBMS), or "database systems" for
short. A database system does a great deal more than "keep track of data"large
parts of the system also take care of different types of security.
Visual tools such as "point and click" and "drag and drop" are often used to set
up the connection between a user interface and a database when developing
software that uses a database system. Microsoft Access is an example of a combined
tool and database system. These visual tools also usually require a good deal of
programming to get the system the way we want it.
20 Programming with Databases
The driver is an adaptor from JDBC to ODBC. ODBC takes care of the
communication with the database. This sort of driver is called a /DBC-ODBC
Bridge.
The driver is specially created for the database system we are programming for.
Figure 20.1 A Java program communicates with a database through a database driver. A
slightly revised version of the figure 23-2, p. 528 in [Orfali, Harkey 1998]. Reproduced by
permission of John Wiley & Sons, Inc.
capital and lower-case letters, "Edward Brown" and "edward Brown" will be
considered two different people by the database system, even if the latter was
probably just a typo.
Program Listing 20.1 shows a Java program that connects to the database and
retrieves all the data stored there. (See the printout at the bottom.)
/* Example Run:
100: EDWARD BROWN
101: ANN MARGARET GREEN
102: JOHN JOHNSON
V
Let's go through the code line by line. The classes we use in connection with
database management are in the java . sql package:
import java.sql.*;
20.2 Establishing Contact with a Database
We see that main () throws any possible exceptions on without handling them.
This (or try-catch) is necessary because all database calls can throw
java.sql.SQLException.
First we have to register the driver we're going to use. The easiest way to do that
is:
String databaseDriver = "oracle.jdbc.driver.OracleDriver";
Class.forName(databaseDriver);
The forName () method is a class method in the Class class. It says that we will
load in a class named oracle . jdbc . driver .OracleDriver. (If we look
at the contents of the file collection dasseslll.zip, we'll find the file
OracleDriver. class in the oracle/'jdbc/driver subdirectory, which conforms to the class
name.)
The next step is to set up a connection to the database:
String userName = JOptionPane.showlnputDialog(User Name:");
String password = JOptionPane.showlnputDialog("Password:");
String databaseName = "jdbc:oracle:thin:@loiosh.stud.idb.hist.no:1521 :orcl";
Connection conn
= DriverManager.getConnection(databaseName, userName, password);
We input the user name and password from the user and open the connection
to an Oracle database that's running on port 1521 on a machine named
loiosh.stud.idb.hist.no.
/* In this case, neither user name nor password is set, but they'll be the two last
arguments to the getConnection() method */
Connection conn = DriverManager.getConnection(databaseName,"","");
20 Programming with Databases
Now we're done with the database system specific aspect. The program will retrieve
all the data in the person table and display it on the screen. The following SQL
statement does the job:
select * from person;
We'll send this statement to the database. We have to begin by instantiating a
Statement object linked to the database connection:
Statement statement = conn.createStatement();
SQL statements that manipulate data are usually divided into two groups: the select
statement that's used to search in the database, and the other statements (insert,
update, and delete) which are used to change the contents of the database. The
latter group of statements can be executed by sending the message
executeUpdate () to the Statement object. We'll see an example of this in
the next section. Now we'll execute a select statement by sending the message
executeQuery () to the Statement object:
ResultSet res = statement.executeQuery("select * from person");
res is an instance of the ResultSet class. The result from a select statement is
usually several rows of data. We use the next () method to run through all the
rows:
while (res.next()) {
int idNo = res.getlntfidentNo");
String firstName = res.getString("firstname");
String lastName = res.getString("lastname");
System.out.println(idNo + ":" + firstName + "" + lastName);
}
Notice that we also have to use next () to get hold of the first row. For every row
we have to retrieve the data value in each individual column. We use
getString () for strings, getlnt () for integers, getDouble () for decimal
numerals, etc. Table 20.1 shows the relationship between data types in SQL and in
Java, and also which getxxx() method should be used in the various situations.
The last thing we do is to release the database resources:
res.close();
statement.close();
conn.close();
20.2 Establishing Contact with a Database
Table 20.1 The relationship between SQL data type, Java data types, and getxxx() methods
Even now we can suspect that problems arise because we're not working with an
object database. To save a person object, we have to take it apart into identification
number, first name, and last name, and make table rows from these. To retrieve an
object, we have to retrieve each individual data value and create an object from
these data values. Here, we only write out the values, but we could also create an
object, like this:
Person aPerson = new Person(identNo, firstName, lastName);
20 Programming with Databases
There are pure object databases and there are also object-like extensions of many
of the traditional database systems. This makes it possible to deal with the object
model when we save data as well (cf. serialization). But there is very little to suggest
that the use of relational databases is diminishing; therefore we are prioritizing this
type of database in this brief introduction to the topic of "programming with
databases".
API Reference
All of the methods throw an SQLExcept ion if an error code is returned from the
database system or another error occurs in connection with the database
management.
The Java. sql.DriverManager class
This class manages the database drivers. It's possible to have multiple database
drivers registered (see the online API documentation).
Method:
public static Connection getConnection(String databaseUrl,
String userName, String password)
This method tries to establish a connection to the database indicated and choose
an appropriate database driver from the drivers that are registered. The method
returns a reference to a Connection object (see below).
The Java.sql.Connection interface
This interface is implemented in the database driver.
Methods:
public void close()
This method closes the connection to the database. Any Statement and
ResultSet object that's open is also closed. Associated database resources are
released.
public Statement createStatement()
This method creates a Statement object that can be used to send SQL statements
to the database.
In the API Reference in Section 20.6, you'll find more methods for this interface.
The Java.sql.Statement interface
This interface is implemented in the database driver.
Methods:
public void closeQ
20.2 Establishing Contact with a Database
This method closes the Statement object and also any open ResultSet
objects. Associated database resources are released.
public ResultSet executeQuery(String sqIStatement)
This method closes any open ResultSet objects, executes a select statement, and
returns the result in a new ResultSet object.
public int executeUpdate(String sqIStatement)
This method executes an insert, update, or delete statement. The number of table
rows affected is returned. We can also use this method to execute SQL statements
that don't return anything, for example "create table." In these cases, the method
will return 0.
The Java.sql.ResultSet interface
This interface is implemented in the database driver. An instance of a class that
implements this interface will contain the result from a select statement (see the
executeQuery () method above).
Methods:
public void close()
This method closes the ResultSet object with associated database resources,
public boolean next()
This method moves the row pointer forward a row in the result set. Before the first
call to next (), the row pointer is positioned before the first row. Thus, next ()
has to be called once in order to access thefirstrow.
public xxx getxxx(String columnName)
See table 20.1 for a synopsis of xxx's possible values. The methods retrieve a value
from the row the pointer is pointing to (see the description of the next () method
above). The column name determines which value will be retrieved. If the value is
SQL NULL (an empty field in the database) 0, null, or false is returned,
depending on the data type.
public xxx getxxx(int columnNo)
This is equivalent to the method above, but takes the column number instead of
the column name as its argument. The columns are numbered starting with 1.
public Object getObject(String columnName)
In a way, this replaces all the getxxx () methods. It retrieves the value and saves
it in a wrapper object of a suitable type (Integer, Double, etc.).
public boolean wasNull()
This method returns true if the last value read was SQL NULL. It might be
necessary to use this if, for example, the get Int () method returns 0. (Otherwise,
20 Programming with Databases
would that mean that the field in the database contained the value 0, or was the
field empty?)
Problem
1. The SQL statement
select identno, firstname from person where lastname = 'JOHNSON';
gives us the identification number and first name of all persons with the last
name Johnson. Change Program Listing 20.1 so that the program executes this
SQL statement. Remember, the SQL-string has to contain single quotes.
2. Then change the program so that it runs in a loop and inputs different last names
from the user.
Database
getAII()
updateName(thePerson: Person)
regteterNewPerson(firstName: String, lastName: String)
deletePereon(identNo: int)
closeTheConnection()
The class and test program are shown in Program Listing 20.2. Let's go through the
Database class. The class is in the myLibrary package, and it uses the Person
class (Program Listing 15.5) in the same package.
The constructor sets up the database connection and creates a Statement
object. The database connection is, and has to be, an instance variable. All the
operations to the database use the same database connection. The Statement
object is an instance variable for efficiency reasons. In our case it's not necessary to
instantiate a new Statement object every time an operation to the database is
20.3 A Bigger Example
import java.sql.*;
import myLibrary. Person;
public class Database {
private static final String databaseDriver = "oracle.jdbc.driver.OracleDriver";
private static final String databaseName
= "jdbc:oracle:thin:@loiosh.stud.idb.hist.no:1521 :orcl";
private Connection conn;
private Statement statement;
/* The code if one tries to store more than one person with the same ident.no.*/
private static final int code = 1 ; // Oracle return code
* Returns an array list with all the data from the person table.
* The list is sorted with respect to the last name.
V
public ArrayList getAII() throws SQLException {
Array List all = new ArrayList();
String sqIStmt = "select * from person order by lastName, firstName";
System.out.println("** From the Database class: " + sqIStmt);
ResultSet res = null;
try {
res = statement.executeQuery(sqlStmt);
while (res.next()) {
int identNo = res.getlnt("identno");
String firstName = res.getString("firstname");
String lastName = res.getString("lastname");
Person thePerson = new Person(identNo, convert(firstName),
convert(lastName)); // convert, private method, see below
20.3 A Bigger Example
all.add(thePerson);
}
} finally { // the statements below are executed regardless of exceptions thrown
/* Releases database resources, in every case, also if exceptions are thrown. *l
if (res != null) res.close();
return all;
/*
* updates the name of a person in the database.
* Returns false if no persons with this identno. exist.
*/
public boolean updateName(Person thePerson) throws SQLException {
int identNo = thePerson.getPersldent();
String newFirstName = thePerson.getFirstName().toUpperCase();
String newLastName = thePerson.getLastName().toUpperCase();
String sqIStmt = "update person set firstname = '" + newFirstName
+ '", lastname = '" + newLastName + "' where identno = " + identNo;
System.out.println("** From the Database class: " + sqIStmt);
if (statement.executeUpdate(sqlStmt) == 0) return false;
else return true;
}
/*
* Stores a new person in the database.
* Identno. is assigned by the method. If this is the first person to be registered,
* she'll get number 1 . Other persons get a number equal to 1 + max. no. until now.
* (Data may be deleted, this method may therefore give holes in the number
* sequence.)
*/
public Person registerNewPerson(String firstName, String lastName)
throws SQLException {
firstName = firstName.toUpperCase();
lastName = lastName.toUpperCase();
int newldentNo = 1 ; // if no persons in the database
boolean ok = true;
do{
ResultSet res = null;
try{
String sqIStmt = "select max(identno) as maxno from person";
res = statement.executeQuery(sqlStmt);
if (res.next()) newldentNo = res.getlnt("maxno") + 1 ;
sqIStmt = "insert into person values(" + newldentNo + ", '"
+ firstName + "', '" + lastName + '")";
System.out.println("** From the Database class: " + sqIStmt);
statement.executeUpdate(sqlStmt);
} catch (SQLException e) {
/* If the error code means that a person with this no. already exists,
20 Programming with Databases
another client must have stored this person in between our two sql statements.
We therefore rerun the do loop. (This happens very rarely.) */
if (e.getErrorCode() == code) ok = false;
else throw e;
} finally {
if (res != null) res.close();
}
} while (!ok);
return new Person(newldentNo, firstName, lastName);
}
/*
* Deletes a person with a given identno.
*/
public boolean deletePerson(int identNo) throws SQLException {
String sqIStmt = "delete from person where identno = " + identNo;
System.out.println("** From the Database class: " + sqIStmt);
if (statement.executeUpdate(sqlStmt) == 0) return false;
else return true;
}
/*
* Converts a name from the database (only capital letters) into a string
* having a capital letter at the beginning of each word (as usual for names).
*/
private String convert(String text) {
String newText = "";
StringTokenizer theText = new StringTokenizer(text);
while (theText.hasMoreTokens())) {
String s = theText.nextToken();
newText += s.substring(0, 1);
if (s.length() > 0) newText += s.substring(1).toLowerCase() + " ";
}
newText = newText.trim();
return newText;
/*
* DatabaseTest.java E.L. 2001-08-26
V
import javax.swing.*;
import java.util.*;
import myLibrary.*; // Person and Database
class DatabaseTest {
public static void main(String args) throws Exception {
String userName = JOptionPane.showlnputDialog("User Name: ");
String password = JOptionPane.showlnputDialog("Password: ");
Database db = new Database(userName, password);
20.3 A Bigger Example
/* Example Run, the person table contains the data from the script in Section 20.2.
** From the Database class: A connection to the database is established.
Get all:
** From the Database class: select * from person order by lastName, firstName
100: Brown, Edward
101 : Green, Ann Margaret
102: Johnson, John
20 Programming with Databases
Problem
Make a method in the Database class that finds all the different last names.
can work with the database at the same time, it's still not definite that the list will
reflect the exact contents of the database. The "Refresh" button fills the list with
"fresh" data from the database.
* The primary window in this GUI application shows all the data in the person table.
* The user may choose to update data, delete data or add new data to the database.
* If updates were accepted by the database, they are also reflected in the primary
* window. To reflect database updates done by other users, the user has to click on
* the "Refresh" button.
*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.text.*;
import myLibrary.*;
20 Programming with Databases
/*
* Here follow the three panels describing the user interface.
V
private class HeadingPanel extends JPanel {
20.4 A Database Application
/*
* This class handles all the button clicks.
V
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
JButton source = (JButton) event.getSource();
if (source == deleteButton) { // Deletes a person
Person thePerson = (Person) list.getSelectedValue();
try{
boolean deleted = theDatabaseContact.deletePerson(thePerson.getPersldent());
if (deleted) {
listData.remove(list.getSelectedlndex());
if (HstData.size() == 0) {
20 Programming with Databases
deleteButton.setEnabled(false);
editButton.setEnabled(false);
}
else list.setSelectedlndex(0);
} else {
JOptionPane.showMessageDialog(null, "Not possible to delete this person." +
"Other clients may have done it already.");
}
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "Error when deleting: " + e);
class DatabaseApplication {
public static void main(String[] args) {
Database theDatabaseContact = null;
try{
String userName = JOptionPane.showlnputDialogfUser Name: ");
String password = JOptionPane.showlnputDialog("Password: ");
theDatabaseContact = new Database(userName, password);
} catch (Exception e) {
JOptionPane.showMessageDialog(null,
"Problems when establishing database connection, " +
"the user name or the password may be invalid. \nError: " + e);
try{
// disconnects what may be disconnected
theDatabaseContact.closeTheConnection();
} catch (Exception e1 ) {
}
System. exit(0);
}
DatabaseGUI theApplication = new DatabaseGUI(theDatabaseContact);
theApplication.setVisible(true);
Problem
Assume that the names (in addition to the numbers) in our person database are
unambiguous. Expand the Database class with the method
int getPerson(String firstName, String lastName)
which returns the identification number of the person with this name, if found in
the database. If not found, the method should return a negative number.
20 Programming with Databases
Write an application that inputs a name from the user and finds out whether it's
registered in the database. If it's not registered, it will be inserted into the database.
database
A
Figure 20.4 The distribution of the components in the database application (UML)
In our case, we have two of the layers running on the same machine. This is a rather
"thick client". Often the layers are distributed on different machines. RMI may help
20.6 Transactions and Compiled SQL Statements
person who will be added to the database will have. We use the SQL function
max () to find the largest number up to this point. The new number will be 1 larger
than this. Now if another client succeeds in registering a new person before we've
inserted ours, our number will already be taken in and the database system will
protest. An exception object is thrown and we set ok equal to false. Then the
program will ask the database once more for the largest number used so far.
This method of handling transactions builds on the fact that the probability of
two or more clients accessing the same data at the same time is negligible. This
solution therefore requires very few resources.
But notice that the method can't always be used. The account update example
demonstrates this. The program code for the account example is shown as the
solution to problem 1 after this section.
Compiled SQL statements
An SQL statement has to be compiled by the database system before it is run. The
database system also sets up a plan so that the search can be done in the most
efficient way possible. If you send the same statement many times, you'll save u'me
by making these preparations only once. We can replace constant values in the
statement without compiling it again.
We can make a compiled Statement object using the PreparedSta-
tement class: see Program Listing 20.4.
The SQL statement contains two question marks:
select * from person where firstName like ? and lastName like ?
Here we get the persons that satisfy specific search criteria. The program runs in a
loop and constantly asks the user for new first and last name search criteria. We put
in the search criteria in place of the question marks:
statement.setString(1, searchCritFirstName.toUpperCaseO);
statement.setString(2, searchCritLastName.toUpperCase());
The first question mark is number 1. We can use the wildcard symbol in the search
criteria. % means any sequence of characters, while _ means exactly one character.l
The search criteria (three underline characters) for the first name and h% for
the last name give us all the names that have first names with exactly three letters
and last names that start with H.
API Reference
1. These wildcard symbols are standard SQL, but not all database systems follow the standard exactly
on this point.
20.6 Transactions and Compiled SQL Statements
Methods:
public void setAutoCommit(boolean autocommit)
We turn autocommit off by sending this message with the argument false to the
database connection. It's important to remember to turn autocommit on again
(same message with the argument true) when we no longer need to deal with
transactions that consist of more than one SQL statement.
public void commit()
This method makes all the changes that have occurred since the last commit () /
rollback () permanent. All the locks that this connection holds are released.
This method should only be used if autocommit is turned off.
public void rollbackQ
This method cancels all changes since the last commit () /rollback (). All the
locks this connection holds are released. This method should only be used if
autocommit is turned off.
public PreparedStatement prepareStatement(String sql)
This method makes a compiled SQL statement. If the same statement is going to be
executed more than once, it pays to compile it first.
The Java.sql.PreparedStatement interface
The database driver implements this interface. The interface is a subinterface of
j ava.sql.Statement.
Methods:
public ResultSet executeQueryQ
This method executes the compiled select statement. The result is returned as an
ResultSet object.
public int executeUpdate()
This method executes the compiled insert, update, or delete statement. It returns
the number of table rows affected. This method can also be used to execute SQL
statements that don't return anythingfor example, create table. In these cases, the
method will return 0.
public void setlnt(int questionMarkNo, int x)
public void setLong(int questionMarkNo, long x)
public void setString(int questionMarkNo, String text)
These are three of the methods in a family of methods used to give values to the
question marks (called parameters) in the SQL statement. The first question mark
has number 1. For the relationship between the SQL data types, Java data types, and
method names, see table 20.1.
20 Programming with Databases
/* Example Run:
The Search Criteria: %
EDWARD BROWN
ANN MARGARET GREEN
The Search Criteria: % %n
EDWARD BROWN
20.7 New Concepts in This Chapter
Problems
1. Write an SQL script that sets up a table of accounts in a database. It should
contain account numbers, names, and balances. Put in three accounts. Then
make a single program that tests the transaction example described above.
2. Modify the Database class in Program Listing 20.2 so that all SQL statements
are compiled beforehand.
database driver Software that makes it possible to use JDBC on a specific database system.
DBMS Database Management System. "A software system that enables users to define, create, and
maintain the database and provides controlled access to this database." [Connolly, Begg,
Strachan 1999, p, 16]
JDBC lava Database Connectivity. The part of the Java API that's used to communicate with
relational databases.
JDBC-ODBC An adaptor from JDBC to ODBC. ODBC takes care of the communication with the database.
Bridge
ODBC Open Database Connectivity. An API for database systems, created by Microsoft.
SQL Structured Query Language. Standard query language for relational databases.
three-layer The principle of dividing a software system into three layers; often the bottom layer is the
architecture database, and the top layer is the user interface. In between we have software for the problem
domain, which may be divided further ("n-layer architecture"). One layer communicates
only with the layer directly above and/or below, not with the others.
A student can take a course more than once. The best grade counts.
There will be two types of clients:
20.9 Programming Problems
1. One client that has all the privileges including updating, modifying and deleting
all data. This client logs in as an ordinary database user.
2. One client that can only look at the grades. This could be a student. Each student
has his own password and is only allowed to look at his own data.
What each individual has access to can be controlled by creating an SQL view
and setting privileges and a password linked to these. Find out what you can
accomplish with the database system you're using. In a test phase you can input the
student's password as an extra column in the student table. In this case, database
log-in can be hard coded (!) in the program.
Make a class (or classes) that communicates with the database. Test the class by
writing a simple test program.
Think of a suitable user interface for both types of clients. Emphasize simplicity.
Implement the user interface.
Problem 4
(This problem was written by Simon Thoresen.)
Use javax. swing. JOpt ionPane to program a database client. This client
will be able to execute any SQL statement entered by the user.
It should be "transparent" to the user how the program sends the call to the
database (executeQuery () or executeUpdate ( ) ) .
The client has to be able to produce a reasonable output for a query (select
statements) with the right headers for each column. The Result Set class
provides a getMetaData () method that returns a ResultSetMetaData
object. This object contains the necessary information about the table columns.
For updates, it's enough to print out the return value from
executeUpdate().
This page intentionally left blank
Programming
Maintain state information for the client (cookies) and the server (session
object)
Despite the fact that Java's usability on the Internet led to its enormous popularity,
very few of the programs in this book have been specially designed for this
purpose. We've focused on creating ready-made classes that can be used in many
different contexts. The client program could be a simple test program, or a
traditional menu-driven program, or we can place a graphical user interface over
the classes. Of course this graphical user interface can be an applet, and then we
instantly have a program that is specially designed for the Internet.
You have certainly used the Internet to find hotels, for example. You enter the
city and get back a list of possible hotels. The source code for this page shows the
names of the hotels in plain text. Why doesn't the page contain program logic that
searches for the hotels in a database? The answer is that the HTML code is specially
adapted. The Web server receives your query for hotels in a specific city, sends this
21 Web Programming with JavaServer Pages
query to a program that searches the database, and generates HTML code with the
applicable hotels. This code is then sent to the client in response to the query.
Compared to applets, this requires a completely different way of programming.
The program runs on the Web server, not in the client's Web browser. These types
of programs are the main topic of this chapter. We are still using our ready-made
classes, but now with a new type of client program.
Consider this chapter an introduction, and refer to [Annunziato, Kaminaris
2001] and [Hall 2000], for example, to study the topic in more detail.
As we will see, a jsp file will be converted to a Java servlet class. The servlet's
source code is in a Java file, which is compiled automatically. The compilation
errors refer to the line number in the Java file, and therefore it's beneficial for
these not to be deleted. You avoid this by opening the <LWS-home>/config/
examples/servlets.properties file in an editor and changing keepgener-
ated=false to keepgenerated=true (at the very end of the file).
In Section 21.9, we'll create pages that maintain state information without using
cookies. Line 8 in the <LWS-home>/config/examples/session.properties file looks
like: enable . urlrewriting=false You should change false to true
here as well.
A server program has to know where the files it will use are. For LWS, the
following apply if you don't make special adjustments in the configuration files:
The Java files generated automatically from translating the jsp files will be placed
in the <LWS-home>/work/examples subdirectory.
You'll have the other java files you use, such as for example the Database class
from Chapter 20, in the myLibrary package. You'll be reminded of this when
the time comes to run the examples.
Stop the Web server. Remember to use the admin page (http://localhost:9090/
admin, press "Shutdown") if you're using LWS.
Delete automatically generated java and class files. LWS: Look at the <LWS-
home>/ work/examples directory. Remember that nothing will happen if you delete
too many of these files. They will be recreated as necessary.
Start the Web server again. LWS: If you've followed the installation instructions,
entering Iws in the command line should suffice.
21.3 Servlets
A servlet is a Java program that runs on a Web server. Servlets have certain traits in
common with applets. While the browser creates the applet objects, the servlet
objects are created by the Web server. Both types of objects have an init ()
method that is run once. When the user moves in and out of the Web page that
contains an applet, the messages stop () and start () are sent to the applet
object (see Figure 18.2). Every time a client requests a servlet object, the
service ( ) message is sent to the object in question (see Figure 21.1). There is,
however, a substantial difference:
An applet object is created and lives inside the client's browser and is therefore
used by only one user.
21.3 Sen/lets
A servlet object is created by the Web server and is running there. The same
object can therefore be used by many clients.
Note that all the clients work with the same servlet object. Therefore, any instance
variables there might be can be updated by multiple clients. Methods that work
with the instance variables should therefore be synchronized. 1 In particular it
should be mentioned that the java . u t i l . A r r a y L i s t class is not
synchronized. I n s t e a d , t h e r o u g h l y i d e n t i c a l , b u t s y n c h r o n i z e d ,
java. unti1. Vector class should be used.
API Reference
1. Which is to say that the code will be "thread safe". Servlet code should have this trait for efficiency
reasons. The page directive (see Section 21.5) can be used if the code does not have this trait: <%3
page isThreadSafe="false" %>.
21.3 Servlets
This method is called by the Web server and it interprets the query and then calls
doGet ( ) ordoPost ( ) .
protected void doGet(HttpServletRequest request, HttpServletResponse response)
protected void doPost(HttpServletRequest request, HttpServletResponse response)
These methods are called by the service () method.
Program Listing 21.1 shows a servlet that prints out the date and time in the client-
side browser (see Figure 21.2).
The example uses the response object to indicate that it's HTML code that is
being sent, and also to retrieve a PrintWriter object that can be used to send
data back to the client. Notice how the HTML codes are created with
out. print () and out .println (). The new line, which is a result of
print In (), will be included in the HTML code that results. To get a new line to
appear in the browser, we have to send the HTML element "<br>" to the out
object:
out.print("<br>This text is on a line of its own.<br>");
We could also use " <p>" for a new paragraph.
For the example to generate something more than a static HTML code, we've
included the time on the server machine:
out.println("This page was downloaded:" + new java.util.DateQ);
This is sent in plain text to the out object: see the result in the figure.
We've not used the request object in the example, but it contains information
about the client and also, for example, data the user has entered into data fields.
Program Listing 21.1
/*
* SimpleServlet.java E.L. 2001-08-27
*/
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class SimpleServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, lOException {
response.setContentType("text/html");
PrintWriter out = response.getWriterQ;
out.print("<html>");
out.print("<head>");
out.print("<title>An example of server side programming</title>");
out.println("</head>");
out.println("<body>");
21 Web Programming with JavaServer Pages
Problems
The main goal of these problems is for you to understand what's involved in the
concept of server-side Web programming. You run the Web server on your own
machine and you will also be able to test all the servlets by opening all the pages in
the browser on your own machine. In addition, it will be beneficial to download
the pages at least once on another machine besides your own. This will allow you
to see on your own that this does work over the Internet.
1. Copy the source code in Program Listing 21.1 to the right location on your
computer. It should go in the directory for servlets. Compile.2 Then open the
servlet in your browser. Make sure that you understand what's happening on the
server side and what's happening on the client side. Check the source code in the
browser.
2. It may happen that you have to make sure that CLASSPATH contains servlet.jar. The servlet.jar file is
located where the Web server is.
21.4 JavaServer Pages (JSP)
2. Change the source code so that, in addition to the time, it outputs five random
numbers. For your change to take effect, you have to stop the servlet from
problem 1 and start it again. To find out how to do this, you need to study the
documentation for the Web server. Alternatively, you can stop the Web server
and start it up again.
3. When a browser requests a Web page, it sends along some information about
itself, for example the name of the computer it's on. The computer name can be
accessed by sending the message getRemoteHostQ to the request object.
Try this and output the result on the server side using S y s t e m .
out.println().
3. Our Web server, LWS, creates a file that we will find in the work/examples subdirectory. The file name
is long and detailed, but for this example, it includes the text "time_JSP", because the jsp file is named
time. jsp. If you have several files like this, look at the dates to find the most recent one.
21 Web Programming with JavaServer Pages
response parameters. We also find the variable out, which is used in writing the
HTML codes.
Right from the start it may seem as if most of the advantage to using JSP instead
of writing our own servlets is not having to write out. print In () around the
HTML elements.
A jsp file will, for the most part, contain HTML code. As with other HTML files,
therefore, the presentation will be the main purpose. In several places in this book,
we have demonstrated the importance of differentiating the user interface from the
problem we are solving. The same problem can be presented with several different
user interfaces. A potential user interface can be specified by HTML codes. We can
also imagine other "markup" languages (see Appendix E.1). One example is
Wireless Markup Language, WML, for use on mobile phones that support Wireless
Application Protocol, WAP.
By using JSP, we can let Web designers use their own tools to generate an
appealing design while we can create regular Java classes that cover most of the
programming. Only smaller "snippets" of Java code are needed in the jsp file. With
a few programming skills, Web designers can learn to put some of these in place
themselves.
The examples in this book, however, will emphasize the JSP code over design.
Most of the examples will therefore contain more JSP than HTML.
Nevertheless, to understand the examples and to solve the problems in this
chapter, you'll need to know more about HTML than Appendix E tells you. You
probably will need a reference such as [URL W3C] and perhaps a textbook like
[Deitel, Deitel, Nieto 2000].
That having been said, it's not a disadvantage, of course, that the quantity of
code we need to write when we write a jsp file is quite a bit less than for an
equivalent servlet. And this is true not just for generating the HTML code. We will
see that JSP also offers us several other "shortcuts".
Problems
1. Insert the sample file from Program Listing 21.2 into the right place and retrieve
it in your browser. Check that you're finding the automatically generated java
file. Open it in an editor and check to see that you recognize some of the code.
2. Change one of the texts in the sample file and check that you can see the change
in the browser. This should work on its own. If you have problems, see the last
part of Section 21.2.
Predefined objects
When we write JSP code, we can use the following objects directly:
request
This object describes the client's request, and it belongs to the
HttpServletRequest type, which is a subinterface of ServletRequest.
The most important methods are described in the API references in Section 21.6
and 21.9.
response
This object describes the response the Web server will send to the client, and it
belongs to the HttpServletResponse type. We don't use this object much
(see the online API documentation for more information).
out
This object is an instance of the PrintWriter class and makes it possible to
write directly to the client's HTML page (API reference, see Section 11.5).
session
This object describes the client's session (see Section 21.9) and it belongs to the
HttpSession type. The most important methods are described in the API
reference in Section 21.9.
JSP expressions
In Program Listing 21.2, we have a JSP expression:
This page was downloaded: <%= new java.util.DateQ %> // N.B.! No semicolon!
The expression is surrounded by <%= and %> and the value of the expression is
calculated before it is sent to the client in an out. print () statement. Here the
value of the expression is a reference to an instance of the Date class. As you know,
print () will look for an object's toString () method and use this.
Another example:
The server calculates 17*7 and gets <%= 17*7 %>
This gives the following on the client side:
The server calculates 17*7 and gets 119
Or we can use a predefined object:
The client machine is: <%= request.getRemoteHostQ %>
JSP scriptlets
A scriptlet is surrounded by <% and %> and can contain larger sections of Java code:
Five random numbers in the interval [1,100]:
<%
int sum = 0;
21 Web Programming with JavaServer Pages
JSP declarations
In the example above, we declared the local variables sum, i, and number. We can
also declare variables and methods that are located outside the service ()
method. These are instance variables and instance methods in the servlet class. We
enclose these types of declarations in <%! and %>. For example:
<%! private int noOfVisits = 0; %>
Since all clients deal with the same servlet object, these variables will be common
for all the clients. (Of course, we could declare class variables and class methods as
well.)
The following example demonstrates the difference between variables declared
in <%! %> and variables declared in <% %>.
21.5 What Does JSP Consist of?
<%! private int noOfVisits = 0; %> instance variable, same for all clients
<% noOfVisits++; %>
No. of visits since servlet started = <%= noOfVisits %>
<br>
<% int counter = 0; %> local variable, every client has its own variable
<% counter++; %>
Counter = <%= counter %>
The first time the servlet is accessed, we get this printout in the browser window:
No. of visits since servlet started = 1
Counter = 1
The next time it looks like this:
No. of visits since servlet started = 2
Counter = 1
And so on:
No. of visits since servlet started = 3
Counter = 1
Every time the servlet restarts, the variable noOfVisits is set to zero.
Comments
We can use regular Java comments in the Java code.
In addition, we can use JSP comments to document the JSP code:
<%-- this is a JSP comment, it can be several lines long --%>
The JSP comments are not sent to the browser. If we want the comments to be sent
to the browser, we use HTML comments:
<!-- this is an HTML comment, it can be several lines long -->
JSP directives
A JSP directive controls the construction of the servlet that is created from the jsp file.
A directive is enclosed between <%@ and %>. There are three types of directives:
page, include, and taglib.
The page directive has many possibilities. In this book, we will only use the
import version of this directive. Not surprisingly, it will be converted to an
import declaration in the servlet. For example:
<%@ page import="myl_ibrary.Book, java.text.NumberFormat" %>
page directives can be located anywhere in the jsp file, but we prefer to put them
at the top, just before the first JSP declaration or scriptlet.
The include directive is used to insert the contents of another file into the
location where the directive is. The text of the other file is copied in before the jsp
file is converted to a servlet. The drawback is that if the other file is changed, the
servlet won't know. Therefore, in this case, you have to make sure that a new servlet
is generated and compiled (see the last part of Section 21.2). For example:
21 Web Programming with JavaServer Pages
</form>
</body><html>
We use the HTML form element to read in data from the user (see Figure 21.3),
Let's look at the HTML code.
< form> and </ form> enclose the HTML elements that describe the part of the
page that contains data that will be sent to the Web server. In addition to the usual
formatting elements (<p>, <br>, etc.), there are different types of input
elements; here we have text fields and pushbuttons. An input element receives data
from the user.
The attributes4 in <form> are responsible for the further handling of the input
data. In the example we have:
<form action="ReadCountry.jsp" method="post">
The value of the act ion attribute gives the URL for the program that will receive
the data, method indicates the way the data will be sent. In our case, act ion will
always refer to a jsp file, while the method will usually be "post." The closest
alternative is "get." Before we look at the difference between "post" and "get,"
however, we will look at what else happens.
The form includes three input elements, one of which is a text field. The two
others are a submit button ("Send") and a reset button ("Reset"). Figure 21.4 shows
what happens if the user presses "Send." The ReadCountry.jsp file runs. The source
code that is sent to the browser is shown in the bottom right of the figure.
<html><head><title>Feedback</title></head><body>
<%
String theCountry = request.getParameter("country");
if(theCountry I=null){
theCountry = theCountry .trim0;
if (theCountry.equalsO) out.println("You have to enter data!");
ReadCountry.jsp else out.println("Hallo, you are from " + theCountry + "!");
Figure 21.4 What happens after the user presses the send button
The input elements in an HTML form have names. These become parameters5 in the
request object. The value of a parameter is what the user enters; alternatively it
is the value that is indicated as value in the input element. The parameter names
are case sensitivein other words, "Country" and "country" are two different
parameters.
5. Note that the word "parameter" is being used with a somewhat different connotation than it has
been up to this point
21.6 Inputting Data from the User
sent to the client. This time, the country parameter will have a value it wil!
either be blank because the user didn't enter anything or it will contain a text.
<hr>
<%
String country = request.getParameter("country");
/* country is null the first time the page is downloaded by a user */
if (country != null) {
country = country .trim();
if (country.equalsC"1)) out.println("You have to enter data!");
else out.println("Hallo, you are from " + country + "!");
</bodyx/html>
Always use post transfer if the user is entering sensitive data. When transferring
particularly sensitive data, encryption must also be used. That is not covered in this
book.
21 Web Programming with JavaServer Pages
Figure 21.6 Keyed-in data shows up again as part of the URL if "get" is used
<htmlxheadxtitle>Restaurant Evaluation</titlex/head>
<body bgcolor="wheat" text="black" link="darkgreen" vlink="steelblue" alink="darkblue">
<h1>Restaurant Evaluation</h1>
<form action="RestaurantEvaluation.jsp" method="post">
<pxstrong>The Restaurant's Name:</strongxbr>
<select name="nameRestaurant">
<option>Tom's Brasserie and Bar
<option>Cafe Just Now
<option>Cafe Just Here
<option>Chinahouse
<option>Cecilie Food House
<option>Centre Restaurant
<option>The Big House Restaurant
<option>ltalian Ristorante
</select>
<pxstrong>What did you like:</strongxbr>
Food<input name="like" type="checkbox" value="food">
Situation<input name="like" type="checkbox" value="situation">
Service<input name="like" type="checkbox" value="service">
Price<input name="like" type="checkbox" value="price">
<pxstrong>What did you not like:</strongxbr>
Food<input name="notLike" type="checkbox" value="food">
Situation<input name="notLike" type="checkbox" value="situation">
Service<input name="notLike" type="checkbox" value="service">
Price<input name="notLike" type="checkbox" value="price">
<pxstrong>What did you eat?</strong>
<input name="menu" type="text" size="30">
<pxstrong>Comments:</strongxbr>
<textarea name="comments" type="textarea" rows="4" cols="40"x/textarea>
<pxstrong>Sex:</strongxbr>
Female<input name="sex" type="radio" value="female" checked>
Male<input name="sex" type="radio" value="male">
<pxstrong>Age:</strongxbr>
Less than 20 years<input name="age" type="radio" value="less20" checked>
20-29 years<input name="age" type="radio" value="twenty">
30-39 years<input name="age" type="radio" value="thirty">
40-49 years<input name="age" type="radio" value="forty">
50-59 years<input name="age" type="radio" value="fifty">
Over 60 years<input name="age" type="radio" value="sixty">
21 Web Programming with JavaServer Pages
Program Listing 21 .5
<!--
RestaurantEvaluation.jsp E.L. 2001-08-27
This jsp file is activated from the RestaurantEvaluation.html.
Data entered into the form is fetched, and saved to a text file.
New evaluations are appended to the evaluations already saved.
-->
<%@ page import="java.io.*" %>
<%! String fileName = "EvalRest.txt"; %>
.,o/
< /0~
if (request.getParameter("Send") != null) {
String output =
"Restaurant:" + request.getParameter("nameRestaurant") + "\n" +
"Pleased with:" +
composeOneString(request.getParameterValues("like")) + "\n" +
"Not pleased with:" +
composeOneString(request.getParameterValues("notLike")) + "\n" +
"The guest ate:" + request.getParameter("menu") + "\n" +
"Comments:" + request.getParameter("comments") + "\n" +
"Sex:" + request.getParameter("sex") + "\n" +
"Age:" + request.getParameter("age") + "\n" + "\n" -i- "\n";
/* Printing to file: It is important to print all the output in one
single print statement. This prevents other clients to intervene.
If you have installed LWS as explained in Section 21.2,
the data file will be in the examples directory. */
String fileName - application.getRealPath(nameOfFile);
FileWriter writeConnToFile = new FileWriter(fileName, true);
PrintWriter printer = new PrintWriter(new BufferedWriter(writeConnToFile));
21.6 Inputting Data from the User
printer.print(output);
printer.close();
out.println("<P>Your evaluation is saved.");
API Reference
These methods return the IP address and the name of the host computer the request
came from, respectively.
API Reference
Problems
1. Try the example shown in Figures 21.3 and 21.4. Change the example so that first
and last names can be read in, in addition to country. Also include radio buttons
to indicate sex.
21.7 Client-Side Validation with JavaScript
2. (Difficult) you're going to expand the large example from above. Make a new jsp
file that writes out all the data that's been keyed in by the user. If the user accepts
the data, it's saved. If not, the user will return to the original page to change the
data.
Program Listing 21 .6
<!--
Country3.html E.L 2001-08-27
>
<htmlxheadxtitle>An Input Field with JavaScript data controk/title>
<script language="JavaScript">
function checkDataQ {
if (window.document.countrylnput.country .value == "") alert("You have to enter data!");
else window.document.countrylnput.submit();
}
</script>
</head>
<form name="countrylnput" action="ReadCountry.jsp" method="post">
<p>Enter Your Home Country:
<brxinput name="country" type="text" size="30">
"method" in Java terminology) will be executed. This function is at the top, after
the title element. The function is placed inside the script element.
What, for example, does window. document. country-Input. country
mean? When we program JavaScript, we have access to a vast quantity of pre-
defined hierarchically organized objects, window represents the browser window
that among other things contains the document object, which describes the
document that is displayed. The HTML code shows what objects a document
contains. For example, these could be images, applets, and forms. In our case, it is
a single form, which in contrast to earlier, has been given a name,
countryInput:
<form name="countrylnput" action="ReadCountry.jsp" method="post">
We can refer to the individual parts of a form, and to get the value of the value
attribute in the country input field, we write: window. document. count-
rylnput. country. value. The checkData () function checks whether the
field contains a blank textif that is the case, a brief message appears on the screen
(alert (. . )); if not, everything is alright and the submit () message is sent to
the window. document. count rylnput object. Also notice that in JavaScript
we use the == operator to compare texts.
JavaScript makes it possible to alert the user of errors right after he's made them.
This is clearly an advantage compared with receiving all the error messages after all
the data has been sent to the server. It also reduces network traffic. Therefore, we
should add a client-side data check where it makes sense.
We won't devote any more time to JavaScript in this book. Therefore, you will
need references to use JavaScript: see [URL JavaScript], or if you prefer a textbook,
try [Deitel, Deitel, Nieto 2000].
In addition, there should always be a server-side error check. We may run into
Web developers who don't run the requisite data check when developing their
pages. On the flip side, the pages should be built so that they also work for users
who have turned JavaScript support off on their browsers. Alternatively, these users
should be advised that the page will not work.
Of course, we may use applets as an alternative to forms and JavaScript on the
client side.
21.8 Databases
We're going to make an Internet version of the example from Chapter 20. We will
start as simply as we did there with a jsp file that retrieves data from a table in the
database. Refer to Figure 21.8 with the jsp file in Program Listing 21.7.6 Notice that
the data is retrieved from the database and is then inserted as plain text into the
HTML file that is sent to the browser.
6. Note that we have to qualify the Statement name. The reason is that the resulting servlet imports the
j ava. beans package, which contains a Statement class. We have to qualify this to avoid name conflict.
21.8 Databases
For the sake of simplicity, we are putting the password directly into the source
code in the jsp file. As you can see, the Java code is like Program Listing 20.1. The
only new thing here is probably the HTML element table. To summarize, < tr>
is a table row, <th> is a table head, and <td> is table data.
Figure 21.8 Data from the person table with the generated HTML code on the right
out.println("<td>" + resSet.getString("lastname")
}
if (statement != null) statement.close();
if (conn != null) conn.closeQ;
} catch (Exception e) {
out.print("Error, database connection: " + e);
</table>
</body>
</html>
Then we'll make a Web-based version of the database application in Section 20.4.
We use the Database class from Program Listing 20.2.7 Figure 21.9 shows the
user interface as it looks in the browser.
The Web application consists of many files: see Figure 21.10 and Program
Listing 21.8. We will go through the jsp files in the order they are shown in the
program listing.
The introductory file, NameArchive.jsp, is shown at the top center of Figure 21.9.
This shows all the names recorded. The user chooses between three different
submit buttons depending on what is going to be done.
The HandleSelection.jsp file is activated. The request object contains
information about which submit button the user presses. getParameter ( )
returns null for the buttons that weren't pressed. Depending on the user's
selection, either the DeletePersonData.jsp or the PersonForm.jsp file is included. The
include directive makes sure that the source code in the file in question is
inserted in place of the directive before the page is converted into a servlet. The
effect is the same as if the source code had been there from the beginning.
The PersonForm.jsp file is used both to change existing data and to record new
data. However, there are two differences between these situations.
The identification number is unknown when you go to enter a new person. In
this case, as in Chapter 20, we've chosen to fill the "Idem. No." field with the text
"not defined". If we go to change the data, the selected person's number will be
displayed in the field. What will be displayed is determined in HandleSelection.jsp.
That text will be stored in the idNo variable. PersonForm.jsp gets this:
<td align = left>ldent.no.:</td>
<td align = left><strongx%=idNo%></strong></td>
The database operation itself also differs depending on whether data is going to be
changed or entered for the first time. You'll find the two operations in the files
UpdatePersonData.jsp and AddPersonData.jsp. In other words, the submit button in
PersonForm.jsp will activate different files. Again we use a local variable:
7. LWS: You have to update the lws.bat file such that CL\SSPATH contains the path to myLibrary and
to the database driver you used in Chapter 20. See LWS Reference Manual
21.8 Databases
NameArchive.jsp
form Action
HandleSelection.jsp
include
idNo as for the person
xX include ^-^^managngFile= "UpdatePen>onDa
idNo= 'Yiot defined" ^^~\^
managmgFile= "AddPersonData jsp*\^^
i ^~"~>*.
<htmlxhead><title>Name Archive</title></head>
<body bgcolor="wheat" text="black" link="darkgreen" vlink="steelblue" alink="darkblue">
<h1>NameArchive</h1>
<form action = "HandleSelection.jsp" method = "post">
<select name = "persons" size = 5>
try {
myLibrary.Database theDatabase =
new my Library.Database("username", "password");
java.utiI.Array List all = theDatabase.getAII();
out.println("<option selected>" + all.get(0));
for (int i = 1; i < all.size(); i++) {
out.println("<option>" + all.get(i));
theDatabase.closeTheConnection();
} catch (Exception e) {
out.print("Error, database connection:" + e);
</select>
21.8 Databases
</body>
</html>
try {
my Library. Database theDatabase = new myLibrary.Database("username", "password");
if (theDatabase. deletePerson(identNo)) {
out.println("The person with no. " + identNo + " is removed from the archive.\n");
}
else out.println("Not possible to delete data about this person. " +
"Other clients may have done it already.\n");
theDatabase.closeTheConnection();
} catch (java.sql.SQLException e) {
out.println("Error when deleting from the database: " + e);
Here we use four local variables (idNo, managingFile, firstName and lastName),
which are given values in the HandleSelection.jsp file.
-->
<br><strong>Add/changedata</strong>
<form action="<%=managingFile%>" method = "post">
<table>
<tr>
<td align = left>ldent.no.:</td>
<td align = leftxstrongx%=idNo%></strong></td>
<input type = "hidden" name = "identNo" value = "<%=idNo%>">
</tr>
<tr>
<td align = left>First Name:</td>
<td align = leftxinput type = "text" name = "firstName" size = "20"
value = "<%=firstName%>"></td>
</tr>
21.8 Databases
<tr>
<td align = lefts>Last Name:</td>
<td align = left><input type = "text" name = "lastName" size = "20"
value = "<%=lastName%>"></td>
</td>
</table>
<input type = "submit" name = "save" value = "Save">
<input type = "reset" name = "reset" value = "Reset">
</form>
<!--
AddPersonData.jsp E.L. 2001-08-27
This file is a part of the Name Archive System.
The file is activated from the PersonForm.jsp if data should be added.
>
<html><head><title>New person</title></head>
<body bgcolor="wheat" text="black" link="darkgreen" vlink="steelblue" alink="darkblue">
<%@ page import="myLibrary.*" %>
<%
Database theDatabase = new Database("username", "password");
try {
String firstName = request.getParameter("firstName");
String lastName = request.getParameter("lastName");
Person thePerson = theDatabase.registerNewPerson(firstName, lastName);
out.println("<br>The data is saved, and the person has ident. no.:" +
thePerson.getPersldent() + "\n");
} catch (java.sql.SQLException e) {
out.println("Error saving data:" + e);
}
theDatabase.closeTheConnectionQ;
%>
<p><a href = "NameArchive.jsp">Back to the Main Page</a>
</body>
</html>
<!--
UpdatePersonData.jsp E.L. 2001-08-01
This file is a part of the Name Archive System.
The file is activated from the PersonForm.jsp if data should be updated.
-->
<html><head><title>Editdata</title></head>
<body bgcolor="wheat" text="black" link="darkgreen" vlink="steelblue" alink="darkblue">
<%@ page import="myLibrary.*" %>
<%
Database theDatabase = new Database("username", "password");
try {
int pNo = lnteger.parselnt(request.getParameter("identNo"));
String firstName = request.getParameter("firstName");
21 Web Programming with JavaServer Pages
Problems
1. Change the SimplePersonTable.jsp file so that the number of people is printed out
under the table.
2. Change the SimplePersonTable.jsp file so that the user can enter a last name and
the list only shows people with that last name. Try to do this on the same page.
3. Change the system in Figure 21.9 so that the messages about changes appear on
the start page. In other words, the number of different pages should be reduced
from six to three.
name cookies and files with the name cookies. *. You may be surprised at how many
you find. Many of the places you have visited recently on the Internet have left
traces on your computer. Not all of them are immediately readablelong, cryptic
numbers could be session identifications (see below). That said, we should also
point out that this is the only thing the Web server can do to your computer, i.e.
leave a little snippet of text in a specific location. It does not have access to other
locations on your disk, nor can it deposit other types of files. In other words,
cookies let the server recognize you, but not identify you.
Programs on Web servers, however, should not depend on cookies working.
Cookies should be an option for the client and not the only solution.
The alternative to store state information at the client side is to store it on the
server. In that case, it's normal for the client to be assigned a session ID when the
session starts, i.e. when contact is established between the client and the server. The
data is stored in a session object on the server, while the session ID is normally stored
as a cookie on the client. But as we'll see later, it is possible to use sessions without
using cookies.
Let's look at an example of how cookies and session objects can be used. You log
onto an Internet store to order pizza and soda and are assigned a session ID, which
is stored on your computer as a cookie. At the same time, you are assigned a session
object on the Web server. This happens without your being aware of it. You browse
here and there and check out different types of pizza toppings and side dishes.
Every time your computer asks for a new file from the Web server, the session ID is
sent along with the URL. If you place an order, it is saved in the associated session
object on the server. If the Web server has already saved your name, telephone
number, and delivery address in cookies on your computer, you will be asked to
confirm that they are correct before your order is confirmed. Or you may have to
enter this information and then they will be saved automatically in cookies so that
you don't have to enter them again later. If you decide to forget the whole order
and make do with what you have in the fridge, the session object will be deleted
from the Web server after a given period of time. It's standard for the object to be
deleted if the client is inactive for 20-30 minutes. This can, however, be controlled
by the Web site's creator.
We will take a look at how we program using cookies and session objects.
Cookies
Figure 21.11 shows how cookies work. The jsp files are shown in Program Listing
21.9. Try them by downloading CookiesTest.jsp into the browser. The page should
look like the one on the left of the figure. (If it shows cookies, restart the browser
to remove the cookies.) Type in your name, and then press the "Save" button.
You'll get the following message:
Have found: Mary Johnson
Now the cookies are stored.
Push the 'Back' button and 'Reload' the previous page.
21 Web Programming with JavaServer Pages
Then, follow the instructions ("Back" and "Reload") and you'll get a page similar
to the one on the right side of the figure. This means that your name is stored on
your computer as a cookie, between the downloadings.
If, when running these programs, you check if new cookies really were saved on
your computer, you will probably find that this is not the case. Cookies are
temporarily saved for a time before they are permanently saved on your disk, if
they're saved permanently at all. The cookies in this example disappear when the
user closes the browser. This you may utilize when testing the programs. If you
want the cookies removed, simply restart the browser.
Now, let's look at the source code. The CookiesTest.jsp file starts by getting the
cookies that are stored for this Web site. Nothing is stored the first time you
download the page. Then you enter your first and last name and press "Save", and
control is transferred to the SaveNameAsCookies.jsp page. The cookies are recorded
in the response object:
response.addCookie(cookie1);
response.addCookie(cookie2);
This is how cookies are sent to the client. Now if you reload the previous page, the
name and the session ID are found as cookies. Hence, a session is automatically
established when a client contacts a Web server without anyone having to ask for it.
First Name:|
Last Name:
<html><head><title>CookiesTest</title></head>
<body bgcolor= "wheat" text="black" link="darkgreen" vlink="steelblue" alink="darkblue">
<h1>Searching for Cookies</h1>
<%
Cookie[] cookies = request.getCookies();
if (cookies == null || cookies.length == 0) {
out.println("<p>No cookies.<br><br>");
}
else {
for (int i = 0; i < cookies.length; i++) {
out.println("<br>Cookie found: " + cookies[i].getName() + ", " +
cookies[i].getValue());
<strong>
The name you enter will be saved as a cookie if you press the Save button
</strong>
<form action="SaveNameAsCookies.jsp" method="post">
<table>
<tr>
<td align = left>First Name:</td>
<td align = left><input type = "text" name = "firstName" size = "20"></td>
</tr><tr>
<td align = left>Last Name:</td>
<td align = left><input type = "text" name = "lastName" size = "20"></td>
</td>
</table>
<input type="submit" name="save" value="Save">
<input type="reset" name="reset" value="Reset">
</form>
<!--
SaveNameAsCookies.jsp E.L. 2001-08-28
>
<html><head><title>Save the Name as Cookies</title></head><body>
<%
String firstName = request.getParameter("firstName");
String lastName = request.getParameter("lastName");
out.println("<br>Have found: " + firstName + " " + lastName);
Cookie cookie"1 = new Cookie("firstName", firstName);
Cookie cookie2 = new Cookie("lastName", lastName);
response.addCookie(cookie1);
response.addCookie(cookie2);
out.println("<br>Now the cookies are stored.");
out.println("<br>Push the 'Back' button and 'Reload' the previous page.");
21 Web Programming with JavaServer Pages
%>
</body></html>
API Reference
8. In the Web servers LWS 2.2.1 and Tomcat 3.2.1 this method returns -1 regardless of what value was
set as the maximum age. The age still works the way it should, it's only this method that returns the
wrong value.
21.9 Storing State Information
Sessions
Figure 21.12 and Program Listing 21.10 show sessions. Download the file
SessionTest.jsp in your browser. Then enter some data and press "Save the new
attribute". Then you get a message:
The session ID came from the client as cookie.
Now the new attribute is stored in the session object.
Want to store more data in the session object
The last line is a link to the previous page. Click on it. And you'll see your data in
the attribute list. You may enter more data. Try it out!
The data contents of a session object are called attributes. An attribute is
identified by name (for example: "City") and contains a value (for example:
"London").
Now we'll look at the JSP code in Program Listing 21.10. The SessionTest.jsp file
starts by displaying some information about the session. Test the pages with and
without cookies turned on in the browser.
Servlets are created so that if the client doesn't support cookies, then another
method will be used. The session ID will be sent along with the URL. This assumes
21 Web Programming with JavaServer Pages
that all URLs on the pages that are downloaded from the Web server are run
through the response . encodeURL ( ) method. For example:
<a href="SessionTest.jsp">
is replaced by
<a href="<%=response.encodeURL("SessionTest.jsp")%>">
If the pages don't work without cookies, it might be that the Web server doesn't
support this, or that it's not configured for this.9
Once the session information is written out, the scriptlet runs through all the
attributes and prints out their values. The first time the page is downloaded, this list
is empty: see the left side of the figure.
The user can enter an attribute with a name and value in the two fields and save
it in the session object by hitting the "Save the new attribute" button. Control is
transferred to the SaveDataSession.jsp file. Here, the session object is expanded to
include the new attributes.
else {
out.println("<p>Attributes:");
while (attributeNames.hasMoreElementsO) {
String name = (String) attributeNames.nextElementQ;
out.println("<br>Name: " + name + ", Value: " + session. getAttribute(name));
<br><a href="<%=response.encodeURL("SessionTest.jsp")%>">
Want to store more data in the session object</a>
</body></html>
Let's look at a slightly larger example. Figure 21.13 and Program Listing 21.11 show
something that could be the beginning of an Internet bookstore. Meanwhile, all the
data is hard coded in the program and we're not connected to a database. It also
doesn't include any information about the buyer.
The Book class is shown at the end of the program listing. This class is in the
myLibrary package and it describes a book.
Look at the figure. So far, we've ordered 6 books at a value of $232.82. The page
is designed such that "Update Status" or "Reset the Order" takes us back to the same
page. If, for example, we also order a copy of Bergsten's book, the status line at the
top of the page will be changed to:
The number of books up to now: 7,
Totalprice: $275.77.
Download the BookStore.jsp file and get familiar with the functionality!
Now we look at the code in the jsp file. Let's start by looking at the form element
at the bottom of the file:
<form action = "BookStore.jsp" method = "post">
Note how we design the field names that are going to contain the number of books.
In the source code we write
<td> <input type="text" name="<%="number"+i%>"
value="<%=bookTitles[i].getNumber()%>"></td>
Thus the name of the fields will be number 0, number1, number2, etc. Take a
look at the source code in the browser to be convinced. For example, for Bergsten's
book, this will be converted to the following HTML code:
<input type="text" name="number4" value="0">
The starting value of the number fields is got from the book object. The user can
then change this as desired.
Data we enter is handled by BookStore.jsp. Therefore, this file has to handle both
the case where the user is visiting the page for the first time and where she is
returning to the page because she pressed one of the buttons.
Let's go to the beginning of the file. There we first find an instance variable
currencyFormat and an instance method jspInit ( ). The book prices are
real, they are found on the book covers, and they are all in US dollars, so we have
to set the localization to USA to guarantee the correct currency format. This instance
variable has the same value for all clients, and therefore we want to set it in the
i n i t ( ) method of the resulting servlet. The equivalent method in JSP is
jspInit (). (We also have a method jspDestroy ( ) if we need to release
resources or clear in some other way before the servlet is taken down. But don't
21.9Storing State Information
trust 100% in the jspDestroy () method. It's not called if the servlet is stopped
in an irregular way.)
We have one more instance method, createBookList (), which generates
an array of books and records this as a session attribute. Note the difference
between an instance variable and a session attribute. Here's how we would make
the instance variable:
<%! private Book() bookTitles = {
new Book("Annunziato, Kaminaris: JavaServer Pages in 24 Hours", 29.99),
As the variable currencyFormat, this array would be common for all clients.
This would have been fine if the array only contained the titles and prices. An
instance of the Book class, as we have designed the class, would also come to
contain information on the number of books. We choose to use the class so that
this means the number of books the individual customer has ordered. Therefore we
have to have one array, bookTitles, per customer. We accomplish this by
declaring that as a session attribute:
session.setAttribute("bookList", bookTitles);
Now the book array will live for one session, i.e. either until the user exits the
browser or until a long period of time has elapsed since she's visited the Web site.
In our case, a "long time" is defined by the Web server (usually 20-30 minutes),
since we haven't set any specific length.
Here we come to the active section of the file. If the bookList attribute does
not exist, we generate it by calling the method we went through above:
if (session.getAttribute("bookList") == null) createBookList(session);
We make the attribute locally accessible:
Book[] bookTitles = (BookQ) session.getAttribute("bookList");
Then we handle the different situations we might be in when the user arrives at this
page:
If both of these parameters are null, that means that the page is being visited
for the first time in this session. All we do is display a little welcome message.
Books
The number of books up to now. 6.
Total price: $235.82.
Title
. Kamiaf.JavaServerPagesin24 Hours $29.99JJ1
HougiandandTavistock:Core JSP
jPekowisky.JavaServer Pages $39.95 j
(Hall: Co |$42.99
j$39.95pT
out.println("The number of books up to now: " + totalnumber + ", <br>Total price: " +
currencyFormat.format(totalprice) + ".");
} catch (NumberFormatException e) {
out.println("lnvalid number entered for " + bookTitles[index].getTitle());
value="<%=bookTitles[i].getNumber()%>"></td>
</tr>
</table>
<br>
<input type="submit" name="update" value="Update Status">
<input type="submit" name="reset" value="Reset the Order">
</form>
</body></html>
/*
*Book.java E.L 2001-08-28
V
package myLibrary;
public class Book {
private String title;
private double price;
private int number = 0;
public Book(String initTitle, double initPrice) {
title = initTitle;
price = initPrice;
}
public String getTitle() {
return title;
}
public double getPrice() {
return price;
}
public int getNumber() {
return number;
}
public void setNumber(int newNumber) {
number = newNumber;
API Reference
Methods:
public Cookie[] getCookies()
This method returns an array with all cookies that came in with this request. null
is returned if there weren't any cookies.
public String getRequestedSessionld()
This method returns this session's ID.
public boolean isRequestedSessionldValid()
This method checks if the requested session is still valid.
public boolean isRequestedSessionldFromCookie()
public boolean isRequestedSessionldFromURL()
These methods check where the session ID came from, either from a cookie or from
the URL.
Thejavax.servlet.http.HttpSession interface
The JSP default session object is an instance of a class that implements this
interface.
Methods:
public long getCreationTime()
This method gets the time the session object was created. The time is stated as a
number of seconds after midnight (00:00) GMT on January 1, 1970. This can be an
argument for the Date constructor to get the time in the date format instead.
public String getld()
This method returns the session ID.
public long getLastAccessedTime()
This method returns the time the client last sent a request in this session, as a
number of seconds since midnight (00:00) GMT on January 1, 1970.
public void setMaxlnactivelnterval(int interval)
public int getMaxlnactivelnterval()
These methods are used to set and get the maximum number of seconds between
the requests. If the number of seconds exceeds this limit, the session object is no
longer valid. A negative interval means that the session will live "forever". If an
interval is not specified, the default value set for the Web server is used.
public Object getAttribute(String name)
public void setAttribute(String name, Object value)
public void removeArtribute(String name)
These methods are used to maintain the contents of the session object.
getAttribute () returns null if an attribute with the indicated name does
21 Web Programming with JavaServer Pages
Problems
1. Expand the code in Program Listing 21.9 with cookies for address, zip code and
city.
2. Set the age of one of the cookies in Program Listing 21.9 to 24 hours, and try it
from one day to the next. Check that the cookie is stored on your disk.
3. Implement the solution to "The problem with Reloading Pages" for the
restaurant evaluation example, as presented above.
4. Change the code in Program Listing 21.11 after the following lines:
Put the book information into a text file (use a text editor). The number should
now tell us the total number of books ordered by all clients. All the information
21.10New Concepts in This Chapter
in this file should be read into an instance variable bookTitles when the
accompanying servlet is initiated (put this in the method jsplnit ( ) ).
When the servlet runs, the information should be held in the instance variable.
The number of books ordered by an individual customer should be held in a
session attribute.
The page should be expanded with a "Send Order" button, which updates the
instance variable and saves it to the file.
attribute, HTML HTML code can have attributes that provide additional information for an element.
attribute, session The individual data element in a session object is called an attribute and is identified
with a name. The attribute has to be of a reference type.
client-side Data is checked on the client side before being sent to the server.
validation
cookie A small quantity of information that is stored as text on the computer where the
browser is running.
JSP JavaServer Pages a technology that makes it possible to distinguish the Web page's
dynamic contents from its design. The dynamics are isolated and surrounded with
special characters. See the concepts that start with JSP below.
JSP comment Comment surrounded by < % - - and - - % > . The comment doesn't show when the
source code is shown in the browser.
JSP declaration Variables and methods surrounded by <%! and %>. These will become members in the
servlet created from the jsp file.
JSP directive Directives that control how the servlet will be constructed. Enclosed between <% and
JSP page An HTML page that is made by a servlet based on a jsp file.
parameter, the In conjunction with Web programming, the word "parameter" refers to the data sent to
request the server as part of a request object (or a query string). The parameters are usually
object names and values from the input elements in HTML forms.
21 Web Programming with JavaServer Pages
pool Often used about data resources that are labor-intensive to set up. A pool is a specific
quantity of this type of resources, for example 10 database connections. Clients that
need one of these resources are assigned one from the pool. The resource is returned to
the pool after use, without dosing it If the pool is empty, the client has to wait until
one is free, or the pool can be expanded to contain more.
script Code written in a scripting language is not compiled, but rather interpreted line by line.
language
server-side The data is checked on the server side.
validation
servlet A Java program that runs on a Web server. It is started and runs until the Web server is
taken down or it is stopped in another way. Executes specific tasks every time it's
accessed by a Web client.
The period of time during which a client communicated with a specific Web site.
WML Wireless Markup Languagea "markup" language, usually used in developing pages for
mobile phones.
7. By translating a jsp file to a servlet class, some variables become instance variables
while others become local variables. Which variables turn into instance
variables? Which ones become local variables? And in which method are these
variables local?
8. Among other things, by transferring data from client to server, we can use "post"
or "get". What is the difference and which method should we use?
9. What do we use JavaScript for?
10. What is a cookie?
11. Explain the concept of a session, and in particular the relationship between a
session and a cookie.
12. Why should we send all URLs in jsp files through the response, en-
codeURL ( ) method?
Problem 4
Make a Web interface that can be used by a client of type 2 in Problem 3 from
Chapter 20. The user will enter his user ID and password.
Problem 5
Make a Web interface for the application developed as the solution to Problem 4 in
Chapter 20.
As explained in Chapter 1, we can divide the program systems we need to program
Java i n t o two: a tool for writing, editing, and storing the files in source code, and a
set of tools for compiling and running the files. In many cases, we use larger
development tools, which combine these functions in one program. For example
we will use the Java SDK (Software Development Kit) package from Sun to compile
and run. This is the official development tool for Java. SDK is the same package that
was previously called JDK, the Java Development Kit. As of version 2 of Java, the
package has been called SDK, but the name JDK is still hanging on, and the two
names are used interchangeably even on Sun's Web pages.
We've used a program called WinEdit for text editing, but that's just to have an
example. There are many similar programs. In addition to the primitive Notepad
that comes with Windows, we can also mention UltraEdit and JPad as examples.
Another tool used a great deal by advanced users is Emacs, a powerful tool with a
somewhat steep learning curve. You can search for "editors" at [URL WinFiles],
where there's a large selection of text editing tools that are cheap or even free.
On the book's Web pages [URL Java book], you'll find links and updated
information concerning Java-related tools.
A.1 SDK
The SDK development package exists for many types of computers/operating
systems. A bunch of versions come from Sun itself, but there are also SDKs for other
platforms that others have made (or "ported," as we call it when you rewrite
programs for operating systems other than those they were originally written for).
For those with limited experience, installing this program package can be a little
complicated. A little help, for example from people who have done it before, may
come in handy.
Downloading and installing
In this book, we're assuming that the reader is using Windows 95/98/NT/2000,
even though we don't go as far as recommending it. The SDK for this platform is
available from Sunthe URL to go to it is [URL Javasoft]. In the following, as an
example, is a description of how the download works. (Sun may have modified the
Appendix A: Using Java SDK and WinEdit
procedure since this was written.) Read through the whole thing before you begin,
and keep in mind that small details may have been changed. The most important
thing is to keep your goal in mind: to download Java 2 SDK and install it on your
hard disk.
You'll come to the [URL Javasoft] front page. Here you'll find advertisements
and news. You can click on Products & APIs in the menu; here you'll find the
products that are available. Sun have a menu where you can choose a product to
download. We want Java 2 SDK Standard Edition.
When you get to the SDK page, you can click on Microsoft Windows. Locate the
download button on the following page.
Press "Agree" to agree to the terms for downloading. You see pages of terms like
this all the time when downloading software, but they don't usually have any
practical significance for students. One exception may be time-limited licenses.
You get to choose between an FTP or HTTP download. Choose FTP. Now your
browser will ask where you want to save the file. It may be beneficial to have a
directory ready on your hard disk for SDK, C:\sdk2\ or something similar.
When the file is finished downloading, it can be unwrapped by running the file.
(It's a self-expanding exe file, which means that it will unwrap itself when you run
it.) It will ask where on the disk SDK should be placed, and which modules you
want. In terms of the modules, it's OK to say "yes" to whatever is being
recommended.
As for the documentation, you can download it, but it's also available on the
Webyou can get to it from [URL Javasoft]. We recommend that you download the
entire set of documentation to your own hard disk, and read it from there.
Especially in connection with programming graphical user interfaces, there will be
a lot of use for it. Regardless, it's important to familiarize yourself with the
documentation, because only a small portion of the program code that is available
for use is discussed in this book.
The size of the program package can be a hassle for people with slow Net
connections: it just takes too long to download everything. However, you need the
development tools to get some work done, so this problem has to be addressed.
One possibility could be downloading the package from a place with a good
Internet connection.
Path
In the computer's operating system, there's something called environmental varia-
bles. These are values or a list of values that belong to all the programs we run. They
are used to keep track of the many things a program needs to know. They are exactly
like Java's own variables that we cover in Chapter 2: they have names and values.
But the environmental variables apply to the whole operating system, and we as
users can create and delete them as needed.
When SDK is expanded and ready, it's an advantage if we can use the programs
in the package regardless of where we are on the hard disk, in the console window
(MS-DOS window), or in using other programs, like WinEdit. We can do this by
A.1 SDK
adding the directory to the environmental variable PATH. The result of this is that,
for example, we can use the program javac regardless of where we are in the console
window. Often this is done automatically when SDK is installed, so it may happen
that this is all taken care of once your installation is done. The section Using SDK
on below describes how you check this. In the next paragraph, we'll describe how
you can do this yourself.
To change PATH in Windows NT/2000, go into the control panel from the Start
menu, then System and Environment. Often there's already a PATH, and in that
case, all you have to do is add, for example, C:\sdk2\bin\ to the line of text that's
there. (The programs themselves, the exe files, are in the subdirectory bin under
SDK.) Note that the different directories in PATH are separated by a semicolon, so
the new directory we add has to be as well.
Example of the contents of the PATH variable after we've made this addition:
C:\;C:\windows\;C:\sdk2\bin\
Here we see that three different directories are in PATH. For these changes to apply,
you have to close the Environment dialog and start a new console window.
To do this in Windows 95/98, add this line to C:\auotexec.bat:
set PATH=C:\;C:\windows\;C:\sdk2\bin\
There's probably a PATH line already, and then you just edit it the way we've shown
here. For the changes made in autoexec.bat to apply, you have to run the file by
double-clicking on it.
Classpath
Another environmental variable that affects the use of SDK is CLASSPATH. While
PATH is a general environmental variable that contains information about where
the operating system should look for exe files, CLASSPATH is Java-specific and tells
the Java interpreter, java, where it should look for class files. So there's a certain
analogy between the two; the class files are run in conjunction with Java just as the
exe files are run otherwise. CLASSPATH, like PATH, is a list of directories, and what
is worth taking note of is that even the directory we're in has to be in CLASSPATH
for the Java interpreter to look there. If you get an error message like the following
one when running a Java program, and the right class file is definitely in the
directory, it's probably CLASSPATH that's not correctly set.
C: \javaprogratns> java PrintText
Exception in thread "main" java.lang.NoClassDefFoundError:
PrintText
This is an error message saying that the class definition (class file) was not found.
What should you do if you have problems with this? It's hard to say something
precise that will work every time, because there may be programs other than SDK
that are using CLASSPATH, but we have the following two suggestions.
The first thing you can do is delete the whole environmental variable
CLASSPATH. (If it has a value from before you shouldn't do thisread the next
Appendix A: Using Java SDK and WinEdit
section instead.) In Java 2 SDK, the interpreter will then look in the directory you're
in. You delete an environmental variable the same way you set it (see the section
on PATH). Just remember to restart the console window under NT/2000 afterwards,
and if it's Windows 95/98 it can pay off to reboot.
The other way to go about setting CLASSPATH up correctly is to add a period in
the list of directories. Change CLASSPATH, for example, so that it looks like this:
.;C:\netscape\classes\
In this example, we see that there's a directory that refers to the program Netscape
in CLASSPATH, and we shouldn't touch that. So we add a period to the list. This
indicates that the current directory should always be included in CLASSPATH. The
different directories are also separated by semicolons here.
Bear in mind that it's quite likely you won't need to touch this environmental
variable.
Using SDK
Once you've done all this, you can test that you did the installation and adjusted
PATH correctly by starting a console window and trying to start the compiler by
writing javac:
C : \ > javac
Usage: javac <options> <source files>
where <options> includes:
-g Generate all debugging info
-g:none Generate no debugging info
-g:{lines,vars,source} Generate only some debugging info
-O Optimize; may hinder debugging or
enlarge class files
-nowarn Generate no warnings
-verbose Output messages about what the
compiler is doing
-deprecation Output source locations where
deprecated APIs are used
-classpath <path> Specify where to find user class
files
-sourcepath <path> Specify where to find input
source files
-bootclasspath <path> Override location of bootstrap
class files
-extdirs <dirs> Override location of installed
extensions
-d <directory> Specify where to place generated
class files
-encoding <encoding> Specify character encoding used
by source files
A.2 Running Applets
A.3 WinEdit
The text editor we've decided to use as our example in this book is called WinEdit.
You can read about it at the vendor's Web pages: [URL WinEdit]. At the time of
Appendix A: Using Java SDK and Win Ed it
writing, the program costs $100 (check the URL for the correct price) and you can
download and install a free evaluation version as follows.
From the URL given in the previous paragraph, click on "Download". You will
be given a choice between HTTP and FTP. After the program is downloaded, place
it in its own directory and run the self-expanding exe-file. During installation, you
can safely accept the options the program suggests, but it may also want to install
some add-on programs which you do not necessarily need. Start it up by double-
clicking on WinEdit.exe in the file manager, or choose the program from the start
menu. In other words, install and start up work in the usual Windows fashion
several people will have done this before.
Editing text
WinEdit has the same principal functionality as Windows Notepad, but with many
more options. You open, save, and close files from the File menu. If you open a java
file, you'll notice that the program uses colors in the Java program to make
programming easier. WinEdit will also apply colors to other types of filesfor
example, HTML. This is called syntax highlighting.
If you've written a Java file that you want to try to compile, choose Compile from
the Tools menu at the top. WinEdit will then run javac for you, with the right
parameters.
For WinEdit to be able to do the compiling, SDK must be installed earlier, and PATH
modified so that the bin directory for SDK is included.
A separate window in WinEdit will give you the compiling resulti.e., error
messages or a message that there were no errors. If there are errors, you go into the
code and try to correct them before compiling again.
After you've compiled the program without errors, you can run it by selecting
Java, Run Java Application from the Macro menu. The reason this isn't under Tools
is that this is done another waythe interpreter is started in its own window. In that
window, you will see the dialog with the program. You may also run an applet from
the Macro, Java menu. For applications, you have the choice between running
console (i.e. textual) or graphical applications.
Play around with WinEdit (or the tool you decide to use) on your own, and get
to know its capabilities. Editing and managing text files is an important skill for a
programmer.
K
The list is from [Gosling, Joy, Steele 1996, section 3.9] except for the assert
keyword, which has been added to the language in JDK release 1.4. The Java
authors continue: "The keywords const and goto are reserved by Java, even
though they are not currently used in Java. This may allow a Java compiler to
produce better error messages if these C++ keywords incorrectly appear in Java
programs."
This page intentionally left blank
(Written by Mildrid Ljoslancl)
Most number systems are based on the positional principle so that a number's
value depends on where in the sequence of digits it's located, A 1 means 10 (in the
base 10 system) if it comes next to last, while it means 1000 if it comes two places
further forward, Roman numerals are an example of a number system that doesn't
use the positional principle. The letter D means 500 regardless of where it's located
The number systems covered in this appendix use the positional principle.
Base 10 system (the decimal number system)
Ten different digits, 0 to 9. Example: 286 = 2 102 + 8 10J + 6 10.
Base 2 system (the binary number system)
Two different digits, 0 and 1. Example:
01101 = 0 24 + 1 23 + 1 22 + 0 21 + 1 2 = 0 + 8 + 4 + 0 + 1 = 13
To convert from the base 10 system to the base 2 system, divide repeatedly by
two and then take care of the remainders.
Example: Convert 123 to binary.
123/2 = 61 with a remainder of 1
61 / 2 = 30 with a remainder of 1
30/2= 15 with a remainder of 0
1 5 / 2 = 7 with a remainder of 1
7/2 = 3 with a remainder of 1
3 / 2 = 1 with a remainder of 1
1/2 = 0 with a remainder of 1
When we get 0 as the answer, we're done. Then we collect the remaindersthe
last remainder computed is the first digit in the binary number. Here that will be
1111011. Check that this is correct: 111 1011= 64+ 3 2 + 1 6 + 8 + 0 + 2+1 = 123.
Base 8 system (the octal system)
Eight different digits, 0 to 7.
Appendix C: Number Systems
Example:
632 = 6 82 + 3 81 + 2 8 = 6 64 + 3 8 + 2 = 384 + 24 + 2 = 410
Converting from the base 10 system to the base 8 system works the same way as
to the base 2 system.
Convert 123:
123 / 8 = 15 with a remainder of 3
15 / 8 = 1 with a remainder of 7
1/8 = 0 with a remainder of 1.
Result: 2D18.
To convert to binary: this works the same as for base 8. The difference is that now
there are four binary digits for each hexadecimal digit. Example: 2D18 will become
0010 1101 0001 1000.
To convert to the octal system is done through binary:
2D18 = 0010 1101 0001 1000 = 0010 110 100011 000 = 026430
The hexadecimal system is used in data processing for the same reason as the
octal system, and with it there are even fewer digits to keep track of. This also fits in
well with a byte being 8 bits. There are exactly two digits per byte.
If we're going to indicate that a constant in a program is declared in the
hexadecimal system, we start by writing OX. Example: number = OX2D18 ;
This page intentionally left blank
!-or complete specifications, see JL1RL Unicode), In Windows NT you may find
'Unicode Character Map" in the group Accessories useful. The table below only
shows the printable characters in the part of Unicode that coincides with ASCII
value character value character value character
^2 64 @ 96
33 ! 65 A 97 a
34 " 66 B 98 h
35 # 67 C 99 c
36 $ 68 D 100 d
37 % 69 R 101 e
38 & 70 F 102 f
1
39 71 G 103 g
40 ( 72 H 104 h
41 ) 73 I 105 i
42 * 74 J 106 i
43 + 75 K 107 k
44 , 76 L 108 1
45 - 77 M 109 m
46 78 N 110 n
47 / 79 O 111 o
48 0 80 P 112 P
49 1 81 Q 113 q
50 2 82 R 114 r
51 3 83 S 115 s
52 4 84 T 116 t
53 5 85 LI 117 u
54 6 86 V 118 V
55 7 87 W 119 w
56 8 88 X 120 X
57 9 89 Y 121 y
58 90 Z 122 z
59 * 91 1 123 {
60 < 92 \ 124 1
61 =
>
93 1 125 1
~
62 94 A
126
63 ? 95
This page intentionally left blank
TML and Applets ft. i
As we pointed out in the first chapter, Java is tied to the Web, but far from
exclusively. Applets are small Java programs that are part of a Web page. Applets are
a special version of Java programs. The regular programs, the applications that we
work with, are a larger and more general group.
Java applets are compiled like Java programs from source code with the .java
extension to a byte code file with the .class extension. So an applet takes the form
of a filefor example, SimpleApplet.dass. Here, we will briefly explain how we use
this applet in a Web page, once we've covered the most important elements of
HTML, Hypertext Markup Language.
E.1 HTML
The Web came to exist so that researchers could present documents in electronic
form and so that they could be easily distributed on the Internet. Central to this is
the HTTP protocol, which is the set of rules used when files containing texts,
graphics, sound, etc. are linked together and transported around on the Net. In
general, a protocol is a type of standardized and agreed upon set of rules, and the
concept is key in the field of data networking. HTML is a language that we use to
format the basic Web files, the pages that contain regular text with associated
formatting and also graphics. The hyperlinks are also importantwith these, HTML
allows us to jump to a new document with, for example, the click of a mouse.
When we work on the Web, we are usually dealing with a browser, which is
called a client. We use this to request filesfor example, english.htmlthat are on a
Web sewer. The Web server has a name on the Internet that makes it easy for us to
look it up. www.tisip.no is the name of TISIP's Web server. To get a document on it,
we use a URL, Uniform Resource Locator, which may look like this: http://
www.tisip.no/english.html. Here we're saying that we're going to get the document
with the file name english.html on the server www.tisip.no, and it's the HTTP
protocol that's used (i.e., the regular Web).
This document, in turn, can contain references to graphics (and other things).
Below you'll find an example of how an HTML file might look. It's regular text,
just like Java source code. However, it's important to remember that these aren't
instructions to the computer, but a markup, a static description of something.
Appendix E: HTML and Applets
<html>
<head>
<title>An example page</title>
</head>
<body>
</body>
</html>
We see that different codes are found inside < and >. These codes are called tags
(for example, the body tag). The tags mark the start of different elements and an
element is often ended with </ . . . >. Study the example and you'll see that
<html> and </html> mark the start and end of the HTML document itself,
<head> and </head> mark the start and end of the head part of the document,
and <body> and </body> mark the document's body. This is the basis of all
HTML pages. In our example, there's a title marked with its own tag, and also
header 1, or <hl>. <p> comes before a paragraph and you'll see that these aren't
ended they end when something else starts.
It's the browser Netscape or another browser that's responsible for displaying
the data in this HTML file nicely for those who come and visit the page.
In addition to what we've presented here, there are a number of other elements
we use. A common one is the element with the tag <img> for including graphics:
<img src="sunrise.gif">
Here, graphics from a file are inserted into the Web page. The file is assumed to be
in the same directory on the Web server as the HTML document using it.
The whole point of the Web and HTML is that it can link many different types of
machines together, and that many different browsers can display documents in a
reasonable manner. Thus, there's a need for both HTTP and HTML to be
standardized, and for those who make both Web servers and browsers to focus on
the same standards. It's the World Wide Web Consortium, W3C, which bears the
overall responsibility for this standardization. You can find and study the official
HTML standard (at the time of printing), HTML 4.0, at [URL W3C]. There you'll see
which elements are permitted (and there aren't all that many). The reason that
there are relatively few elements is that it has been cleaned up from the previous
version, HTML 3.2. In version 4.0, everything that has to do with presentation is
formatted in a special language, CSS, which stands for Cascading Style Sheets. We
won't go into any more detail on this here.
E.2 Including Applets
For chapter 21, you will need more HTML elements; look them up in [URL W3C]
when you need to refer to them.
A Java applet runs in a security model called the sandbox model. In practice, that
means that you don't risk anything when you download a foreign applet on the
Web, because it's not allowed to do anything that might damage your computer.
But doesn't this greatly limit the applet's capabilities? Yes, to an extent, but it can
still display things, talk to the user through GUI components, show animations,
and much more.
The quality of browsers' built-in Java interpreters is extremely variable. The level
of performance is often low, and many who have tried their hand at programming
applets have experienced frustration with browsers that don't support applets
written in the version of Java code they used. The language itself varies minimally,
but the ready-made code we use, which is included in the browsers, varies.
URL Coding standard) contains the code standard used in this book. We
chosen to use the standard with the following exceptions:
Point 3.1: "Each Java source file contains a single public class or interface." A file
cannot contain more than one public class, but we permit a file to contain multiple
classes with package access. The code standard doesn't mention classes with
package access.
Point 3.1.1: We've chosen to simplify the head comment a little compared to
these recommendations.
Point 4: Out of space considerations, we're only indenting two spaces instead of
four.
Point 4.1: For the same reason, we allow lines longer than 70 (80) characters.
Point 5: We've included some comments for instructional reasons. These are
comments that explain things that appear in the code. Normally, one would
assume that the reader is familiar with Java and comments like this would be
considered extraneous.
Points 5.1.3 and 5.1.4: We only use// to insert comments at the end of a line.
Point 5.2: Documentation comments are used to generate documentation like
the online API documentation. We're not using documentation comments /**...*/.
You can find examples of these in use (and a brief description of how they're used)
in the myLibrary package.
Point 6.1: We chose the first alternative, a blank space between the data type and
the name.
Point 6.3: We are putting variable declarations close to where the variables are
used for the first time. This makes it easier to initialize the variables (Point 6.2) with
reasonable values.
Point 7.2: We permit the brackets in i f / e l s e / w h i l e / f o r / d o statements
to be omitted if only one statement is going to be executedand this statement goes
on the same line as if/else/while/for/do. (We have our reservations
about this exception, but have found that this simplification is difficult to avoid in
practical programming.)
Point 7.4: Nested if might therefore look like this:
if (...)_
else if (...)
Appendix F: Exceptions to the Code Standard
else if (...)
else...
"Note" at the end of the section is still important. Remember that there has to be
room for the statement on the same line as the if statement.
Point 9: Only ASCII characters (AZ, az, '0''9') are used in class names. Names
of classes that are answers to problems are the exception. There we use the
underline character to indicate which problem the answer is for (example
Problem5_4_3).
We have opted to use the same naming conventions for constants as for
variables.
Point 10.3: This is too severe a limitation. It must be possible to use other
anonymous constants (literals) besides -1, 0, and 1 directly in the program. For
example: the number 2 in the formula for the radius of a circle: 2 * Math. PI *
radius.
Point 10.5.1: We're not using extraneous parentheses in expressions containing
frequently used operators. We think that the reader should learn the operator
precedence, and we also think that so many levels of parentheses make the
expressions difficult to read. There are, however, examples of expressions in point
10.4 and point 10.5.3 where parentheses should be used: if ( ( C + + = d++)
!= 0) ... and (x >= 0) ? x : -x;. Particularly thefirstone is the type of
expression that is best rewritten as multiple statements.
Point 10.5.2: We find the first two alternatives to be equivalent. In the second
case, the code standard recommends using the conditional operator. This operator
is difficult for many people, especially beginners. Therefore it's not used in this
book.
References
Books:
Cay S. Honsmann, Gary Cornell Core Java 2. Volume I - Fundamentals. Prentice Hall 1999.
Cay S. Hortsmann, Gary Cornell Core Java 2. Volume II - Advanced Features. Prentice Hal!
2000.
Craig Larman Applying UML and Patterns An introduction to Object-Oriented Analysis and
Design. PTR (ECS Professional) 2000.
David Flanagan Java in a Nutshell. A Desktop Quick Reference. 2nd edn. O'Reilly 1997.
Grady Booch, James Rumbaugh, Ivar Jacobson Unified Modeling Language User Guide.
Addison-Wesley 1999.
H. M. Deitel, P. J. Deitel, T. R. Nieto Internet and World Wide Web, How to Program. Prentice
Hall 2000.
James Gosling, Bill Joy, Guy Steele The Java Language Specification. Addison-Wesley 1996. See
[URL Language spec].
James Rumbaugh, Ivar Jacobson, Grady Booch The Unified Modeling Language Reference
Manual. Addison-Wesley 1999.
Jose Annunziato, Stephanie Fesler Kaminaris Sams Teach Yourself JavaServer Pages in 24 Hours.
Sams Publishing 2001.
Kathy Walrath, Mary Campione The JFC Swing Tutorial. A Guide to Constructing GUIs.
Addison-Wesley 1999.
Knut Hofstad, Stale L01and, Per Scott Norsk dataordbok, 6.utgave. Universitetsforlaget 1997.
(A Norwegian book on computer terms.)
Mark Allen Weiss Data Structures and Problem Solving Using Java. Addison-Wesley 1998.
Marty Hall Core Servlets and JavaServer Pages. Prentice Hall 2000.
Nigel Warren, Philip Bishop Java in Practice. Design Styles and Idioms for Effective Java.
Addison-Wesley 1999.
Robert Eckstein, Marc Loy, Dave Wood Java Swing. O'Reilly 1998.
Robert Orfali, Dan Harkey Client/Server Programming with Java and Corba. Second Edition. John
Wiley & Sons, Inc. 1998.
Thomas Connolly, Carolyn Begg, Anne Strachan Database Systems. A Practical Approach to
Design, Implementation and Management. Addison-Wesley 1999.
Thomas H. Cormen, Charles E. Leiserson, Ronald L Rivest Introduction to Algorithms. MIT
Press 1997.
Appendix G: References
URLs:
[URL Coding standard] http://java.sun.com/docs/codeconv/
[URL ColorApplet] http://www.tisip.no/JavaTheUmlWay/examples/ColorApplet.htmI
[URL Database Drivers] http://industry.java.sun.com/products/jdbc/drivers
[URL Gefion] http://www.gefionsoftware.com/
[URL Java book] http://www.tisip.no/JavaTheUmlWay/
[URL Java glossary] http://java.sun.com/docs/glossary.html
[URL JavaScript] http://developer.netscape.com/docs/manuals/javascript.html
[URL-Javasoft] http://java.sun.com/products/
[URL Language spec] http://java.sun.com/docs/books/jls/html/
[URL Servlet info] http://java.sun.com/products/servlet/
[URL SimpleApplet] http://www.tisip.no/JavaTheUmlWay/examples/SimpleApplet.html
[URL Unicode] http://www.unicode.org/
[URLW3C] http://www.w3.org/
[URL Web servers] http://java.sun.com/products/servlet/industry.html
[URL WinEdit] http://www.winedit.com/
[URL WinFiles] http://www.winfiles.com/
ndex
Page numbers in italic refer to concept explanations. Identical terms with different
capitalization are different words in Java and this is reflected in the index entries.