JAVA HAS A BUILT-IN TYPE, String,
to represent strings of characters. This type differs from the
eight primitive types because a value of type String is
an object. A String is not just a data value;
it also has "methods." (A method is a subroutine
that is part of an object.) For example, if str
is a variable of type String, you can call the method
str.length(), which is a function that returns the
number of characters in the string. There's a lot more you
can do with strings. This section covers some of the
details.
One thing that you cannot do with strings is to use the
relational operators <, >, <=, and <=
to compare them. You can legally use == and != to compare
Strings, but because of peculiarities in the way
objects behave, they won't give the results you want. (The == operator
checks whether two objects are stored in the same memory location,
rather than whether they contain the same value. Occasionally,
for some objects, you do want to make such a check -- but rarely for strings.
I'll get back to this in a later chapter.) Instead, you should
use the methods equals() and equalsIgnoreCase(),
which are described below,
to compare two Strings.
The String class defines a lot of methods.
Here are some that you might find useful. Assume that s1
and s2 are Strings:
s1.equals(s2) is a boolean-valued function that returns true if s1 consists of exactly the same sequence of characters as s2.
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, is a char-valued function that returns the N-th character in the string. Positions are numbered starting with 0, so s1.charAt(0) is the actually the first character, s1.charAt(1) is the second, and so on. The final position is s1.length() - 1.
s1.substring(N,M), where N and M are integers, returns a String containing a substring of the characters in s1. The substring consists of the characters in s1 in positions N, N+1,..., M-1. Note that the character in position M is not included.
s1.indexOf(s2) returns an integer. If s2 occurs as a substring of s1, then the returned value is the starting position of that substring. Otherwise, the returned value is -1. You can also use s1.indexOf(ch) to search for a particular character, ch, in s1. To find the first occurrence of x at or after position N, you can use s1.indexOf(x,N).
s1.compareTo(s2) is an integer-valued function that compares the two strings. If the strings are equal, the value returned is zero. If s1 is less than s2, the value returned is -1, and if s1 is greater than s2, the value returned is 1. (If the strings consist entirely of lowercase letters, then "less than" and "greater than" refer to alphabetical order.)
s1.toUpperCase() is a String-valued function that returns a new string that is equal to s1, except that any lower case letters in s1 have been converted to upper case. There is also a method s1.toLowerCase().
s1.trim() is a String-valued function that returns a new string that is equal to s1 except that any non-printing characters such as spaces and tabs have been trimmed from the beginning and from the end of the string. Thus, if s1 has the value "fred ", then s1.trim() is the string "fred".
For the methods s1.toUpperCase(), s1.toLowerCase()
and s1.trim(), note that the
value of s1 is not changed. 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
"s2 = s1.toLowerCase();".
Here is another extremely useful fact about strings that
I haven't mentioned so far: You can use the 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.)
Even more surprising is that you can concatenate values
belonging to one of the primitive types onto a String
using the + operator. The value of primitive type is
converted to a string, just as it would be if you printed it
to the standard output. For example, the expression "Number" + 42
evaluates to the string "Number42". And the statements
TextIO.put("After ");
TextIO.put(years);
TextIO.put(" years, the value is ");
TextIO.put(principal);
can be replaced by the single statement:
TextIO.put("After " + years +
" years, the value is " + principal);
Obviously, this is very convenient. It would have shortened several of the examples used earlier in this chapter.
You can even use the
+= operator to add something onto the end of a String. For example,
if you want to read a sequence of letters from standard input and
store them in a String, you could do it like this:
String str = ""; // start with an empty string
char ch = TextIO.getChar(); // read one character
while ( (ch >= 'a' && ch <= 'z')
|| (ch >= 'A' && ch <= 'Z') ) {
// ch is a letter, so append it to the string
// and read the next character.
str += ch; // (note: same as str = str + ch;)
ch = TextIO.getChar();
} // end of while loop
End of Chapter 2
Page 2
ONE WAY TO BREAK UP A COMPLEX PROGRAM into
manageable pieces is to use subroutines.
A subroutine consists of the instructions for carrying out a certain
task, grouped together and given a name. Elsewhere in the program,
that name can be used as a stand-in for the whole set of instructions.
That is, as a computer executes a program, whenever it encounters
a subroutine name, it executes all the instructions necessary to
carry out the task associated with that subroutine.
Subroutines can be used over and over, at different places in
the program. A subroutine can even be used inside another subroutine.
This allows you to write simple subroutines and then use them to help
write more complex subroutines, which can then be used in turn in other
subroutines. In this way, very complex programs can be built up step-by-step,
where each step in the construction is reasonably simple.
As mentioned in Section 2.6, subroutines in
Java can be either static or non-static. This chapter covers static
subroutines only. Non-static subroutines, which are used in true
object-oriented programming, will be covered in the next chapter.
Sections in Chapter 3:
Page 3
WHEREAS A SUBROUTINE represents a single task,
an object can encapsulate both data (in the form of instance
variables) and a number of different tasks or "behaviors"
related to that data (in the form of instance methods).
Therefore objects provide another, more sophisticated
type of structure that can be used to help manage the complexity of
large programs.
This chapter covers the creation and use of objects in Java. It also
discusses the object-oriented approach to program design.
Sections in Chapter 4:
Page 4
JAVA IS A PROGRAMMING LANGUAGE DESIGNED for the world
of modern networked computers. Java programs are meant to be downloaded
over a network to run on any computer that implements the Java virtual
machine. Java is fast becoming an integral part of the World Wide Web,
the most interesting and fastest-growing Internet service, in the form
of "applets" that can be directly embedded into Web pages.
A Java applet uses a GUI (graphical user interface), in which the
user interacts with components such as buttons, menus, and text input
boxes. User interactions with these components generate events,
and an applet is programmed by specifying how it should respond
to the various kinds of events that can be generated. An applet that
wants to carry out some activity, such as an animation, independently
of user events can create a separate thread to do so. Similar GUI's
can be used in stand-alone applications as well as in applets.
This chapter covers some of the basics of applets, graphics, and
GUI's. There is a section about the
Web and about HyperText Markup Language (HTML), the
language used for writing Web pages. I've also included a long
section covering threads and animation. While threads are often
used to animate applets, they have much wider use beyond the context of GUI's. The discussion of applets and GUI's will
continue in the next chapter with a more complete discussion of
components and events.
Sections in Chapter 5:
Page 5
MOST COMPUTERS TODAY HAVE A Graphical
User Interface (GUI). With a GUI, the user interacts with the computer
through windows, buttons, menus, and other components
which are drawn on the screen. There are several different GUI's, for different
types of computers. Although each GUI has its own look-and-feel, they all
have certain features in common, and these common features make it possible
to write platform-independent programs that use a GUI.
The Java packages java.awt and java.awt.event
contain classes for writing programs
that use a graphical user interface. The previous chapter introduced several
of these classes, including the class Button.
An object of type Button represents a push-button that the user
can click on to perform some action. When the programmer creates an
instance of this class, it will appear on the screen as a button appropriate
to the platform on which the program is running. Even though the button will
appear different on different platforms, its "logical" or
"abstract" behavior will be the same. The Java programmer only has
to worry about this abstract behavior; the platform-dependent details are left
to the Java implementation on each platform. This is why the Java GUI
system is called the Abstract Windowing Toolkit (AWT).
This chapter continues the study of GUI programming that was begun in the previous chapter by looking at a much wider selection of components,
events, and layout managers. Section 4 introduces a new Java language
feature, nested classes, that is useful for event-handling but that can
be very useful in other contexts as well. Section 5 shows how a graphical
user interface can be used in standalone applications, rather than
just in applets. The final section of the chapter
looks at how events were handled in the original version of Java,
Java 1.0. The Java 1.0 event model can still be used in Java 1.1, and might
even be more convenient than the Java 1.1 model in some cases.
Sections in Chapter 6:
Page 6
COMPUTERS GET A LOT OF THEIR POWER from working with
data structures. A data structure is an organized
collection of related data. An object is a type of data structure (although
it is in fact more than this, since it also includes operations or methods
for working with that data). However, this type of data structure -- consisting of a fairly small number of named instance variables -- is only
one of the many different types of data structure that a programmer might
need. In many cases, the programmer has to build more complicated data
structures by linking objects together. But there is one type of data
structure that is so important and so basic that it is built into every
programming language: the array.
An array is a data
structure consisting of a numbered list of items, where all the items are of the same type. In Java, the items in an array are always numbered
from zero up to some maximum value. For example, an array might
contain 100 integers, numbered from zero to 99. The items in an array
can be objects, so that you could, for example, make an array containing
all the Buttons in an applet.
This chapter discusses how arrays are created and used in Java.
The last section introduces several other data structures
that are available as standard classes in Java.
Sections in Chapter 7:
Page 7
IT IS AN UNFORTUNATE TRUTH that sometimes when
programs are running, errors occur. There are programming errors,
such as an array index that is out of the actual range of indices for
the array or an attempt to divide a number by zero. Then there
are errors over which the programmer has less control or none at all, such
as when the user types in a word when the program is expecting a
number or when the system runs out of memory.
Often, when an error occurs, the program simply crashes (or worse,
goes on to produce incorrect results). However, Java provides a neat
mechanism for handling errors and other "exceptional conditions."
This exception-handling capability is one of the topics of this chapter.
The other topic is Java's built-in input/output facilities, which are
implemented through objects called Streams, Readers
and Writers. It turns out to
be impossible to use these objects without some understanding of
exceptions.
Sections in Chapter 8:
Exceptions, try, and catch
Streams, Readers, and Writers
Files
Networking
Page 8
WHEN I WROTE THE FIRST VERSION OF THESE NOTES in 1996,
Java was still a very new programming language. Although it had already caused
a lot of excitement, it's long-term prospects were not entirely clear. Now, in the
middle of 1998, I think it is clear that Java is an important language and
will remain so for the long term. However, it is true at least for now
that most "serious" programming is done in C and C++. Fortunately, these
languages share a lot of features with Java. The older language, C, has no
object-oriented features. C++ is a much larger language, which extends C with classes,
objects, and other features. This chapter serves as a brief introduction to C++
for someone who already knows Java. The coverage here is very incomplete,
and is meant only as a starting point for learning about C++.
You'll find that a lot of the basics ("programming in the small")
are almost identical in Java and C++. However, both the programming philosophy
and the large-scale structure of programs ("programming in the large")
in C++ are quite different from Java.