Introduction To Programming Using Java David J Eck instant download
Introduction To Programming Using Java David J Eck instant download
Eck download
https://ebookbell.com/product/introduction-to-programming-using-
java-david-j-eck-2375550
https://ebookbell.com/product/introduction-to-programming-using-java-
version-9-swing-edition-david-j-eck-50625664
https://ebookbell.com/product/introduction-to-programming-using-
java-7e-itebooks-23836692
https://ebookbell.com/product/multimedia-introduction-to-programming-
using-java-1st-edition-david-gries-2100192
https://ebookbell.com/product/new-programmers-start-here-an-
introduction-to-computer-programming-using-javascript-
bartlett-55919162
Introduction To Programming Using Python Daniel Y Liang
https://ebookbell.com/product/introduction-to-programming-using-
python-daniel-y-liang-22039592
https://ebookbell.com/product/introduction-to-programming-using-
visual-basics-10th-edition-david-i-schneider-11768686
https://ebookbell.com/product/introduction-to-programming-using-
visual-basic-11e-11th-edition-david-i-schneider-11732072
https://ebookbell.com/product/introduction-to-programming-using-
fortran-9520032008-version-3051-ed-jorgensen-10466018
https://ebookbell.com/product/an-introduction-to-programming-using-
python-schneider-david-i-21354512
Introduction to Programming Using Java
Version 6.0, June 2011
David J. Eck
Hobart and William Smith Colleges
ii
Preface xiii
iii
iv CONTENTS
3 Control 63
3.1 Blocks, Loops, and Branches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.1.1 Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.1.2 The Basic While Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.1.3 The Basic If Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
3.2 Algorithm Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
3.2.1 Pseudocode and Stepwise Refinement . . . . . . . . . . . . . . . . . . . . 68
3.2.2 The 3N+1 Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
3.2.3 Coding, Testing, Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . 74
3.3 while and do..while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
3.3.1 The while Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
3.3.2 The do..while Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
3.3.3 break and continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
3.4 The for Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
3.4.1 For Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
3.4.2 Example: Counting Divisors . . . . . . . . . . . . . . . . . . . . . . . . . . 85
3.4.3 Nested for Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
3.4.4 Enums and for-each Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
3.5 The if Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
3.5.1 The Dangling else Problem . . . . . . . . . . . . . . . . . . . . . . . . . . 91
3.5.2 The if...else if Construction . . . . . . . . . . . . . . . . . . . . . . . . . . 92
3.5.3 If Statement Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
3.5.4 The Empty Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
3.6 The switch Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
3.6.1 The Basic switch Statement . . . . . . . . . . . . . . . . . . . . . . . . . . 98
3.6.2 Menus and switch Statements . . . . . . . . . . . . . . . . . . . . . . . . . 100
3.6.3 Enums in switch Statements . . . . . . . . . . . . . . . . . . . . . . . . . 101
3.6.4 Definite Assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
3.7 Exceptions and try..catch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
3.7.1 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
3.7.2 try..catch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
3.7.3 Exceptions in TextIO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
3.8 GUI Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Exercises for Chapter 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Quiz on Chapter 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
CONTENTS v
4 Subroutines 119
4.1 Black Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
4.2 Static Subroutines and Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
4.2.1 Subroutine Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
4.2.2 Calling Subroutines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
4.2.3 Subroutines in Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
4.2.4 Member Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
4.3 Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
4.3.1 Using Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
4.3.2 Formal and Actual Parameters . . . . . . . . . . . . . . . . . . . . . . . . 130
4.3.3 Overloading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
4.3.4 Subroutine Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
4.3.5 Throwing Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
4.3.6 Global and Local Variables . . . . . . . . . . . . . . . . . . . . . . . . . . 135
4.4 Return Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
4.4.1 The return statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
4.4.2 Function Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
4.4.3 3N+1 Revisited . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
4.5 APIs, Packages, and Javadoc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
4.5.1 Toolboxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
4.5.2 Java’s Standard Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
4.5.3 Using Classes from Packages . . . . . . . . . . . . . . . . . . . . . . . . . 144
4.5.4 Javadoc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
4.6 More on Program Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
4.6.1 Preconditions and Postconditions . . . . . . . . . . . . . . . . . . . . . . . 149
4.6.2 A Design Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
4.6.3 The Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
4.7 The Truth About Declarations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
4.7.1 Initialization in Declarations . . . . . . . . . . . . . . . . . . . . . . . . . 156
4.7.2 Named Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
4.7.3 Naming and Scope Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
Exercises for Chapter 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
Quiz on Chapter 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
7 Arrays 319
7.1 Creating and Using Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
7.1.1 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
7.1.2 Using Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
7.1.3 Array Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
7.2 Programming With Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
7.2.1 Arrays and for Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
7.2.2 Arrays and for-each Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
7.2.3 Array Types in Subroutines . . . . . . . . . . . . . . . . . . . . . . . . . . 327
7.2.4 Random Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
7.2.5 Arrays of Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330
7.2.6 Variable Arity Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
7.3 Dynamic Arrays and ArrayLists . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
7.3.1 Partially Full Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
7.3.2 Dynamic Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
7.3.3 ArrrayLists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
7.3.4 Parameterized Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
7.3.5 Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
7.4 Searching and Sorting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
viii CONTENTS
Glossary 731
xii CONTENTS
Preface
xiii
xiv Preface
related topic of event-oriented programming and graphical user interfaces. Arrays are covered
in Chapter 7. Chapter 8 is a short chapter that marks a turning point in the book, moving
beyond the fundamental ideas of programming to cover more advanced topics. Chapter 8
is about writing robust, correct, and efficient programs. Chapters 9 and 10 cover recursion
and data structures, including the Java Collection Framework. Chapter 11 is about files and
networking. Chapter 12 covers threads and parallel processing. Finally, Chapter 13 returns
to the topic of graphical user interface programming to cover some of Java’s more advanced
capabilities.
∗ ∗ ∗
Major changes were made for the previous (fifth) edition of this book. Perhaps the most
significant change was the use of parameterized types in the chapter on generic programming.
Parameterized types—Java’s version of templates—were the most eagerly anticipated new fea-
ture in Java 5.0. Other new features in Java 5.0 were also introduced in the fifth edition,
including enumerated types, formatted output, the Scanner class, and variable arity methods.
In addition, Javadoc comments were covered for the first time.
The changes in this sixth edition are much smaller. The major change is a new chapter
on threads (Chapter 12). Material about threads from the previous edition has been moved
to this chapter, and a good deal of new material has been added. Other changes include some
coverage of features added to Java in versions 6 and 7 and the inclusion of a glossary. There
are also smaller changes throughout the book.
∗ ∗ ∗
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.)
• Sixth edition: http://math.hws.edu/eck/cs124/javanotes6/ (Covers Java 5.0 and later.)
Introduction to Programming using Java is free, but it is not in the public do-
main. As of Version 6.0, it is published under the terms of the Creative Commons
Attribution-NonCommercial-ShareAlike 3.0 License. To view a copy of this license, visit
http://creativecommons.org/licenses/by-nc-sa/3.0/. For example, you can:
• 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 unmodified copies of this book or sell them at cost of production, 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 non-commercially, 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.
For uses of the book in ways not covered by the license, permission of the author is required.
Preface xv
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 made the complete source files available for download at the following
address:
http://math.hws.edu/eck/cs124/downloads/javanotes6-full-source.zip
These files were not originally meant for publication, and therefore are not very cleanly
written. Furthermore, it requires a fair amount of expertise to use them effectively. However,
I have had several requests for the sources and have made them available on an “as-is” basis.
For more information about the source and how they are used see the README file from the
source download.
∗ ∗ ∗
Professor David J. Eck
Department of Mathematics and Computer Science
Hobart and William Smith Colleges
300 Pulteney Street
Geneva, New York 14456, USA
Email: [email protected]
WWW: http://math.hws.edu/eck/
xvi Preface
Chapter 1
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
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 (al-
though 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 instruc-
tion. 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.)
∗ ∗ ∗
Memory
00101110 (Location 0)
11010011 (Location 1)
Data to memory 01010011 (Location 2)
00010000 (Location 3)
CPU 10111111
Data from memory 10100110
11101001
Program 00000111
counter: 10100110
Address for
1011100001 reading/writing 00010001
data 00111110 (Location 10)
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-and-
execute cycle, things happen in a predetermined order; everything that happens is “synchro-
nized” 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 unpredictable 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,
since it is threads that are used in Java.) Many CPUs can literally execute more than one
thread simultaneously—such CPUs contain multiple “cores,” each of which can run a thread—
but there is always a limit on the number of threads that can be executed at the same time.
Since there are often more threads than can be executed simultaneously, the computer has to be
able switch its attention from one thread to another, just as a timesharing computer switches
its attention from one user to another. In general, a thread that is being executed will continue
to run until 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, if any, 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
6 CHAPTER 1. THE MENTAL LANDSCAPE
one thread to another, whether the thread that is currently running likes it or not. All
modern desktop and laptop computers use preemptive multitasking.
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
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 and
multiprocessing. In fact, the ability to work with threads is fast becoming an essential job skill
for programmers. Fortunately, Java has good support for threads, which are built into the Java
programming language as a fundamental programming concept. Programming with threads
will be covered in Chapter 12.
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 asyn-
chronously when specific 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, starting in Chapter 6
∗ ∗ ∗
By the way, the software that does all the interrupt handling, handles communication with
the user and with hardware devices, and controls which thread is allowed to run 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, Windows XP, Windows Vista, and Mac OS.
One use of interpreters is to execute high-level language programs. For example, the pro-
gramming 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 Mac OS computers. Virtual PC is an interpreter that
executes machine-language programs written for IBM-PC-clone computers. If you run Virtual
PC on your Mac OS, 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 Mac OS machine-language instructions
for 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. Pro-
grams 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, or JVM. The machine language for the Java Virtual Machine is called Java
bytecode. There is no reason why Java bytecode couldn’t be used as the machine language of a
real computer, rather than a virtual computer. But in fact the use of a virtual machine makes
possible one of the main selling points of Java: the fact 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 JVM in the same way that Virtual PC simulates a PC computer. (The term JVM
is also used for the Java bytecode interpreter program that does the simulation, so we say that
a computer needs a JVM in order to run Java programs. Technically, it would be more correct
to say that the interpreter implements the JVM than to say that it is a JVM.)
Of course, a different Java 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 I n t e r p r e t e r
f
o r M a c O S
J a v a
J a v a J a v a I n t e r p r e t e r
o m p i l e r B y t e c o d e
f
P r o g r a m C o r W i n d o w s
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 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
8 CHAPTER 1. THE MENTAL LANDSCAPE
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.
When Java was still a new language, it was criticized for being slow: Since Java bytecode was
executed by an interpreter, it seemed that Java bytecode programs could never run as quickly
as programs compiled into native machine language (that is, the actual machine language of the
computer on which the program is running). However, this problem has been largely overcome
by the use of just-in-time compilers for executing Java bytecode. A just-in-time compiler
translates Java bytecode into native machine language. It does this while it is executing the
program. Just as for a normal interpreter, the input to a just-in-time compiler is a Java bytecode
program, and its task is to execute that program. But as it is executing the program, it also
translates parts of it into machine language. The translated parts of the program can then be
executed much more quickly than they could be interpreted. Since a given part of a program is
often executed many times as the program runs, a just-in-time compiler can significantly speed
up the overall execution time.
I should note that there is no necessary connection between Java and Java bytecode. A pro-
gram 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 network-
compatible while allowing you to program in a modern high-level object-oriented language.
(In the past few years, it has become fairly common to create new programming languages,
or versions of old languages, that compile into Java bytecode. The compiled bytecode programs
can then be executed by a standard JVM. New languages that have been developed specifically
for programming the JVM include Groovy, Clojure, and Processing. Jython and JRuby are
versions of older languages, Python and Ruby, that target the JVM. These languages make it
possible to enjoy many of the advantages of the JVM while avoiding some of the technicalities
of the Java language. In fact, the use of other languages with the JVM has become important
enough that several new features have been added to the JVM in Java Version 7 specifically to
add better support for some of those languages.)
∗ ∗ ∗
I should also note that the really hard part of platform-independence is providing a “Graph-
ical 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.
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 in many other programming 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
floating-point 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 kind
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
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
10 CHAPTER 1. THE MENTAL LANDSCAPE
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 sub-
routines 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 object-
oriented programming, which is discussed in the next section.
realized that the design of the data structures for a program was at 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 that a module can be “plugged into” a system. The details of what goes on
inside the module are not important to the system as a whole, as long as the module fulfills its
assigned role correctly. This is called information hiding , and it is one of the most important
principles of software engineering.
One common format for software modules is to contain some data, along with some sub-
routines for manipulating that data. For example, a mailing-list module might contain a list of
names and addresses along with a subroutine for adding a new name, a subroutine for printing
mailing labels, and so forth. In such modules, the data itself is often hidden inside the module;
a program that uses the module can then manipulate the data only indirectly, by calling the
subroutines provided by the module. This protects the data, since it can only be manipulated
in known, well-defined ways. And it makes it easier for programs to use the module, since they
don’t have to worry about the details of how the data is represented. Information about the
representation of the data is hidden.
Modules that could support this kind of information-hiding became common in program-
ming languages in the early 1980s. Since then, a more advanced form of the same idea has
more or less taken over software engineering. This latest approach is called object-oriented
programming , often abbreviated as OOP.
The central concept of object-oriented programming is the object, which is a kind of module
containing data and subroutines. The point-of-view in OOP is that an object is a kind of self-
sufficient entity that has an internal state (the data it contains) and that can respond to
messages (calls to its subroutines). A mailing list object, for example, has a state consisting
of a list of names and addresses. If you send it a message telling it to add a name, it will
respond by modifying its state to reflect the change. If you send it a message telling it to print
itself, it will respond by printing out its list of names and addresses.
The OOP approach to software engineering is to start by identifying the objects involved in
a problem and the messages that those objects should respond to. The program that results is
a collection of objects, each with its own data and its own set of responsibilities. The objects
interact by sending messages to each other. There is not much “top-down” in the large-scale
design of such a program, and people used to more traditional programs can have a hard time
getting used to OOP. However, people who use OOP would claim that object-oriented programs
12 CHAPTER 1. THE MENTAL LANDSCAPE
tend to be better models of the way the world itself works, and that they are therefore easier
to write, easier to understand, and more likely to be correct.
∗ ∗ ∗
You should think of objects as “knowing” how to respond to certain messages. Different
objects might respond to the same message in different ways. For example, a “print” message
would produce very different results, depending on the object it is sent to. This property of
objects—that different objects can respond to the same message in different ways—is called
polymorphism .
It is common for objects to bear a kind of “family resemblance” to one another. Objects
that contain the same type of data and that respond to the same messages in the same way
belong to the same class. (In actual programming, the class is primary; that is, a class is
created and then one or more objects are created using that class as a template.) But objects
can be similar without being in exactly the same class.
For example, consider a drawing program that lets the user draw lines, rectangles, ovals,
polygons, and curves on the screen. In the program, each visible object on the screen could be
represented by a software object in the program. There would be five classes of objects in the
program, one for each type of visible object that can be drawn. All the lines would belong to
one class, all the rectangles to another class, and so on. These classes are obviously related;
all of them represent “drawable objects.” They would, for example, all presumably be able to
respond to a “draw yourself” message. Another level of grouping, based on the data needed
to represent each type of object, is less obvious, but would be very useful in a program: We
can group polygons and curves together as “multipoint objects,” while lines, rectangles, and
ovals are “two-point objects.” (A line is determined by its endpoints, a rectangle by two of its
corners, and an oval by two corners of the rectangle that contains it.) We could diagram these
relationships as follows:
D r a w a b l e O b j e c t
M u l t i p o i n t O b j e c t T w o P o i n t O b j e c t
P o l y g o n C u r v e L e c t a n g l e O v a l
i n e R
fits, you can still reuse it by defining a subclass and making only the small changes necessary
to adapt it exactly to your needs.
So, OOP is meant to be both a superior program-development tool and a partial solution
to the software reuse problem. Objects, classes, and object-oriented programming will be
important themes throughout the rest of this text. You will start using objects that are built
into the Java language in the next chapter, and in Chapter 5 you will being creating your own
classes and objects.
Now, Java actually has two complete sets of GUI components. One of these, the AWT or
Abstract Windowing Toolkit, was available in the original version of Java. The other, which
is known as Swing , is included in Java version 1.2 or later, and is used in preference to the
AWT in most modern Java programs. The applet that is shown above uses components that
are part of Swing. If Java is not installed in your Web browser or if your browser uses a very old
version of Java, you might get an error when the browser tries to load the applet. Remember
that most of the applets in this textbook require Java 5.0 (or higher).
When a user interacts with the GUI components in this applet, an “event” is generated.
For example, clicking a push button generates an event, and pressing return while typing in a
text field generates an event. Each time an event is generated, a message is sent to the applet
telling it that the event has occurred, and the applet responds according to its program. In
fact, the program consists mainly of “event handlers” that tell the applet how to respond to
various types of events. In this example, the applet has been programmed to respond to each
event by displaying a message in the text area. In a more realistic example, the event handlers
would have more to do.
The use of the term “message” here is deliberate. Messages, as you saw in the previous sec-
tion, are sent to objects. In fact, Java GUI components are implemented as objects. Java
includes many predefined classes that represent various types of GUI components. Some of
these classes are subclasses of others. Here is a diagram showing some of Swing’s GUI classes
and their relationships:
J C o m p o n e n t
J L a b e l J A b s t r a c t B u t t o n J C o m b o B o x J S c r o l l b a r J T e x t C o m p o n e n t
J B u t t o n J T o g g l e B u t t o n J T e x t F i e l d J T e x t A r e a
J C h e c k B o x J R a d i o B u t t o n
Don’t worry about the details for now, but try to get some feel about how object-oriented
programming and inheritance are used here. Note that all the GUI classes are subclasses,
directly or indirectly, of a class called JComponent, which represents general properties that are
shared by all Swing components. Two of the direct subclasses of JComponent themselves have
subclasses. The classes JTextArea and JTextField, which have certain behaviors in common,
are grouped together as subclasses of JTextComponent. Similarly JButton and JToggleButton
1.7. THE INTERNET AND BEYOND 15
are subclasses of JAbstractButton, which represents properties common to both buttons and
checkboxes. (JComboBox, by the way, is the Swing class that represents pop-up menus.)
Just from this brief discussion, perhaps you can see how GUI programming can make effec-
tive use of object-oriented design. In fact, GUI’s, with their “visible objects,” are probably a
major factor contributing to the popularity of OOP.
Programming with GUI components and events is one of the most interesting aspects of
Java. However, we will spend several chapters on the basics before returning to this topic in
Chapter 6.
to the users of those computers). These services use TCP/IP to send various types of data over
the net. Among the most popular services are instant messaging, file sharing, electronic mail,
and the World-Wide Web. Each service has its own protocols, which are used to control
transmission of data over the network. Each service also has some sort of user interface, which
allows the user to view, send, and receive data through the service.
For example, the email service uses a protocol known as SMTP (Simple Mail Transfer
Protocol) to transfer email messages from one computer to another. Other protocols, such as
POP and IMAP, are used to fetch messages from an email account so that the recipient can
read them. A person who uses email, however, doesn’t need to understand or even know about
these protocols. Instead, they are used behind the scenes by computer programs to send and
receive email messages. These programs provide the user with an easy-to-use user interface to
the underlying network protocols.
The World-Wide Web is perhaps the most exciting of network services. The World-Wide
Web allows you to request pages of information that are stored on computers all over the
Internet. A Web page can contain links to other pages on the same computer from which it
was obtained or to other computers anywhere in the world. A computer that stores such pages
of information is called a web server . The user interface to the Web is the type of program
known as a web browser . Common web browsers include Internet Explorer and Firefox. You
use a Web browser to request a page of information. The browser sends a request for that
page to the computer on which the page is stored, and when a response is received from that
computer, the web browser displays it to you in a neatly formatted form. A web browser is just
a user interface to the Web. Behind the scenes, the web browser uses a protocol called HTTP
(HyperText Transfer Protocol) to send each page request and to receive the response from the
web server.
∗ ∗ ∗
Now just what, you might be thinking, does all this have to do with Java? In fact, Java
is intimately associated with the Internet and the World-Wide Web. As you have seen in the
previous section, special Java programs called applets are meant to be transmitted over the
Internet and displayed on Web pages. A Web server transmits a Java applet just as it would
transmit any other type of information. A Web browser that understands Java—that is, that
includes an interpreter for the Java Virtual Machine—can then run the applet right on the Web
page. Since applets are programs, they can do almost anything, including complex interaction
with the user. With Java, a Web page becomes more than just a passive display of information.
It becomes anything that programmers can imagine and 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 much 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
network-related. 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. You will learn about Java’s network support in Chapter 11.
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.
∗ ∗ ∗
As Java has matured, its applications have reached far beyond the Net. The standard version
1.7. THE INTERNET AND BEYOND 17
of Java already comes with support for many technologies, such as cryptography and data
compression. Free extensions are available to support many other technologies such as advanced
sound processing and three-dimensional graphics. Complex, high-performance systems can be
developed in Java. For example, Hadoop, a system for large scale data processing, is written in
Java. Hadoop is used by Yahoo, Facebook, and other Web sites to process the huge amounts
of data generated by their users.
Furthermore, Java is not restricted to use on traditional computers. Java can be used to
write programs for many smartphones (though not for the iPhone). It is the primary develop-
ment language for Blackberries and Android-based phones such as the Verizon Droid. Mobile
devices such as smartphones use a version of Java called Java ME (“Mobile Edition”). It’s
the same basic language as the standard edition, but the set of classes that is included as a
standard part of the language is different. Java ME is also the programming language for the
Amazon Kindle eBook reader and for interactive features on Blu-Ray video disks.
At this time, Java certainly ranks as one of the most widely used programming languages.
It is a good choice for almost any programming project that is meant to run on more than one
type of computing device, and is a reasonable choice even for many programs that will run on
only one device. It is probably the most widely taught language at Colleges and Universities.
It is similar enough to other popular languages, such as C, C++, and C#, that knowing it
will give you a good start on learning those languages as well. Overall, learning Java is a great
starting point on the road to becoming an expert programmer. I hope you enjoy the journey!
18 CHAPTER 1. THE MENTAL LANDSCAPE
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?
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?
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.)
10. What is the “Internet”? Give some examples of how it is used. (What kind of services
does it provide?)
Chapter 2
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.
The last section of this chapter discusses programming environments. That section
contains information about how to compile and run Java programs, and you might want to
take a look at it before trying to write and use your own programs.
19
20 CHAPTER 2. NAMES AND THINGS
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
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:
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 informa-
tion 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
2.1. THE BASIC JAVA APPLICATION 21
some of the steps for you—for example, the compilation step is often done automatically—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
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. In an integrated development
environment such as Eclipse, the output might appear somewhere in one of the environment’s
windows.)
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
}
22 CHAPTER 2. NAMES AND THINGS
When you tell the Java interpreter to run the program, the interpreter calls this 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.
The word “public” in the first line of main() means that this routine can be called from out-
side 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-name i {
hoptional-variable-declarations-and-subroutines i
public static void main(String[] args) {
hstatements i
}
hoptional-variable-declarations-and-subroutines i
}
The name on the first line is the name of the program, as well as the name of the class.
(Remember, again, that hprogram-namei is a placeholder for the actual name!) 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 translation of the program into Java bytecode, which can be
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.
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
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
24 CHAPTER 2. NAMES AND THINGS
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.
If I say “the President is playing basketball,” I mean that Barack Obama is playing basketball.
But if I say “Sarah Palin wants to be President” I mean that she wants to fill the office, not
that she wants to be Barack Obama.)
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 “=”.)
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.
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, for representing integer data 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
26 CHAPTER 2. NAMES AND THINGS
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
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.
Java 7 introduces a couple of minor improvements in numeric literals. First of all, nu-
meric literals in Java 7 can include the underscore character (“ ”), which can be used to
separate groups of digits. For example, the integer constant for one billion could be writ-
ten 1 000 000 000, which is a good deal easier to decipher than 1000000000. There is no rule
about how many digits have to be in each group. Java 7 also supports binary numbers, using
the digits 0 and 1 and the prefix 0b (or OB). For example: 0b10110 or 0b1010 1100 1011.
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
2.2. VARIABLES AND TYPES 27
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.
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 subroutine 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 strongly 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
(with one very technical exception). 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.” However, I should note that some people prefer to use the
term “method” from the beginning.
∗ ∗ ∗
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. Generally, the returned value is meant to be used somehow in the
program.
You are familiar with the mathematical function that computes the square root of a num-
ber. Java has a corresponding function called Math.sqrt. This function is a static member
2.3. OBJECTS AND SUBROUTINES 31
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:
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 radi-
ans, 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 sub-
routine 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
32 CHAPTER 2. NAMES AND THINGS
endTime = System.currentTimeMillis();
time = (endTime - startTime) / 1000.0;
System.out.print("\nRun time in seconds was: ");
System.out.println(time);
} // end main()
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.print("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 N-
th 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 of 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. The
subroutine s1.substring(N) returns the substring of s1 consisting of characters starting
at position N up until the end of the string.
• 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).
34 CHAPTER 2. NAMES AND THINGS
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);
Obviously, this is very convenient. It would have shortened some of the examples presented
earlier in this chapter.
Other documents randomly have
different content
Section 2. Information about the Mission
of Project Gutenberg™
Project Gutenberg™ is synonymous with the free distribution of
electronic works in formats readable by the widest variety of
computers including obsolete, old, middle-aged and new
computers. It exists because of the efforts of hundreds of
volunteers and donations from people in all walks of life.
Most people start at our website which has the main PG search
facility: www.gutenberg.org.
ebookbell.com