3 Oracle BY SHAAN
3 Oracle BY SHAAN
Oracle BOOK
BY Nitin Shaan
for input in the first half of the book has been rewritten to support
formatted output. I have also added some file I/O capabilities to
this class to make it possible to cover some examples that use files
early in the book. Javadoc comments are covered for the first time in
this edition. Almost all code examples have been revised to use
Javadoc-style comments. The coverage of graphical user interface
programming has been reorganized, much of it has been rewritten, and
new material has been added. In previous editions, I emphasized
applets. Stand-alone GUI applications were covered at the end, almost
as an afterthought. In the fifth edition, the emphasis on applets is
gone, and almost all examples are presented as stand-alone
applications. However, applet versions of each example are still
presented on the web pages of the on-line version of the book. The
chapter on advanced GUI programming has been moved to the end, and a
significant amount of new material has been added, including coverage
of some of the features of Graphics2D. Aside from the changes in
content, the appearance of the book has been improved, especially the
appearance of the PDF version. For the first time, the quality of the
PDF approaches that of conventional textbooks. ∗ ∗ ∗ The latest
complete edition of Introduction to Programming using Java is always
available on line at http://math.hws.edu/javanotes/. The first
version of the book was written in 1996, and there have been several
editions since then. All editions are archived at the following Web
addresses: • First edition: http://math.hws.edu/eck/cs124/javanotes1/
(Covers Java 1.0.) • Second edition:
http://math.hws.edu/eck/cs124/javanotes2/ (Covers Java 1.1.) • Third
edition: http://math.hws.edu/eck/cs124/javanotes3/ (Covers Java 1.1.)
• Fourth edition: http://math.hws.edu/eck/cs124/javanotes4/ (Covers
Java 1.4.) • Fifth edition: http://math.hws.edu/eck/cs124/javanotes5/
(Covers Java 5.0.) Introduction to Programming using Java is free,
but it is not in the public domain. As of Version 5.0, it is
published under the terms of the Creative Commons Attribution-Share
Alike 2.5 License. To view a copy of this license, visit
http://creativecommons.org/licenses/bysa/2.5/ or send a letter to
Creative Commons, 543 Howard Street, 5th Floor, San Francisco,
California, 94105, USA. This license allows redistribution and
modification under certain terms. For example, you can: Preface xv •
Post an unmodified copy of the on-line version on your own Web site
(including the parts that list the author and state the license under
which it is distributed!). • Give away or sell printed, unmodified
copies of this book, as long as they meet the requirements of the
license. • Make modified copies of the complete book or parts of it
and post them on the web or otherwise distribute them, provided that
attribution to the author is given, the modifications are clearly
noted, and the modified copies are distributed under the same license
as the original. This includes translations to other languages. While
it is not actually required by the license, I do appreciate hearing
from people who are using or distributing my work. ∗ ∗ ∗ A
technical note on production: The on-line and PDF versions of this
book are created from a single source, which is written largely in
XML. To produce the PDF version, the XML is processed into a form
that can be used by the TeX typesetting program. In addition to XML
files, the source includes DTDs, XSLT transformations, Java source
code files, image files, a TeX macro file, and a couple of scripts
that are used in processing. I have not made the source materials
available for download, since they are not in a clean enough form to
be publishable, and because it would require a fair amount of
expertise to make any use of them. However, they are not meant to be
secret, and I am willing to make them available on request. ∗ ∗ ∗
Professor David J. Eck Department of Mathematics and Computer Science
Hobart and William Smith Colleges Geneva, New York 14456, USA Email:
[email protected] WWW: http://math.hws.edu/eck/ xvi Preface Chapter 1
Overview: The Mental Landscape When you begin a journey, it’s a good
idea to have a mental map of the terrain you’ll be passing through.
The same is true for an intellectual journey, such as learning to
write computer programs. In this case, you’ll need to know the
basics of what computers are and how they work. You’ll want to have
some idea of what a computer program is and how one is created. Since
you will be writing programs in the Java programming language,
you’ll want to know something about that language in particular and
about the modern, networked computing environment for which Java is
designed. As you read this chapter, don’t worry if you can’t
understand everything in detail. (In fact, it would be impossible for
you to learn all the details from the brief expositions in this
chapter.) Concentrate on learning enough about the big ideas to
orient yourself, in preparation for the rest of the book. Most of
what is covered in this chapter will be covered in much greater
detail later in the book. 1.1 The Fetch and Execute Cycle: Machine
Language A computer is a complex system consisting of many different
components. But at the heart—or the brain, if you want—of the
computer is a single component that does the actual computing. This
is the Central Processing Unit, or CPU. In a modern desktop computer,
the CPU is a single “chip” on the order of one square inch in size.
The job of the CPU is to execute programs. A program is simply a list
of unambiguous instructions meant to be followed mechanically by a
computer. A computer is built to carry out instructions that are
written in a very simple type of language called machine language.
Each type of computer has its own machine language, and the computer
can directly execute a program only if the program is expressed in
that language. (It can execute programs written in other languages if
they are first translated into machine language.) When the CPU
executes a program, that program is stored in the computer’s main
memory (also called the RAM or random access memory). In addition to
the program, memory can also hold data that is being used or
processed by the program. Main memory consists of a sequence of
locations. These locations are numbered, and the sequence number of a
location is called its address. An address provides a way of picking
out one particular piece of information from among the millions
stored in memory. When the CPU needs to access the program
instruction or data in a particular location, it sends the address of
that information as a signal to the memory; the memory responds by
sending back the data contained in the specified 1 2 CHAPTER 1. THE
MENTAL LANDSCAPE location. The CPU can also store information in
memory by specifying the information to be stored and the address of
the location where it is to be stored. On the level of machine
language, the operation of the CPU is fairly straightforward
(although it is very complicated in detail). The CPU executes a
program that is stored as a sequence of machine language instructions
in main memory. It does this by repeatedly reading, or fetching, an
instruction from memory and then carrying out, or executing, that
instruction. This process—fetch an instruction, execute it, fetch
another instruction, execute it, and so on forever—is called the
fetch-and-execute cycle. With one exception, which will be covered in
the next section, this is all that the CPU ever does. The details of
the fetch-and-execute cycle are not terribly important, but there are
a few basic things you should know. The CPU contains a few internal
registers, which are small memory units capable of holding a single
number or machine language instruction. The CPU uses one of these
registers—the program counter, or PC—to keep track of where it is
in the program it is executing. The PC stores the address of the next
instruction that the CPU should execute. At the beginning of each
fetch-and-execute cycle, the CPU checks the PC to see which
instruction it should fetch. During the course of the fetch-and-
execute cycle, the number in the PC is updated to indicate the
instruction that is to be executed in the next cycle. (Usually, but
not always, this is just the instruction that sequentially follows
the current instruction in the program.) ∗ ∗ ∗ A computer executes
machine language programs mechanically—that is without understanding
them or thinking about them—simply because of the way it is
physically put together. This is not an easy concept. A computer is a
machine built of millions of tiny switches called transistors, which
have the property that they can be wired together in such a way that
an output from one switch can turn another switch on or off. As a
computer computes, these switches turn each other on or off in a
pattern determined both by the way they are wired together and by the
program that the computer is executing. Machine language instructions
are expressed as binary numbers. A binary number is made up of just
two possible digits, zero and one. So, a machine language instruction
is just a sequence of zeros and ones. Each particular sequence
encodes some particular instruction. The data that the computer
manipulates is also encoded as binary numbers. A computer can work
directly with binary numbers because switches can readily represent
such numbers: Turn the switch on to represent a one; turn it off to
represent a zero. Machine language instructions are stored in memory
as patterns of switches turned on or off. When a machine language
instruction is loaded into the CPU, all that happens is that certain
switches are turned on or off in the pattern that encodes that
particular instruction. The CPU is built to respond to this pattern
by executing the instruction it encodes; it does this simply because
of the way all the other switches in the CPU are wired together. So,
you should understand this much about how computers work: Main memory
holds machine language programs and data. These are encoded as binary
numbers. The CPU fetches machine language instructions from memory
one after another and executes them. It does this mechanically,
without thinking about or understanding what it does—and therefore
the program it executes must be perfect, complete in all details, and
unambiguous because the CPU can do nothing but execute it exactly as
written. Here is a schematic view of this first-stage understanding
of the computer: 1.2. ASYNCHRONOUS EVENTS 3 Data to memory Data from
memory Address for reading/writing data 1011100001 Program counter:
CPU Memory (Location 0) (Location 1) (Location 2) (Location 3)
(Location 10) 00101110 11010011 01010011 00010000 10111111 10100110
11101001 00000111 10100110 00010001 00111110 1.2 Asynchronous Events:
Polling Loops and Interrupts The CPU spends almost all of its time
fetching instructions from memory and executing them. However, the
CPU and main memory are only two out of many components in a real
computer system. A complete system contains other devices such as: •
A hard disk for storing programs and data files. (Note that main
memory holds only a comparatively small amount of information, and
holds it only as long as the power is turned on. A hard disk is
necessary for permanent storage of larger amounts of information, but
programs have to be loaded from disk into main memory before they can
actually be executed.) • A keyboard and mouse for user input. • A
monitor and printer which can be used to display the computer’s
output. • A modem that allows the computer to communicate with other
computers over telephone lines. • A network interface that allows the
computer to communicate with other computers that are connected to it
on a network. • A scanner that converts images into coded binary
numbers that can be stored and manipulated on the computer. The list
of devices is entirely open ended, and computer systems are built so
that they can easily be expanded by adding new devices. Somehow the
CPU has to communicate with and control all these devices. The CPU
can only do this by executing machine language instructions (which is
all it can do, period). The way this works is that for each device in
a system, there is a device driver, which consists of software that
the CPU executes when it has to deal with the device. Installing a
new device on a system generally has two steps: plugging the device
physically into the computer, and installing the device driver
software. Without the device driver, the actual physical device would
be useless, since the CPU would not be able to communicate with it. 4
CHAPTER 1. THE MENTAL LANDSCAPE ∗ ∗ ∗ A computer system consisting
of many devices is typically organized by connecting those devices to
one or more busses. A bus is a set of wires that carry various sorts
of information between the devices connected to those wires. The
wires carry data, addresses, and control signals. An address directs
the data to a particular device and perhaps to a particular register
or location within that device. Control signals can be used, for
example, by one device to alert another that data is available for it
on the data bus. A fairly simple computer system might be organized
like this: Input/ Output Controller Data bus Address bus Control bus
CPU Empty Slot for future Expansion Keyboard Network Interface ... ...
Network Cable Video Controller and Monitor Memory Now, devices such
as keyboard, mouse, and network interface can produce input that
needs to be processed by the CPU. How does the CPU know that the data
is there? One simple idea, which turns out to be not very
satisfactory, is for the CPU to keep checking for incoming data over
and over. Whenever it finds data, it processes it. This method is
called polling, since the CPU polls the input devices continually to
see whether they have any input data to report. Unfortunately,
although polling is very simple, it is also very inefficient. The CPU
can waste an awful lot of time just waiting for input. To avoid this
inefficiency, interrupts are often used instead of polling. An
interrupt is a signal sent by another device to the CPU. The CPU
responds to an interrupt signal by putting aside whatever it is doing
in order to respond to the interrupt. Once it has handled the
interrupt, it returns to what it was doing before the interrupt
occurred. For example, when you press a key on your computer keyboard,
a keyboard interrupt is sent to the CPU. The CPU responds to this
signal by interrupting what it is doing, reading the key that you
pressed, processing it, and then returning to the task it was
performing before you pressed the key. Again, you should understand
that this is a purely mechanical process: A device signals an
interrupt simply by turning on a wire. The CPU is built so that when
that wire is turned on, the CPU saves enough information about what
it is currently doing so that it can return to the same state later.
This information consists of the contents of important internal
registers such as the program counter. Then the CPU jumps to some
predetermined memory location and begins executing the instructions
stored there. Those instructions make up an interrupt handler that
does the processing necessary to respond to the interrupt. (This
interrupt handler is part of the device driver software for the
device that signalled the interrupt.) At the end of 1.2. ASYNCHRONOUS
EVENTS 5 the interrupt handler is an instruction that tells the CPU
to jump back to what it was doing; it does that by restoring its
previously saved state. Interrupts allow the CPU to deal with
asynchronous events. In the regular fetch-andexecute cycle, things
happen in a predetermined order; everything that happens is
“synchronized” with everything else. Interrupts make it possible
for the CPU to deal efficiently with events that happen
“asynchronously,” that is, at unpredictable times. As another
example of how interrupts are used, consider what happens when the
CPU needs to access data that is stored on the hard disk. The CPU can
access data directly only if it is in main memory. Data on the disk
has to be copied into memory before it can be accessed. Unfortunately,
on the scale of speed at which the CPU operates, the disk drive is
extremely slow. When the CPU needs data from the disk, it sends a
signal to the disk drive telling it to locate the data and get it
ready. (This signal is sent synchronously, under the control of a
regular program.) Then, instead of just waiting the long and
unpredictalble amount of time that the disk drive will take to do
this, the CPU goes on with some other task. When the disk drive has
the data ready, it sends an interrupt signal to the CPU. The
interrupt handler can then read the requested data. ∗ ∗ ∗ Now, you
might have noticed that all this only makes sense if the CPU actually
has several tasks to perform. If it has nothing better to do, it
might as well spend its time polling for input or waiting for disk
drive operations to complete. All modern computers use multitasking
to perform several tasks at once. Some computers can be used by
several people at once. Since the CPU is so fast, it can quickly
switch its attention from one user to another, devoting a fraction of
a second to each user in turn. This application of multitasking is
called timesharing. But a modern personal computer with just a single
user also uses multitasking. For example, the user might be typing a
paper while a clock is continuously displaying the time and a file is
being downloaded over the network. Each of the individual tasks that
the CPU is working on is called a thread. (Or a process; there are
technical differences between threads and processes, but they are not
important here.) At any given time, only one thread can actually be
executed by a CPU. The CPU will continue running the same thread
until one of several things happens: • The thread might voluntarily
yield control, to give other threads a chance to run. • The thread
might have to wait for some asynchronous event to occur. For example,
the thread might request some data from the disk drive, or it might
wait for the user to press a key. While it is waiting, the thread is
said to be blocked, and other threads have a chance to run. When the
event occurs, an interrupt will “wake up” the thread so that it can
continue running. • The thread might use up its allotted slice of
time and be suspended to allow other threads to run. Not all
computers can “forcibly” suspend a thread in this way; those that
can are said to use preemptive multitasking. To do preemptive
multitasking, a computer needs a special timer device that generates
an interrupt at regular intervals, such as 100 times per second. When
a timer interrupt occurs, the CPU has a chance to switch from one
thread to another, whether the thread that is currently running likes
it or not. Ordinary users, and indeed ordinary programmers, have no
need to deal with interrupts and interrupt handlers. They can
concentrate on the different tasks or threads that they want the
computer to perform; the details of how the computer manages to get
all those tasks done are not important to them. In fact, most users,
and many programmers, can ignore threads and 6 CHAPTER 1. THE MENTAL
LANDSCAPE multitasking altogether. However, threads have become
increasingly important as computers have become more powerful and as
they have begun to make more use of multitasking. Indeed, threads are
built into the Java programming language as a fundamental programming
concept. Just as important in Java and in modern programming in
general is the basic concept of asynchronous events. While
programmers don’t actually deal with interrupts directly, they do
often find themselves writing event handlers, which, like interrupt
handlers, are called asynchronously when specified events occur. Such
“event-driven programming” has a very different feel from the more
traditional straight-through, synchronous programming. We will begin
with the more traditional type of programming, which is still used
for programming individual tasks, but we will return to threads and
events later in the text. ∗ ∗ ∗ By the way, the software that does
all the interrupt handling and the communication with the user and
with hardware devices is called the operating system. The operating
system is the basic, essential software without which a computer
would not be able to function. Other programs, such as word
processors and World Wide Web browsers, are dependent upon the
operating system. Common operating systems include Linux, DOS,
Windows 2000, Windows XP, and the Macintosh OS. 1.3 The Java Virtual
Machine Machine language consists of very simple instructions that
can be executed directly by the CPU of a computer. Almost all
programs, though, are written in high-level programming languages
such as Java, Pascal, or C++. A program written in a high-level
language cannot be run directly on any computer. First, it has to be
translated into machine language. This translation can be done by a
program called a compiler. A compiler takes a high-level-language
program and translates it into an executable machine-language program.
Once the translation is done, the machine-language program can be run
any number of times, but of course it can only be run on one type of
computer (since each type of computer has its own individual machine
language). If the program is to run on another type of computer it
has to be re-translated, using a different compiler, into the
appropriate machine language. There is an alternative to compiling a
high-level language program. Instead of using a compiler, which
translates the program all at once, you can use an interpreter, which
translates it instruction-by-instruction, as necessary. An
interpreter is a program that acts much like a CPU, with a kind of
fetch-and-execute cycle. In order to execute a program, the
interpreter runs in a loop in which it repeatedly reads one
instruction from the program, decides what is necessary to carry out
that instruction, and then performs the appropriate machine-language
commands to do so. One use of interpreters is to execute high-level
language programs. For example, the programming language Lisp is
usually executed by an interpreter rather than a compiler. However,
interpreters have another purpose: they can let you use a machine-
language program meant for one type of computer on a completely
different type of computer. For example, there is a program called
“Virtual PC” that runs on Macintosh computers. Virtual PC is an
interpreter that executes machine-language programs written for IBM-
PC-clone computers. If you run Virtual PC on your Macintosh, you can
run any PC program, including programs written for Windows.
(Unfortunately, a PC program will run much more slowly than it would
on an actual IBM clone. The problem is that Virtual PC executes
several Macintosh machine-language instructions for 1.3. THE JAVA
VIRTUAL MACHINE 7 each PC machine-language instruction in the program
it is interpreting. Compiled programs are inherently faster than
interpreted programs.) ∗ ∗ ∗ The designers of Java chose to use a
combination of compilation and interpretation. Programs written in
Java are compiled into machine language, but it is a machine language
for a computer that doesn’t really exist. This so-called “virtual”
computer is known as the Java virtual machine. The machine language
for the Java virtual machine is called Java bytecode. There is no
reason why Java bytecode could not be used as the machine language of
a real computer, rather than a virtual computer. However, one of the
main selling points of Java is that it can actually be used on any
computer. All that the computer needs is an interpreter for Java
bytecode. Such an interpreter simulates the Java virtual machine in
the same way that Virtual PC simulates a PC computer. Of course, a
different Jave bytecode interpreter is needed for each type of
computer, but once a computer has a Java bytecode interpreter, it can
run any Java bytecode program. And the same Java bytecode program can
be run on any computer that has such an interpreter. This is one of
the essential features of Java: the same compiled program can be run
on many different types of computers. J a v a P r o g r a m C o m p i
l e r J a v a B y t e c o d e P r o g r a m J a v a I n t e r p r e t
e r f o r M a c O S J a v a I n t e r p r e t e r f o r W i n d o w s
J a v a I n t e r p r e t e r f o r L i n u x Why, you might wonder,
use the intermediate Java bytecode at all? Why not just distribute
the original Java program and let each person compile it into the
machine language of whatever computer they want to run it on? There
are many reasons. First of all, a compiler has to understand Java, a
complex high-level language. The compiler is itself a complex program.
A Java bytecode interpreter, on the other hand, is a fairly small,
simple program. This makes it easy to write a bytecode interpreter
for a new type of computer; once that is done, that computer can run
any compiled Java program. It would be much harder to write a Java
compiler for the same computer. Furthermore, many Java programs are
meant to be downloaded over a network. This leads to obvious security
concerns: you don’t want to download and run a program that will
damage your computer or your files. The bytecode interpreter acts as
a buffer between you and the program you download. You are really
running the interpreter, which runs the downloaded program indirectly.
The interpreter can protect you from potentially dangerous actions on
the part of that program. I should note that there is no necessary
connection between Java and Java bytecode. A program written in Java
could certainly be compiled into the machine language of a real
computer. And programs written in other languages could be compiled
into Java bytecode. However, it is the combination of Java and Java
bytecode that is platform-independent, secure, and networkcompatible
while allowing you to program in a modern high-level object-oriented
language. 8 CHAPTER 1. THE MENTAL LANDSCAPE ∗ ∗ ∗ I should also
note that the really hard part of platform-independence is providing
a “Graphical User Interface”—with windows, buttons, etc.—that
will work on all the platforms that support Java. You’ll see more
about this problem in Section 1.6. 1.4 Fundamental Building Blocks of
Programs There are two basic aspects of programming: data and
instructions. To work with data, you need to understand variables and
types; to work with instructions, you need to understand control
structures and subroutines. You’ll spend a large part of the course
becoming familiar with these concepts. A variable is just a memory
location (or several locations treated as a unit) that has been given
a name so that it can be easily referred to and used in a program.
The programmer only has to worry about the name; it is the
compiler’s responsibility to keep track of the memory location. The
programmer does need to keep in mind that the name refers to a kind
of “box” in memory that can hold data, even if the programmer
doesn’t have to know where in memory that box is located. In Java
and most other languages, a variable has a type that indicates what
sort of data it can hold. One type of variable might hold integers—
whole numbers such as 3, -7, and 0— while another holds floating
point numbers—numbers with decimal points such as 3.14, -2.7, or
17.0. (Yes, the computer does make a distinction between the integer
17 and the floatingpoint number 17.0; they actually look quite
different inside the computer.) There could also be types for
individual characters (’A’, ’;’, etc.), strings (“Hello”, “A
string can include many characters”, etc.), and less common types
such as dates, colors, sounds, or any other type of data that a
program might need to store. Programming languages always have
commands for getting data into and out of variables and for doing
computations with data. For example, the following “assignment
statement,” which might appear in a Java program, tells the computer
to take the number stored in the variable named “principal”,
multiply that number by 0.07, and then store the result in the
variable named “interest”: interest = principal * 0.07; There are
also “input commands” for getting data from the user or from files
on the computer’s disks and “output commands” for sending data in
the other direction. These basic commands—for moving data from place
to place and for performing computations—are the building blocks for
all programs. These building blocks are combined into complex
programs using control structures and subroutines. ∗ ∗ ∗ A program
is a sequence of instructions. In the ordinary “flow of control,”
the computer executes the instructions in the sequence in which they
appear, one after the other. However, this is obviously very limited:
the computer would soon run out of instructions to execute. Control
structures are special instructions that can change the flow of
control. There are two basic types of control structure: loops, which
allow a sequence of instructions to be repeated over and over, and
branches, which allow the computer to decide between two or more
different courses of action by testing conditions that occur as the
program is running. For example, it might be that if the value of the
variable “principal” is greater than 10000, then the “interest”
should be computed by multiplying the principal by 0.05; if not, then
the 1.5. OBJECT-ORIENTED PROGRAMMING 9 interest should be computed by
multiplying the principal by 0.04. A program needs some way of
expressing this type of decision. In Java, it could be expressed
using the following “if statement”: if (principal > 10000) interest
= principal * 0.05; else interest = principal * 0.04; (Don’t worry
about the details for now. Just remember that the computer can test a
condition and decide what to do next on the basis of that test.)
Loops are used when the same task has to be performed more than once.
For example, if you want to print out a mailing label for each name
on a mailing list, you might say, “Get the first name and address
and print the label; get the second name and address and print the
label; get the third name and address and print the label—” But
this quickly becomes ridiculous—and might not work at all if you
don’t know in advance how many names there are. What you would like
to say is something like “While there are more names to process, get
the next name and address, and print the label.” A loop can be used
in a program to express such repetition. ∗ ∗ ∗ Large programs are
so complex that it would be almost impossible to write them if there
were not some way to break them up into manageable “chunks.”
Subroutines provide one way to do this. A subroutine consists of the
instructions for performing some task, grouped together as a unit and
given a name. That name can then be used as a substitute for the
whole set of instructions. For example, suppose that one of the tasks
that your program needs to perform is to draw a house on the screen.
You can take the necessary instructions, make them into a subroutine,
and give that subroutine some appropriate name—say, “drawHouse()”.
Then anyplace in your program where you need to draw a house, you can
do so with the single command: drawHouse(); This will have the same
effect as repeating all the house-drawing instructions in each place.
The advantage here is not just that you save typing. Organizing your
program into subroutines also helps you organize your thinking and
your program design effort. While writing the house-drawing
subroutine, you can concentrate on the problem of drawing a house
without worrying for the moment about the rest of the program. And
once the subroutine is written, you can forget about the details of
drawing houses—that problem is solved, since you have a subroutine
to do it for you. A subroutine becomes just like a built-in part of
the language which you can use without thinking about the details of
what goes on “inside” the subroutine. ∗ ∗ ∗ Variables, types,
loops, branches, and subroutines are the basis of what might be
called “traditional programming.” However, as programs become
larger, additional structure is needed to help deal with their
complexity. One of the most effective tools that has been found is
objectoriented programming, which is discussed in the next section.
1.5 Objects and Object-oriented Programming Programs must be designed.
No one can just sit down at the computer and compose a program of any
complexity. The discipline called software engineering is concerned
with 10 CHAPTER 1. THE MENTAL LANDSCAPE the construction of correct,
working, well-written programs. The software engineer tends to use
accepted and proven methods for analyzing the problem to be solved
and for designing a program to solve that problem. During the 1970s
and into the 80s, the primary software engineering methodology was
structured programming. The structured programming approach to
program design was based on the following advice: To solve a large
problem, break the problem into several pieces and work on each piece
separately; to solve each piece, treat it as a new problem which can
itself be broken down into smaller problems; eventually, you will
work your way down to problems that can be solved directly, without
further decomposition. This approach is called top-down programming.
There is nothing wrong with top-down programming. It is a valuable
and often-used approach to problem-solving. However, it is incomplete.
For one thing, it deals almost entirely with producing the
instructions necessary to solve a problem. But as time went on,
people realized that the design of the data structures for a program
was as least as important as the design of subroutines and control
structures. Top-down programming doesn’t give adequate consideration
to the data that the program manipulates. Another problem with strict
top-down programming is that it makes it difficult to reuse work done
for other projects. By starting with a particular problem and
subdividing it into convenient pieces, top-down programming tends to
produce a design that is unique to that problem. It is unlikely that
you will be able to take a large chunk of programming from another
program and fit it into your project, at least not without extensive
modification. Producing high-quality programs is difficult and
expensive, so programmers and the people who employ them are always
eager to reuse past work. ∗ ∗ ∗ So, in practice, top-down design
is often combined with bottom-up design. In bottom-up design, the
approach is to start “at the bottom,” with problems that you
already know how to solve (and for which you might already have a
reusable software component at hand). From there, you can work
upwards towards a solution to the overall problem. The reusable
components should be as “modular” as possible. A module is a
component of a larger system that interacts with the rest of the
system in a simple, well-defined, straightforward manner. The idea is
implement. But applets are only one aspect of Java’s relationship
with the Internet, and not the major one. In fact, as both Java and
the Internet have matured, applets have become less important. At the
same time, however, Java has increasingly been used to write complex,
stand-alone applications that do not depend on a web browser. Many of
these programs are networkrelated. For example many of the largest
and most complex web sites use web server software that is written in
Java. Java includes excellent support for network protocols, and its
platform independence makes it possible to write network programs
that work on many different types of computer. Its association with
the Internet is not Java’s only advantage. But many good programming
languages have been invented only to be soon forgotten. Java has had
the good luck to ride on the coattails of the Internet’s immense and
increasing popularity. Quiz 17 Quiz on Chapter 1 1. One of the
components of a computer is its CPU. What is a CPU and what role does
it play in a computer? 2. Explain what is meant by an “asynchronous
event.” Give some examples. 3. What is the difference between a
“compiler” and an “interpreter”? 4. Explain the difference
between high-level languages and machine language. 5. If you have the
source code for a Java program, and you want to run that program, you
will need both a compiler and an interpreter. What does the Java
compiler do, and what does the Java interpreter do? 6. What is a
subroutine? 7. Java is an object-oriented programming language. What
is an object? 8. What is a variable? (There are four different ideas
associated with variables in Java. Try to mention all four aspects in
your answer. Hint: One of the aspects is the variable’s name.) 9.
Java is a “platform-independent language.” What does this mean? 10.
What is the “Internet”? Give some examples of how it is used. (What
kind of services does it provide?) 18 CHAPTER 1. THE MENTAL LANDSCAPE
Chapter 2 Programming in the Small I: Names and Things On a basic
level (the level of machine language), a computer can perform only
very simple operations. A computer performs complex tasks by
stringing together large numbers of such operations. Such tasks must
be “scripted” in complete and perfect detail by programs. Creating
complex programs will never be really easy, but the difficulty can be
handled to some extent by giving the program a clear overall
structure. The design of the overall structure of a program is what I
call “programming in the large.” Programming in the small, which is
sometimes called coding, would then refer to filling in the details
of that design. The details are the explicit, step-by-step
instructions for performing fairly small-scale tasks. When you do
coding, you are working fairly “close to the machine,” with some of
the same concepts that you might use in machine language: memory
locations, arithmetic operations, loops and branches. In a high-level
language such as Java, you get to work with these concepts on a level
several steps above machine language. However, you still have to
worry about getting all the details exactly right. This chapter and
the next examine the facilities for programming in the small in the
Java programming language. Don’t be misled by the term “programming
in the small” into thinking that this material is easy or
unimportant. This material is an essential foundation for all types
of programming. If you don’t understand it, you can’t write
programs, no matter how good you get at designing their large-scale
structure. 2.1 The Basic Java Application A program is a sequence of
instructions that a computer can execute to perform some task. A
simple enough idea, but for the computer to make any use of the
instructions, they must be written in a form that the computer can
use. This means that programs have to be written in programming
languages. Programming languages differ from ordinary human languages
in being completely unambiguous and very strict about what is and is
not allowed in a program. The rules that determine what is allowed
are called the syntax of the language. Syntax rules specify the basic
vocabulary of the language and how programs can be constructed using
things like loops, branches, and subroutines. A syntactically correct
program is one that can be successfully compiled or interpreted;
programs that have syntax errors will be rejected (hopefully with a
useful error message that will help you fix the problem). So, to be a
successful programmer, you have to develop a detailed knowledge of
the syntax 19 20 CHAPTER 2. NAMES AND THINGS of the programming
language that you are using. However, syntax is only part of the
story. It’s not enough to write a program that will run—you want a
program that will run and produce the correct result! That is, the
meaning of the program has to be right. The meaning of a program is
referred to as its semantics. A semantically correct program is one
that does what you want it to. Furthermore, a program can be
syntactically and semantically correct but still be a pretty bad
program. Using the language correctly is not the same as using it
well. For example, a good program has “style.” It is written in a
way that will make it easy for people to read and to understand. It
follows conventions that will be familiar to other programmers. And
it has an overall design that will make sense to human readers. The
computer is completely oblivious to such things, but to a human
reader, they are paramount. These aspects of programming are
sometimes referred to as pragmatics. When I introduce a new language
feature, I will explain the syntax, the semantics, and some of the
pragmatics of that feature. You should memorize the syntax; that’s
the easy part. Then you should get a feeling for the semantics by
following the examples given, making sure that you understand how
they work, and maybe writing short programs of your own to test your
understanding. And you should try to appreciate and absorb the
pragmatics—this means learning how to use the language feature well,
with style that will earn you the admiration of other programmers. Of
course, even when you’ve become familiar with all the individual
features of the language, that doesn’t make you a programmer. You
still have to learn how to construct complex programs to solve
particular problems. For that, you’ll need both experience and taste.
You’ll find hints about software development throughout this
textbook. ∗ ∗ ∗ We begin our exploration of Java with the problem
that has become traditional for such beginnings: to write a program
that displays the message “Hello World!”. This might seem like a
trivial problem, but getting a computer to do this is really a big
first step in learning a new programming language (especially if
it’s your first programming language). It means that you understand
the basic process of: 1. getting the program text into the computer,
2. compiling the program, and 3. running the compiled program. The
first time through, each of these steps will probably take you a few
tries to get right. I won’t go into the details here of how you do
each of these steps; it depends on the particular computer and Java
programming environment that you are using. See Section 2.6 for
information about creating and running Java programs in specific
programming environments. But in general, you will type the program
using some sort of text editor and save the program in a file. Then,
you will use some command to try to compile the file. You’ll either
get a message that the program contains syntax errors, or you’ll get
a compiled version of the program. In the case of Java, the program
is compiled into Java bytecode, not into machine language. Finally,
you can run the compiled program by giving some appropriate command.
For Java, you will actually use an interpreter to execute the Java
bytecode. Your programming environment might automate some of the
steps for you, but you can be sure that the same three steps are
being done in the background. Here is a Java program to display the
message “Hello World!”. Don’t expect to understand what’s going
on here just yet—some of it you won’t really understand until a few
chapters from 2.1. THE BASIC JAVA APPLICATION 21 now: // A program to
display the message // "Hello World!" on standard output public class
HelloWorld { public static void main(String[] args)
{ System.out.println("Hello World!"); } } // end of class HelloWorld
The command that actually displays the message is:
System.out.println("Hello World!"); This command is an example of a
subroutine call statement. It uses a “built-in subroutine” named
System.out.println to do the actual work. Recall that a subroutine
consists of the instructions for performing some task, chunked
together and given a name. That name can be used to “call” the
subroutine whenever that task needs to be performed. A built-in
subroutine is one that is already defined as part of the language and
therefore automatically available for use in any program. When you
run this program, the message “Hello World!” (without the quotes)
will be displayed on standard output. Unfortunately, I can’t say
exactly what that means! Java is meant to run on many different
platforms, and standard output will mean different things on
different platforms. However, you can expect the message to show up
in some convenient place. (If you use a command-line interface, like
that in Sun Microsystem’s Java Development Kit, you type in a
command to tell the computer to run the program. The computer will
type the output from the program, Hello World!, on the next line.)
You must be curious about all the other stuff in the above program.
Part of it consists of comments. Comments in a program are entirely
ignored by the computer; they are there for human readers only. This
doesn’t mean that they are unimportant. Programs are meant to be
read by people as well as by computers, and without comments, a
program can be very difficult to understand. Java has two types of
comments. The first type, used in the above program, begins with //
and extends to the end of a line. The computer ignores the // and
everything that follows it on the same line. Java has another style
of comment that can extend over many lines. That type of comment
begins with /* and ends with */. Everything else in the program is
required by the rules of Java syntax. All programming in Java is done
inside “classes.” The first line in the above program (not counting
the comments) says that this is a class named HelloWorld.
“HelloWorld,” the name of the class, also serves as the name of the
program. Not every class is a program. In order to define a program,
a class must include a subroutine named main, with a definition that
takes the form: public static void main(String[] args) { hstatements
i } When you tell the Java interpreter to run the program, the
interpreter calls the main() subroutine, and the statements that it
contains are executed. These statements make up the script that tells
the computer exactly what to do when the program is executed. The
main() routine can call subroutines that are defined in the same
class or even in other classes, but it is the main() routine that
determines how and in what order the other subroutines are used. 22
CHAPTER 2. NAMES AND THINGS The word “public” in the first line of
main() means that this routine can be called from outside the program.
This is essential because the main() routine is called by the Java
interpreter, which is something external to the program itself. The
remainder of the first line of the routine is harder to explain at
the moment; for now, just think of it as part of the required syntax.
The definition of the subroutine—that is, the instructions that say
what it does—consists of the sequence of “statements” enclosed
between braces, { and }. Here, I’ve used hstatementsi as a
placeholder for the actual statements that make up the program.
Throughout this textbook, I will always use a similar format:
anything that you see in hthis style of texti (italic in angle
brackets) is a placeholder that describes something you need to type
when you write an actual program. As noted above, a subroutine can’t
exist by itself. It has to be part of a “class”. A program is
defined by a public class that takes the form: public class hprogram-
namei { hoptional-variable-declarations-and-subroutinesi public
static void main(String[] args) { hstatementsi } hoptional-variable-
declarations-and-subroutinesi } The name on the first line is the
name of the program, as well as the name of the class. If the name of
the class is HelloWorld, then the class must be saved in a file
called HelloWorld.java. When this file is compiled, another file
named HelloWorld.class will be produced. This class file,
HelloWorld.class, contains the Java bytecode that is executed by a
Java interpreter. HelloWorld.java is called the source code for the
program. To execute the program, you only need the compiled class
file, not the source code. The layout of the program on the page,
such as the use of blank lines and indentation, is not part of the
syntax or semantics of the language. The computer doesn’t care about
layout— you could run the entire program together on one line as far
as it is concerned. However, layout is important to human readers,
and there are certain style guidelines for layout that are followed
by most programmers. These style guidelines are part of the
pragmatics of the Java programming language. Also note that according
to the above syntax specification, a program can contain other
subroutines besides main(), as well as things called “variable
declarations.” You’ll learn more about these later, but not until
Chapter 4. 2.2 Variables and the Primitive Types Names are
fundamental to programming. In programs, names are used to refer to
many different sorts of things. In order to use those things, a
programmer must understand the rules for giving names to things and
the rules for using the names to work with those things. That is, the
programmer must understand the syntax and the semantics of names.
According to the syntax rules of Java, a name is a sequence of one or
more characters. It must begin with a letter or underscore and must
consist entirely of letters, digits, and underscores. (“Underscore”
refers to the character ’ ’.) For example, here are some legal
names: N n rate x15 quite a long name HelloWorld 2.2. VARIABLES AND
TYPES 23 No spaces are allowed in identifiers; HelloWorld is a legal
identifier, but “Hello World” is not. Upper case and lower case
letters are considered to be different, so that HelloWorld,
helloworld, HELLOWORLD, and hElloWorLD are all distinct names.
Certain names are reserved for special uses in Java, and cannot be
used by the programmer for other purposes. These reserved words
include: class, public, static, if, else, while, and several dozen
other words. Java is actually pretty liberal about what counts as a
letter or a digit. Java uses the Unicode character set, which
includes thousands of characters from many different languages and
different alphabets, and many of these characters count as letters or
digits. However, I will be sticking to what can be typed on a regular
English keyboard. The pragmatics of naming includes style guidelines
about how to choose names for things. For example, it is customary
for names of classes to begin with upper case letters, while names of
variables and of subroutines begin with lower case letters; you can
avoid a lot of confusion by following the same convention in your own
programs. Most Java programmers do not use underscores in names,
although some do use them at the beginning of the names of certain
kinds of variables. When a name is made up of several words, such as
HelloWorld or interestRate, it is customary to capitalize each word,
except possibly the first; this is sometimes referred to as camel
case, since the upper case letters in the middle of a name are
supposed to look something like the humps on a camel’s back. Finally,
I’ll note that things are often referred to by compound names which
consist of several ordinary names separated by periods. (Compound
names are also called qualified names.) You’ve already seen an
example: System.out.println. The idea here is that things in Java can
contain other things. A compound name is a kind of path to an item
through one or more levels of containment. The name
System.out.println indicates that something called “System”
contains something called “out” which in turn contains something
called “println”. Non-compound names are called simple identifiers.
I’ll use the term identifier to refer to any name—simple or
compound—that can be used to refer to something in Java. (Note that
the reserved words are not identifiers, since they can’t be used as
names for things.) 2.2.1 Variables Programs manipulate data that are
stored in memory. In machine language, data can only be referred to
by giving the numerical address of the location in memory where it is
stored. In a high-level language such as Java, names are used instead
of numbers to refer to data. It is the job of the computer to keep
track of where in memory the data is actually stored; the programmer
only has to remember the name. A name used in this way—to refer to
data stored in memory—is called a variable. Variables are actually
rather subtle. Properly speaking, a variable is not a name for the
data itself but for a location in memory that can hold data. You
should think of a variable as a container or box where you can store
data that you will need to use later. The variable refers directly to
the box and only indirectly to the data in the box. Since the data in
the box can change, a variable can refer to different data values at
different times during the execution of the program, but it always
refers to the same box. Confusion can arise, especially for beginning
programmers, because when a variable is used in a program in certain
ways, it refers to the container, but when it is used in other ways,
it refers to the data in the container. You’ll see examples of both
cases below. (In this way, a variable is something like the title,
“The President of the United States.” This title can refer to
different people at different times, but it always refers to the same
office. 24 CHAPTER 2. NAMES AND THINGS If I say “the President went
fishing,” I mean that George W. Bush went fishing. But if I say
“Hillary Clinton wants to be President” I mean that she wants to
fill the office, not that she wants to be George Bush.) In Java, the
only way to get data into a variable—that is, into the box that the
variable names—is with an assignment statement. An assignment
statement takes the form: hvariable i = hexpression i; where
hexpressioni represents anything that refers to or computes a data
value. When the computer comes to an assignment statement in the
course of executing a program, it evaluates the expression and puts
the resulting data value into the variable. For example, consider the
simple assignment statement rate = 0.07; The hvariablei in this
assignment statement is rate, and the hexpressioni is the number 0.07.
The computer executes this assignment statement by putting the number
0.07 in the variable rate, replacing whatever was there before. Now,
consider the following more complicated assignment statement, which
might come later in the same program: interest = rate * principal;
Here, the value of the expression “rate * principal” is being
assigned to the variable interest. In the expression, the * is a
“multiplication operator” that tells the computer to multiply rate
times principal. The names rate and principal are themselves
variables, and it is really the values stored in those variables that
are to be multiplied. We see that when a variable is used in an
expression, it is the value stored in the variable that matters; in
this case, the variable seems to refer to the data in the box, rather
than to the box itself. When the computer executes this assignment
statement, it takes the value of rate, multiplies it by the value of
principal, and stores the answer in the box referred to by interest.
When a variable is used on the left-hand side of an assignment
statement, it refers to the box that is named by the variable. (Note,
by the way, that an assignment statement is a command that is
executed by the computer at a certain time. It is not a statement of
fact. For example, suppose a program includes the statement “rate =
0.07;”. If the statement “interest = rate * principal;” is
executed later in the program, can we say that the principal is
multiplied by 0.07? No! The value of rate might have been changed in
the meantime by another statement. The meaning of an assignment
statement is completely different from the meaning of an equation in
mathematics, even though both use the symbol “=”.) 2.2.2 Types and
Literals A variable in Java is designed to hold only one particular
type of data; it can legally hold that type of data and no other. The
compiler will consider it to be a syntax error if you try to violate
this rule. We say that Java is a strongly typed language because it
enforces this rule. There are eight so-called primitive types built
into Java. The primitive types are named byte, short, int, long,
float, double, char, and boolean. The first four types hold integers
(whole numbers such as 17, -38477, and 0). The four integer types are
distinguished by the ranges of integers they can hold. The float and
double types hold real numbers (such as 3.6 and -145.99). Again, the
two real types are distinguished by their range and accuracy. A
variable of type char holds a single character from the Unicode
character set. And a variable of type boolean holds one of the two
logical values true or false. 2.2. VARIABLES AND TYPES 25 Any data
value stored in the computer’s memory must be represented as a
binary number, that is as a string of zeros and ones. A single zero
or one is called a bit. A string of eight bits is called a byte.
Memory is usually measured in terms of bytes. Not surprisingly, the
byte data type refers to a single byte of memory. A variable of type
byte holds a string of eight bits, which can represent any of the
integers between -128 and 127, inclusive. (There are 256 integers in
that range; eight bits can represent 256—two raised to the power
eight—different values.) As for the other integer types, • short
corresponds to two bytes (16 bits). Variables of type short have
values in the range -32768 to 32767. • int corresponds to four bytes
(32 bits). Variables of type int have values in the range -2147483648
to 2147483647. • long corresponds to eight bytes (64 bits). Variables
of type long have values in the range -9223372036854775808 to
9223372036854775807. You don’t have to remember these numbers, but
they do give you some idea of the size of integers that you can work
with. Usually, you should just stick to the int data type, which is
good enough for most purposes. The float data type is represented in
four bytes of memory, using a standard method for encoding real
numbers. The maximum value for a float is about 10 raised to the
power 38. A float can have about 7 significant digits. (So that
32.3989231134 and 32.3989234399 would both have to be rounded off to
about 32.398923 in order to be stored in a variable of type float.) A
double takes up 8 bytes, can range up to about 10 to the power 308,
and has about 15 significant digits. Ordinarily, you should stick to
the double type for real values. A variable of type char occupies two
bytes in memory. The value of a char variable is a single character
such as A, *, x, or a space character. The value can also be a
special character such a tab or a carriage return or one of the many
Unicode characters that come from different languages. When a
character is typed into a program, it must be surrounded by single
quotes; for example: ’A’, ’*’, or ’x’. Without the quotes, A
would be an identifier and * would be a multiplication operator. The
quotes are not part of the value and are not stored in the variable;
they are just a convention for naming a particular character constant
in a program. A name for a constant value is called a literal. A
literal is what you have to type in a program to represent a
value. ’A’ and ’*’ are literals of type char, representing the
character values A and *. Certain special characters have special
literals that use a backslash, \, as an “escape character”. In
particular, a tab is represented as ’\t’, a carriage return
as ’\r’, a linefeed as ’\n’, the single quote character
as ’\’’, and the backslash itself as ’\\’. Note that even though
you type two characters between the quotes in ’\t’, the value
represented by this literal is a single tab character. Numeric
literals are a little more complicated than you might expect. Of
course, there are the obvious literals such as 317 and 17.42. But
there are other possibilities for expressing numbers in a Java
program. First of all, real numbers can be represented in an
exponential form such as 1.3e12 or 12.3737e-108. The “e12” and “e-
108” represent powers of 10, so that 1.3e12 means 1.3 times 1012 and
12.3737e-108 means 12.3737 times 10−108. This format can be used to
express very large and very small numbers. Any numerical literal that
contains a decimal point or exponential is a literal of type double.
To make a literal of type float, you have to append an “F” or “f”
to the end of the number. For example, “1.2F” stands for 1.2
considered as a value of type float. (Occasionally, you need to know
this because the rules of Java say that you can’t assign a value of
type double to a variable of type float, so you might be 26 CHAPTER 2.
NAMES AND THINGS confronted with a ridiculous-seeming error message
if you try to do something like “x = 1.2;” when x is a variable of
type float. You have to say “x = 1.2F;". This is one reason why I
advise sticking to type double for real numbers.) Even for integer
literals, there are some complications. Ordinary integers such as
177777 and -32 are literals of type byte, short, or int, depending on
their size. You can make a literal of type long by adding “L” as a
suffix. For example: 17L or 728476874368L. As another complication,
Java allows octal (base-8) and hexadecimal (base-16) literals. I
don’t want to cover base-8 and base-16 in detail, but in case you
run into them in other people’s programs, it’s worth knowing a few
things: Octal numbers use only the digits 0 through 7. In Java, a
numeric literal that begins with a 0 is interpreted as an octal
number; for example, the literal 045 represents the number 37, not
the number 45. Hexadecimal numbers use 16 digits, the usual digits 0
through 9 and the letters A, B, C, D, E, and F. Upper case and lower
case letters can be used interchangeably in this context. The letters
represent the numbers 10 through 15. In Java, a hexadecimal literal
begins with 0x or 0X, as in 0x45 or 0xFF7A. Hexadecimal numbers are
also used in character literals to represent arbitrary Unicode
characters. A Unicode literal consists of \u followed by four
hexadecimal digits. For example, the character literal ’\u00E9’
represents the Unicode character that is an “e” with an acute
accent. For the type boolean, there are precisely two literals: true
and false. These literals are typed just as I’ve written them here,
without quotes, but they represent values, not variables. Boolean
values occur most often as the values of conditional expressions. For
example, rate > 0.05 is a boolean-valued expression that evaluates to
true if the value of the variable rate is greater than 0.05, and to
false if the value of rate is not greater than 0.05. As you’ll see
in Chapter 3, boolean-valued expressions are used extensively in
control structures. Of course, boolean values can also be assigned to
variables of type boolean. Java has other types in addition to the
primitive types, but all the other types represent objects rather
than “primitive” data values. For the most part, we are not
concerned with objects for the time being. However, there is one
predefined object type that is very important: the type String. A
String is a sequence of characters. You’ve already seen a string
literal: "Hello World!". The double quotes are part of the literal;
they have to be typed in the program. However, they are not part of
the actual string value, which consists of just the characters
between the quotes. Within a string, special characters can be
represented using the backslash notation. Within this context, the
double quote is itself a special character. For example, to represent
the string value I said, "Are you listening!" with a linefeed at the
end, you would have to type the string literal: "I said, \"Are you
listening!\"\n" You can also use \t, \r, \\, and unicode sequences
such as \u00E9 to represent other special characters in string
literals. Because strings are objects, their behavior in programs is
peculiar in some respects (to someone who is not used to objects).
I’ll have more to say about them in the next section. 2.2. VARIABLES
AND TYPES 27 2.2.3 Variables in Programs A variable can be used in a
program only if it has first been declared. A variable declaration
statement is used to declare one or more variables and to give them
names. When the computer executes a variable declaration, it sets
aside memory for the variable and associates the variable’s name
with that memory. A simple variable declaration takes the form:
htype-name i hvariable-name-or-namesi; The hvariable-name-or-namesi
can be a single variable name or a list of variable names separated
by commas. (We’ll see later that variable declaration statements can
actually be somewhat more complicated than this.) Good programming
style is to declare only one variable in a declaration statement,
unless the variables are closely related in some way. For example:
int numberOfStudents; String name; double x, y; boolean isFinished;
char firstInitial, middleInitial, lastInitial; It is also good style
to include a comment with each variable declaration to explain its
purpose in the program, or to give other information that might be
useful to a human reader. For example: double principal; // Amount of
money invested. double interestRate; // Rate as a decimal, not
percentage. In this chapter, we will only use variables declared
inside the main() subroutine of a program. Variables declared inside
a subroutine are called local variables for that subroutine. They
exist only inside the subroutine, while it is running, and are
completely inaccessible from outside. Variable declarations can occur
anywhere inside the subroutine, as long as each variable is declared
before it is used in any expression. Some people like to declare all
the variables at the beginning of the subroutine. Others like to wait
to declare a variable until it is needed. My preference: Declare
important variables at the beginning of the subroutine, and use a
comment to explain the purpose of each variable. Declare “utility
variables” which are not important to the overall logic of the
subroutine at the point in the subroutine where they are first used.
Here is a simple program using some variables and assignment
statements: /** * This class implements a simple program that * will
compute the amount of interest that is * earned on $17,000 invested
at an interest * rate of 0.07 for one year. The interest and * the
value of the investment after one year are * printed to standard
output. */ public class Interest { public static void main(String[]
args) { /* Declare the variables. */ double principal; // The value
of the investment. double rate; // The annual interest rate. double
interest; // Interest earned in one year. 28 CHAPTER 2. NAMES AND
THINGS /* Do the computations. */ principal = 17000; rate = 0.07;
interest = principal * rate; // Compute the interest. principal =
principal + interest; // Compute value of investment after one year,
with interest. // (Note: The new value replaces the old value of
principal.) /* Output the results. */ System.out.print("The interest
earned is $"); System.out.println(interest); System.out.print("The
value of the investment after one year is $");
System.out.println(principal); } // end of main() } // end of class
Interest This program uses several subroutine call statements to
display information to the user of the program. Two different
subroutines are used: System.out.print and System.out.println. The
difference between these is that System.out.println adds a linefeed
after the end of the information that it displays, while
System.out.print does not. Thus, the value of interest, which is
displayed by the subroutine call “System.out.println(interest);”,
follows on the same line after the string displayed by the previous
System.out.print statement. Note that the value to be displayed by
System.out.print or System.out.println is provided in parentheses
after the subroutine name. This value is called a parameter to the
subroutine. A parameter provides a subroutine with information it
needs to perform its task. In a subroutine call statement, any
parameters are listed in parentheses after the subroutine name. Not
all subroutines have parameters. If there are no parameters in a
subroutine call statement, the subroutine name must be followed by an
empty pair of parentheses. All the sample programs for this textbook
are available in separate source code files in the on-line version of
this text at http://math.hws.edu/javanotes/source. They are also
included in the downloadable archives of the web site. The source
code for the Interest program, for example, can be found in the file
Interest.java. 2.3 Strings, Objects, Enums, and Subroutines The
previous section introduced the eight primitive data types and the
type String. There is a fundamental difference between the primitive
types and the String type: Values of type String are objects. While
we will not study objects in detail until Chapter 5, it will be
useful for you to know a little about them and about a closely
related topic: classes. This is not just because strings are useful
but because objects and classes are essential to understanding
another important programming concept, subroutines. Another reason
for considering classes and objects at this point is so that we can
introduce enums. An enum is a data type that can be created by a Java
programmer to represent a small collection of possible values.
Technically, an enum is a class and its possible values are objects.
Enums will be our first example of adding a new type to the Java
language. We will look at them later in this section. 2.3. OBJECTS
AND SUBROUTINES 29 2.3.1 Built-in Subroutines and Functions Recall
that a subroutine is a set of program instructions that have been
chunked together and given a name. In Chapter 4, you’ll learn how to
write your own subroutines, but you can get a lot done in a program
just by calling subroutines that have already been written for you.
In Java, every subroutine is contained in a class or in an object.
Some classes that are standard parts of the Java language contain
predefined subroutines that you can use. A value of type String,
which is an object, contains subroutines that can be used to
manipulate that string. These subroutines are “built into” the Java
language. You can call all these subroutines without understanding
how they were written or how they work. Indeed, that’s the whole
point of subroutines: A subroutine is a “black box” which can be
used without knowing what goes on inside. Classes in Java have two
very different functions. First of all, a class can group together
variables and subroutines that are contained in that class. These
variables and subroutines are called static members of the class.
You’ve seen one example: In a class that defines a program, the
main() routine is a static member of the class. The parts of a class
definition that define static members are marked with the reserved
word “static”, just like the main() routine of a program. However,
classes have a second function. They are used to describe objects. In
this role, the class of an object specifies what subroutines and
variables are contained in that object. The class is a type—in the
technical sense of a specification of a certain type of data value—
and the object is a value of that type. For example, String is
actually the name of a class that is included as a standard part of
the Java language. String is also a type, and literal strings such as
"Hello World" represent values of type String. So, every subroutine
is contained either in a class or in an object. Classes contain
subroutines called static member subroutines. Classes also describe
objects and the subroutines that are contained in those objects. This
dual use can be confusing, and in practice most classes are designed
to perform primarily or exclusively in only one of the two possible
roles. For example, although the String class does contain a few
rarely-used static member subroutines, it exists mainly to specify a
large number of subroutines that are contained in objects of type
String. Another standard class, named Math, exists entirely to group
together a number of static member subroutines that compute various
common mathematical functions. ∗ ∗ ∗ To begin to get a handle on
all of this complexity, let’s look at the subroutine
System.out.print as an example. As you have seen earlier in this
chapter, this subroutine is used to display information to the user.
For example, System.out.print("Hello World") displays the message,
Hello World. System is one of Java’s standard classes. One of the
static member variables in this class is named out. Since this
variable is contained in the class System, its full name—which you
have to use to refer to it in your programs—is System.out. The
variable System.out refers to an object, and that object in turn
contains a subroutine named print. The compound identifier
System.out.print refers to the subroutine print in the object out in
the class System. (As an aside, I will note that the object referred
to by System.out is an object of the class PrintStream. PrintStream
is another class that is a standard part of Java. Any object of type
PrintStream is a destination to which information can be printed; any
object of type PrintStream has a print subroutine that can be used to
send information to that destination. The object System.out is just
one possible destination, and System.out.print is the subrou- 30
CHAPTER 2. NAMES AND THINGS tine that sends information to that
particular destination. Other objects of type PrintStream might send
information to other destinations such as files or across a network
to other computers. This is object-oriented programming: Many
different things which have something in common—they can all be used
as destinations for information—can all be used in the same way—
through a print subroutine. The PrintStream class expresses the
commonalities among all these objects.) Since class names and
variable names are used in similar ways, it might be hard to tell
which is which. Remember that all the built-in, predefined names in
Java follow the rule that class names begin with an upper case letter
while variable names begin with a lower case letter. While this is
not a formal syntax rule, I recommend that you follow it in your own
programming. Subroutine names should also begin with lower case
letters. There is no possibility of confusing a variable with a
subroutine, since a subroutine name in a program is always followed
by a left parenthesis. (As one final general note, you should be
aware that subroutines in Java are often referred to as methods.
Generally, the term “method” means a subroutine that is contained
in a class or in an object. Since this is true of every subroutine in
Java, every subroutine in Java is a method. The same is not true for
other programming languages. Nevertheless, the term “method” is
mostly used in the context of object-oriented programming, and until
we start doing real object-oriented programming in Chapter 5, I will
prefer to use the more general term, “subroutine.”) ∗ ∗ ∗
Classes can contain static member subroutines, as well as static
member variables. For example, the System class contains a subroutine
named exit. In a program, of course, this subroutine must be referred
to as System.exit. Calling this subroutine will terminate the program.
You could use it if you had some reason to terminate the program
before the end of the main routine. For historical reasons, this
subroutine takes an integer as a parameter, so the subroutine call
statement might look like “System.exit(0);” or “System.exit(1);”.
(The parameter tells the computer why the program was terminated. A
parameter value of 0 indicates that the program ended normally. Any
other value indicates that the program was terminated because an
error was detected. But in practice, the value of the parameter is
usually ignored.) Every subroutine performs some specific task. For
some subroutines, that task is to compute or retrieve some data value.
Subroutines of this type are called functions. We say that a function
returns a value. The returned value must then be used somehow in the
program. You are familiar with the mathematical function that
computes the square root of a number. Java has a corresponding
function called Math.sqrt. This function is a static member
subroutine of the class named Math. If x is any numerical value, then
Math.sqrt(x) computes and returns the square root of that value.
Since Math.sqrt(x) represents a value, it doesn’t make sense to put
it on a line by itself in a subroutine call statement such as
Math.sqrt(x); // This doesn’t make sense! What, after all, would the
computer do with the value computed by the function in this case? You
have to tell the computer to do something with the value. You might
tell the computer to display it: System.out.print( Math.sqrt(x) ); //
Display the square root of x. or you might use an assignment
statement to tell the computer to store that value in a variable: 2.3.
OBJECTS AND SUBROUTINES 31 lengthOfSide = Math.sqrt(x); The function
call Math.sqrt(x) represents a value of type double, and it can be
used anyplace where a numeric literal of type double could be used.
The Math class contains many static member functions. Here is a list
of some of the more important of them: • Math.abs(x), which computes
the absolute value of x. • The usual trigonometric functions,
Math.sin(x), Math.cos(x), and Math.tan(x). (For all the trigonometric
functions, angles are measured in radians, not degrees.) • The
inverse trigonometric functions arcsin, arccos, and arctan, which are
written as: Math.asin(x), Math.acos(x), and Math.atan(x). The return
value is expressed in radians, not degrees. • The exponential
function Math.exp(x) for computing the number e raised to the power x,
and the natural logarithm function Math.log(x) for computing the
logarithm of x in the base e. • Math.pow(x,y) for computing x raised
to the power y. • Math.floor(x), which rounds x down to the nearest
integer value that is less than or equal to x. Even though the return
value is mathematically an integer, it is returned as a value of type
double, rather than of type int as you might expect. For example,
Math.floor(3.76) is 3.0. The function Math.round(x) returns the
integer that is closest to x. • Math.random(), which returns a
randomly chosen double in the range 0.0 <= Math.random() < 1.0. (The
computer actually calculates so-called “pseudorandom” numbers,
which are not truly random but are random enough for most purposes.)
For these functions, the type of the parameter—the x or y inside the
parentheses—can be any value of any numeric type. For most of the
functions, the value returned by the function is of type double no
matter what the type of the parameter. However, for Math.abs(x), the
value returned will be the same type as x; if x is of type int, then
so is Math.abs(x). So, for example, while Math.sqrt(9) is the double
value 3.0, Math.abs(9) is the int value 9. Note that Math.random()
does not have any parameter. You still need the parentheses, even
though there’s nothing between them. The parentheses let the
computer know that this is a subroutine rather than a variable.
Another example of a subroutine that has no parameters is the
function System.currentTimeMillis(), from the System class. When this
function is executed, it retrieves the current time, expressed as the
number of milliseconds that have passed since a standardized base
time (the start of the year 1970 in Greenwich Mean Time, if you care).
One millisecond is one-thousandth of a second. The return value of
System.currentTimeMillis() is of type long. This function can be used
to measure the time that it takes the computer to perform a task.
Just record the time at which the task is begun and the time at which
it is finished and take the difference. Here is a sample program that
performs a few mathematical tasks and reports the time that it takes
for the program to run. On some computers, the time reported might be
zero, because it is too small to measure in milliseconds. Even if
it’s not zero, you can be sure that most of the time reported by the
computer was spent doing output or working on tasks other than the
program, since the calculations performed in this program occupy only
a tiny fraction of a second of a computer’s time. 32 CHAPTER 2.
NAMES AND THINGS /** * This program performs some mathematical
computations and displays * the results. It then reports the number
of seconds that the * computer spent on this task. */ public class
TimedComputation { public static void main(String[] args) { long
startTime; // Starting time of program, in milliseconds. long endTime;
// Time when computations are done, in milliseconds. double time; //
Time difference, in seconds. startTime = System.currentTimeMillis();
double width, height, hypotenuse; // sides of a triangle width = 42.0;
height = 17.0; hypotenuse = Math.sqrt( width*width + height*height );
System.out.print("A triangle with sides 42 and 17 has hypotenuse ");
System.out.println(hypotenuse); System.out.println("\nMathematically,
sin(x)*sin(x) + " + "cos(x)*cos(x) - 1 should be 0.");
System.out.println("Let’s check this for x = 1:");
System.out.print(" sin(1)*sin(1) + cos(1)*cos(1) - 1 is ");
System.out.println( Math.sin(1)*Math.sin(1) + Math.cos(1)*Math.cos(1)
- 1 ); System.out.println("(There can be round-off errors when" + "
computing with real numbers!)"); System.out.print("\nHere is a random
number: "); System.out.println( Math.random() ); endTime =
System.currentTimeMillis(); time = (endTime - startTime) / 1000.0;
System.out.print("\nRun time in seconds was: ");
System.out.println(time); } // end main() } // end class
TimedComputation 2.3.2 Operations on Strings A value of type String
is an object. That object contains data, namely the sequence of
characters that make up the string. It also contains subroutines. All
of these subroutines are in fact functions. For example, every string
object contains a function named length that computes the number of
characters in that string. Suppose that advice is a variable that
refers to a String. For example, advice might have been declared and
assigned a value as follows: String advice; advice = "Seize the day!";
2.3. OBJECTS AND SUBROUTINES 33 Then advice.length() is a function
call that returns the number of characters in the string “Seize the
day!”. In this case, the return value would be 14. In general, for
any string variable str, the value of str.length() is an int equal to
the number of characters in the string that is the value of str. Note
that this function has no parameter; the particular string whose
length is being computed is the value of str. The length subroutine
is defined by the class String, and it can be used with any value of
type String. It can even be used with String literals, which are,
after all, just constant values of type String. For example, you
could have a program count the characters in “Hello World” for you
by saying System.out.print("The number of characters in ");
System.out.println("the string \"Hello World\" is ");
System.out.println( "Hello World".length() ); The String class
defines a lot of functions. Here are some that you might find useful.
Assume that s1 and s2 refer to values of type String: • s1.equals(s2)
is a function that returns a boolean value. It returns true if s1
consists of exactly the same sequence of characters as s2, and
returns false otherwise. • s1.equalsIgnoreCase(s2) is another
boolean-valued function that checks whether s1 is the same string as
s2, but this function considers upper and lower case letters to be
equivalent. Thus, if s1 is “cat”, then s1.equals("Cat") is false,
while s1.equalsIgnoreCase("Cat") is true. • s1.length(), as mentioned
above, is an integer-valued function that gives the number of
characters in s1. • s1.charAt(N), where N is an integer, returns a
value of type char. It returns the Nth character in the string.
Positions are numbered starting with 0, so s1.charAt(0) is actually
the first character, s1.charAt(1) is the second, and so on. The final
position is s1.length() - 1. For example, the value of "cat".charAt(1)
is ’a’. An error occurs if the value of the parameter is less than
zero or greater than s1.length() - 1. • s1.substring(N,M), where N
and M are integers, returns a value of type String. The returned
value consists of the characters in s1 in positions N, N+1,. . . , M-
1. Note that the character in position M is not included. The
returned value is called a substring of s1. • s1.indexOf(s2) returns
an integer. If s2 occurs as a substring of s1, then the returned
value is the starting position of that substring. Otherwise, the
returned value is -1. You can also use s1.indexOf(ch) to search for a
particular character, ch, in s1. To find the first occurrence of x at
or after position N, you can use s1.indexOf(x,N). • s1.compareTo(s2)
is an integer-valued function that compares the two strings. If the
strings are equal, the value returned is zero. If s1 is less than s2,
the value returned is a number less than zero, and if s1 is greater
than s2, the value returned is some number greater than zero. (If
both of the strings consist entirely of lower case letters, then
“less than” and “greater than” refer to alphabetical order.
Otherwise, the ordering is more complicated.) • s1.toUpperCase() is a
String-valued function that returns a new string that is equal to s1,
except that any lower case letters in s1 have been converted to upper
case. For example, "Cat".toUpperCase() is the string "CAT". There is
also a function s1.toLowerCase(). • s1.trim() is a String-valued
function that returns a new string that is equal to s1 except that
any non-printing characters such as spaces and tabs have been trimmed
from the 34 CHAPTER 2. NAMES AND THINGS beginning and from the end of
the string. Thus, if s1 has the value "fred ", then s1.trim() is the
string "fred". For the functions s1.toUpperCase(), s1.toLowerCase(),
and s1.trim(), note that the value of s1 is not modified. Instead a
new string is created and returned as the value of the function. The
returned value could be used, for example, in an assignment statement
such as “smallLetters = s1.toLowerCase();”. To change the value of
s1, you could use an assignment “s1 = s1.toLowerCase();”. ∗ ∗ ∗
Here is another extremely useful fact about strings: You can use the
plus operator, +, to concatenate two strings. The concatenation of
two strings is a new string consisting of all the characters of the
first string followed by all the characters of the second string. For
example, "Hello" + "World" evaluates to "HelloWorld". (Gotta watch
those spaces, of course—if you want a space in the concatenated
string, it has to be somewhere in the input data, as in "Hello " +
"World".) Let’s suppose that name is a variable of type String and
that it already refers to the name of the person using the program.
Then, the program could greet the user by executing the statement:
System.out.println("Hello, " + name + ". Pleased to meet you!"); Even
more surprising is that you can actually concatenate values of any
type onto a String using the + operator. The value is converted to a
string, just as it would be if you printed it to the standard output,
and then it is concatenated onto the string. For example, the
expression "Number" + 42 evaluates to the string "Number42". And the
statements System.out.print("After "); System.out.print(years);
System.out.print(" years, the value is ");
System.out.print(principal); can be replaced by the single statement:
System.out.print("After " + years + " years, the value is " +
principal); Obviously, this is very convenient. It would have
shortened some of the examples presented earlier in this chapter.
2.3.3 Introduction to Enums Java comes with eight built-in primitive
types and a large set of types that are defined by classes, such as
String. But even this large collection of types is not sufficient to
cover all the possible situations that a programmer might have to
deal with. So, an essential part of Java, just like almost any other
programming language, is the ability to create new types. For the
most part, this is done by defining new classes; you will learn how
to do that in Chapter 5. But we will look here at one particular case:
the ability to define enums (short for enumerated types). Enums are a
recent addition to Java. They were only added in Version 5.0. Many
programming languages have something similar, and many people believe
that enums should have been part of Java from the beginning.
Technically, an enum is considered to be a special kind of class, but
that is not important for now. In this section, we will look at enums
in a simplified form. In practice, most uses of enums will only need
the simplified form that is presented here. 2.3. OBJECTS AND
SUBROUTINES 35 An enum is a type that has a fixed list of possible
values, which is specified when the enum is created. In some ways, an
enum is similar to the boolean data type, which has true and false as
its only possible values. However, boolean is a primitive type, while
an enum is not. The definition of an enum types has the (simplified)
form: enum henum-type-namei { hlist-of-enum-valuesi } This definition
cannot be inside a subroutine. You can place it outside the main()
routine of the program. The henum-type-namei can be any simple
identifier. This identifier becomes the name of the enum type, in the
same way that “boolean” is the name of the boolean type and
“String” is the name of the String type. Each value in the hlist-
of-enum-valuesi must be a simple identifier, and the identifiers in
the list are separated by commas. For example, here is the definition
of an enum type named Season whose values are the names of the four
seasons of the year: enum Season { SPRING, SUMMER, FALL, WINTER } By
convention, enum values are given names that are made up of upper
case letters, but that is a style guideline and not a syntax rule.
Enum values are not variables. Each value is a constant that always
has the same value. In fact, the possible values of an enum type are
usually referred to as enum constants. Note that the enum constants
of type Season are considered to be “contained in” Season, which
means—following the convention that compound identifiers are used
for things that are contained in other things—the names that you
actually use in your program to refer to them are Season.SPRING,
Season.SUMMER, Season.FALL, and Season.WINTER. Once an enum type has
been created, it can be used to declare variables in exactly the same
ways that other types are used. For example, you can declare a
variable named vacation of type Season with the statement: Season
vacation; After declaring the variable, you can assign a value to it
using an assignment statement. The value on the right-hand side of
the assignment can be one of the enum constants of type Season.
Remember to use the full name of the constant, including “Season”!
For example: vacation = Season.SUMMER; You can print out an enum
value with an output statement such as System.out.print(vacation).
The output value will be the name of the enum constant (without the
“Season.”). In this case, the output would be “SUMMER”. Because
an enum is technically a class, the enum values are technically
objects. As objects, they can contain subroutines. One of the
subroutines in every enum value is named ordinal(). When used with an
enum value, it returns the ordinal number of the value in the list of
values of the enum. The ordinal number simply tells the position of
the value in the list. That is, Season.SPRING.ordinal() is the int
value 0, Season.SUMMER.ordinal() is 1, Season.FALL.ordinal() is 2,
and Season.WINTER.ordinal() is 3. (You will see over and over again
that computer scientists like to start counting at zero!) You can, of
course, use the ordinal() method with a variable of type Season, such
as vacation.ordinal() in our example. Right now, it might not seem to
you that enums are all that useful. As you work though the rest of
the book, you should be convinced that they are. For now, you should
at least appreciate them as the first example of an important concept:
creating new types. Here is a little example that shows enums being
used in a complete program: 36 CHAPTER 2. NAMES AND THINGS public
class EnumDemo { // Define two enum types -- remember that the
definitions // go OUTSIDE The main() routine! enum Day { SUNDAY,
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY } enum Month
{ JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC } public
static void main(String[] args) { Day tgif; // Declare a variable of
type Day. Month libra; // Declare a variable of type Month. tgif =
Day.FRIDAY; // Assign a value of type Day to tgif. libra = Month.OCT;
// Assign a value of type Month to libra. System.out.print("My sign
is libra, since I was born in "); System.out.println(libra); //
Output value will be: OCT System.out.print("That’s the ");
System.out.print( libra.ordinal() ); System.out.println("-th month of
the year."); System.out.println(" (Counting from 0, of course!)");
System.out.print("Isn’t it nice to get to ");
System.out.println(tgif); // Output value will be: FRIDAY
System.out.println( tgif + " is the " + tgif.ordinal() + "-th day of
the week."); // You can concatenate enum values onto Strings! } } 2.4
Text Input and Output For some unfathomable reason, Java has never
made it easy to read data typed in by the user of a program. You’ve
already seen that output can be displayed to the user using the
subroutine System.out.print. This subroutine is part of a pre-defined
object called System.out. The purpose of this object is precisely to
display output to the user. There is a corresponding object called
System.in that exists to read data input by the user, but it provides
only very primitive input facilities, and it requires some advanced
Java programming skills to use it effectively. Java 5.0 finally makes
input a little easier with a new Scanner class. However, it requires
some knowledge of object-oriented programming to use this class, so
it’s not appropriate for use here at the beginning of this course.
(Furthermore, in my opinion, Scanner still does not get things quite
right.) There is some excuse for this lack of concern with input,
since Java is meant mainly to write programs for Graphical User
Interfaces, and those programs have their own style of input/output,
which is implemented in Java. However, basic support is needed for
input/output in old-fashioned non-GUI programs. Fortunately, it is
possible to extend Java by creating new classes that provide
subroutines that are not available in the standard part of the
language. As soon as a new class is available, the subroutines that
it contains can be used in exactly the same way as built-in routines.
2.4. TEXT INPUT AND OUTPUT 37 Along these lines, I’ve written a
class called TextIO that defines subroutines for reading values typed
by the user of a non-GUI program. The subroutines in this class make
it possible to get input from the standard input object, System.in,
without knowing about the advanced aspects of Java that are needed to
use Scanner or to use System.in directly. TextIO also contains a set
of output subroutines. The output subroutines are similar to those
provided in System.out, but they provide a few additional features.
You can use whichever set of output subroutines you prefer, and you
can even mix them in the same program. To use the TextIO class, you
must make sure that the class is available to your program. What this
means depends on the Java programming environment that you are using.
In general, you just have to add the source code file, TextIO.java,
to the same directory that contains your main program. See Section
2.6 for more information about how to use TextIO. 2.4.1 A First Text
Input Example The input routines in the TextIO class are static
member functions. (Static member functions were introduced in the
previous section.) Let’s suppose that you want your program to read
an integer typed in by the user. The TextIO class contains a static
member function named getlnInt that you can use for this purpose.
Since this function is contained in the TextIO class, you have to
refer to it in your program as TextIO.getlnInt. The function has no
parameters, so a complete call to the function takes the form
“TextIO.getlnInt()”. This function call represents the int value
typed by the user, and you have to do something with the returned
value, such as assign it to a variable. For example, if userInput is
a variable of type int (created with a declaration statement “int
userInput;”), then you could use the assignment statement userInput
= TextIO.getlnInt(); When the computer executes this statement, it
will wait for the user to type in an integer value. The value typed
will be returned by the function, and it will be stored in the
variable, userInput. Here is a complete program that uses
TextIO.getlnInt to read a number typed by the user and then prints
out the square of the number that the user types: /** * A program
that reads an integer that is typed in by the * user and computes and
prints the square of that integer. */ public class PrintSquare
{ public static void main(String[] args) { int userInput; // The
number input by the user. int square; // The userInput, multiplied by
itself. System.out.print("Please type a number: "); userInput =
TextIO.getlnInt(); square = userInput * userInput;
System.out.print("The square of that number is ");
System.out.println(square); } // end of main() } //end of class
PrintSquare 38 CHAPTER 2. NAMES AND THINGS When you run this program,
it will display the message “Please type a number:” and will pause
until you type a response, including a carriage return after the
number. 2.4.2 Text Output The TextIO class contains static member
subroutines TextIO.put and TextIO.putln that can be used in the same
way as System.out.print and System.out.println. For example, although
there is no particular advantage in doing so in this case, you could
replace the two lines System.out.print("The square of that number is
"); System.out.println(square); with TextIO.put("The square of that
number is "); TextIO.putln(square); For the next few chapters, I will
use TextIO for input in all my examples, and I will often use it for
output. Keep in mind that TextIO can only be used in a program if it
is available to that program. It is not built into Java in the way
that the System class is. Let’s look a little more closely at the
built-in output subroutines System.out.print and System.out.println.
Each of these subroutines can be used with one parameter, where the
parameter can be a value of any of the primitive types byte, short,
int, long, float, double, char, or boolean. The parameter can also be
a String, a value belonging to an enum type, or indeed any object.
That is, you can say “System.out.print(x);” or
“System.out.println(x);”, where x is any expression whose value is
of any type whatsoever. The expression can be a constant, a variable,
or even something more complicated such as 2*distance*time. Now, in
fact, the System class actually includes several different
subroutines to handle different parameter types. There is one
System.out.print for printing values of type double, one for values
of type int, another for values that are objects, and so on. These
subroutines can have the same name since the computer can tell which
one you mean in a given subroutine call statement, depending on the
type of parameter that you supply. Having several subroutines of the
same name that differ in the types of their parameters is called
overloading. Many programming languages do not permit overloading,
but it is common in Java programs. The difference between
System.out.print and System.out.println is that the println version
outputs a carriage return after it outputs the specified parameter
value. There is a version of System.out.println that has no
parameters. This version simply outputs a carriage return, and
nothing else. A subroutine call statement for this version of the
program looks like “System.out.println();”, with empty parentheses.
Note that “System.out.println(x);” is exactly equivalent to
“System.out.print(x); System.out.println();”; the carriage return
comes after the value of x. (There is no version of System.out.print
without parameters. Do you see why?) As mentioned above, the TextIO
subroutines TextIO.put and TextIO.putln can be used as replacements
for System.out.print and System.out.println. The TextIO functions
work in exactly the same way as the System functions, except that, as
we will see below, TextIO can also be used to write to other
destinations. 2.4. TEXT INPUT AND OUTPUT 39 2.4.3 TextIO Input
Functions The TextIO class is a little more versatile at doing output
than is System.out. However, it’s input for which we really need it.
With TextIO, input is done using functions. For example,
TextIO.getlnInt(), which was discussed above, makes the user type in
a value of type int and returns that input value so that you can use
it in your program. TextIO includes several functions for reading
different types of input values. Here are examples of the ones that
you are most likely to use: j = TextIO.getlnInt(); // Reads a value
of type int. y = TextIO.getlnDouble(); // Reads a value of type
double. a = TextIO.getlnBoolean(); // Reads a value of type boolean.
c = TextIO.getlnChar(); // Reads a value of type char. w =
TextIO.getlnWord(); // Reads one "word" as a value of type String. s
= TextIO.getln(); // Reads an entire input line as a String. For
these statements to be legal, the variables on the left side of each
assignment statement must already be declared and must be of the same
type as that returned by the function on the right side. Note
carefully that these functions do not have parameters. The values
that they return come from outside the program, typed in by the user
as the program is running. To “capture” that data so that you can
use it in your program, you have to assign the return value of the
function to a variable. You will then be able to refer to the user’s
input value by using the name of the variable. When you call one of
these functions, you are guaranteed that it will return a legal value
of the correct type. If the user types in an illegal value as input—
for example, if you ask for an int and the user types in a non-
numeric character or a number that is outside the legal range of
values that can be stored in in a variable of type int—then the
computer will ask the user to re-enter the value, and your program
never sees the first, illegal value that the user entered. For
TextIO.getlnBoolean(), the user is allowed to type in any of the
following: true, false, t, f, yes, no, y, n, 1, or 0. Furthermore,
they can use either upper or lower case letters. In any case, the
user’s input is interpreted as a true/false value. It’s convenient
to use TextIO.getlnBoolean() to read the user’s response to a Yes/No
question. You’ll notice that there are two input functions that
return Strings. The first, getlnWord(), returns a string consisting
of non-blank characters only. When it is called, it skips over any
spaces and carriage returns typed in by the user. Then it reads non-
blank characters until it gets to the next space or carriage return.
It returns a String consisting of all the non-blank characters that
it has read. The second input function, getln(), simply returns a
string consisting of all the characters typed in by the user,
including spaces, up to the next carriage return. It gets an entire
line of input text. The carriage return itself is not returned as
part of the input string, but it is read and discarded by the
computer. Note that the String returned by this function might be the
empty string, "", which contains no characters at all. You will get
this return value if the user simply presses return, without typing
anything else first. All the other input functions listed—getlnInt(),
getlnDouble(), getlnBoolean(), and getlnChar()—behave like getWord()
in that they will skip past any blanks and carriage returns in the
input before reading a value. Furthermore, if the user types extra
characters on the line after the input value, all the extra
characters will be discarded, along with the carriage return at the
end of the line. If the program executes another input function, the
user will have to type in another line of input. It might not sound
like a good idea to discard any of the user’s input, but it turns
out to be the safest thing to do in most programs. Sometimes, however,
you do want to read more 40 CHAPTER 2. NAMES AND THINGS than one
value from the same line of input. TextIO provides the following
alternative input functions to allow you to do this: j =
TextIO.getInt(); // Reads a value of type int. y = TextIO.getDouble();
// Reads a value of type double. a = TextIO.getBoolean(); // Reads a
value of type boolean. c = TextIO.getChar(); // Reads a value of type
char. w = TextIO.getWord(); // Reads one "word" as a value of type
String. The names of these functions start with “get” instead of
“getln”. “Getln” is short for “get line” and should remind you
that the functions whose names begin with “getln” will get an
entire line of data. A function without the “ln” will read an input
value in the same way, but will then save the rest of the input line
in a chunk of internal memory called the input buffer. The next time
the computer wants to read an input value, it will look in the input
buffer before prompting the user for input. This allows the computer
to read several values from one line of the user’s input. Strictly
speaking, the computer actually reads only from the input buffer. The
first time the program tries to read input from the user, the
computer will wait while the user types in an entire line of input.
TextIO stores that line in the input buffer until the data on the
line has been read or discarded (by one of the “getln” functions).
The user only gets to type when the buffer is empty. Clearly, the
semantics of input is much more complicated than the semantics of
output! Fortunately, for the majority of applications, it’s pretty
straightforward in practice. You only need to follow the details if
you want to do something fancy. In particular, I strongly advise you
to use the “getln” versions of the input routines, rather than the
“get” versions, unless you really want to read several items from
the same line of input, precisely because the semantics of the
“getln” versions is much simpler. Note, by the way, that although
the TextIO input functions will skip past blank spaces and carriage
returns while looking for input, they will not skip past other
characters. For example, if you try to read two ints and the user
types “2,3”, the computer will read the first number correctly, but
when it tries to read the second number, it will see the comma. It
will regard this as an error and will force the user to retype the
number. If you want to input several numbers from one line, you
should make sure that the user knows to separate them with spaces,
not commas. Alternatively, if you want to require a comma between the
numbers, use getChar() to read the comma before reading the second
number. There is another character input function,
TextIO.getAnyChar(), which does not skip past blanks or carriage
returns. It simply reads and returns the next character typed by the
user, even if it’s a blank or carriage return. If the user typed a
carriage return, then the char returned by getAnyChar() is the
special linefeed character ’\n’. There is also a function,
TextIO.peek(), that lets you look ahead at the next character in the
input without actually reading it. After you “peek” at the next
character, it will still be there when you read the next item from
input. This allows you to look ahead and see what’s coming up in the
input, so that you can take different actions depending on what’s
there. The TextIO class provides a number of other functions. To
learn more about them, you can look at the comments in the source
code file, TextIO.java. (You might be wondering why there are only
two output routines, print and println, which can output data values
of any type, while there is a separate input routine for each data
type. As noted above, in reality there are many print and println
routines, one for each data type. The computer can tell them apart
based on the type of the parameter that you provide. However, the
input routines don’t have parameters, so the different input
routines can only be 2.4. TEXT INPUT AND OUTPUT 41 distinguished by
having different names.) ∗ ∗ ∗ Using TextIO for input and output,
we can now improve the program from Section 2.2 for computing the
value of an investment. We can have the user type in the initial
value of the investment and the interest rate. The result is a much
more useful program—for one thing, it makes sense to run it more
than once! /** * This class implements a simple program that will
compute * the amount of interest that is earned on an investment over
* a period of one year. The initial amount of the investment * and
the interest rate are input by the user. The value of * the
investment at the end of the year is output. The * rate must be input
as a decimal, not a percentage (for * example, 0.05 rather than 5).
*/ public class Interest2 { public static void main(String[] args)
{ double principal; // The value of the investment. double rate; //
The annual interest rate. double interest; // The interest earned
during the year. TextIO.put("Enter the initial investment: ");
principal = TextIO.getlnDouble(); TextIO.put("Enter the annual
interest rate (decimal, not percentage!): "); rate =
TextIO.getlnDouble(); interest = principal * rate; // Compute this
year’s interest. principal = principal + interest; // Add it to
principal. TextIO.put("The value of the investment after one year is
$"); TextIO.putln(principal); } // end of main() } // end of class
Interest2 2.4.4 Formatted Output If you ran the preceding Interest2
example, you might have noticed that the answer is not always written
in the format that is usually used for dollar amounts. In general,
dollar amounts are written with two digits after the decimal point.
But the program’s output can be a number like 1050.0 or 43.575. It
would be better if these numbers were printed as 1050.00 and 43.58.
Java 5.0 introduced a formatted output capability that makes it much
easier than it used to be to control the format of output numbers. A
lot of formatting options are available. I will cover just a few of
the simplest and most commonly used possibilities here. You can use
the function System.out.printf to produce formatted output. (The name
“