Quick Java
Quick Java
This book is intended to fill that gap. It’s written for the programmer
who doesn’t need to be taught how to program, just how to do it in
Java—and who needs to get started in a hurry.
Java is covered from the inside out. First, all the things that go inside a
class, most of which are practically identical to C++. After that, all the
various and complicated kinds of classes and interfaces and how they
relate to each other in large-scale programs.
There’s a lot in this little book and, despite my best efforts, you won’t
learn Java in a weekend. But it should be a good start.
FEATURES
David Matuszek
Designed cover image: David Matuszek
Typeset in Minion
by MPS Limited, Dehradun
To all my students
past, present, and future
Contents
Author, xv
Preface, xvii
Versions, xix
Chapter 2 ■ Preliminaries 13
2.1 IDEs 13
2.2 Comments and Tags 14
vii
viii ▪ Contents
3.2.3 Strings 21
3.2.4 Exceptions 22
3.2.5 Operators and Precedence 23
3.2.6 Declarations and Casting 25
3.2.7 Constants 26
3.2.8 Methods 27
3.2.9 Methods Calling Methods 29
3.2.10 Overloading 30
3.2.11 Scope 30
3.2.11.1 Variables Declared in Classes 30
3.2.11.2 Variables Declared in Methods 31
3.2.11.3 Variables Declared in Blocks 32
3.3 Statement Types 32
3.3.1 Statements Also in C++ 34
3.3.1.1 Blocks 34
3.3.1.2 Assignment Statements 35
3.3.1.3 Method Calls and Varargs 36
3.3.1.4 If Statements 36
3.3.1.5 While Loops 38
3.3.1.6 Do-while Loops 39
3.3.1.7 Traditional For Loops 40
3.3.1.8 For-each Loop 41
3.3.1.9 Classic switch Statements 42
3.3.1.10 Labeled Statements 44
3.3.1.11 Break Statements 44
3.3.1.12 Continue Statements 45
3.3.1.13 Return Statements 46
3.3.1.14 Empty Statements 46
3.3.2 Statements Not in C++ 47
3.3.2.1 Assert Statements 47
3.3.2.2 Print “Statements” 48
Contents ▪ ix
Index, 209
Author
I finally escaped from industry and joined the Villanova faculty full-time
for a few years, then I moved to the University of Pennsylvania, where I
directed a Master’s in Computer and Information Technology (MCIT)
program for students entering computer science from another discipline.
Throughout my career, my main interests have been in artificial
intelligence (AI) and programming languages. I’ve used a lot of pro-
gramming languages.
And, hey, if you’re a former student of mine, drop me a note. I’d love to
hear from you at david.matuszek@gmail.com.
xv
Preface
If you are coming from one of the C languages, you will find most of the
statement types familiar. These are clearly designated, so you can just
skim over that material.
If you are coming from C++, you will find the object-oriented concepts
are very similar, but the terminology is different.
If you are coming from another language, such as Python, there is very
little you can skip. Sorry.
xvii
Versions
T HIS BOOK IS ABOUT Java 8 and Java 17. Why those two?
Java 8 is the last version that is free for commercial use. If you are
programming for Android, Java 8 (also known as version 1.8) is the last
version you can use. For these reasons, additions to Java after version 8
will be noted as such.
As this book is being written, the current version is 17. A new version is
released every six months, so when you buy this book, the latest version
number is probably higher. This should not be a concern, because Java
“never throws anything away.” Newer versions do not invalidate older
versions, and the language changes gradually. In fact, Java 17 is an LTS
(Long Term Support) version, along with versions 8 and 11.
If you are uncertain which version of Java you have, you can execute this
from the command line:
java -version
System.out.println(System.getProperty("java.version"));
Since Java 9, you can also run jshell from the command line. This program
lets you execute Java statements (such as the above print statement) one at a
time. This is no way to write a program, but it’s handy for trying things out.
xix
xx ▪ Versions
If you have yet to download Java, it comes in two main varieties: the JRE
(Java Runtime Environment) is used to run existing programs, and the
JDK (Java Development Kit), which is used to create and run programs
(the JDK contains the JRE). Since you are reading this book, you almost
certainly want the JDK.
You can get the Java SE (Standard Edition) JDK from https://www.
oracle.com/java/technologies/downloads/.
Java 9 and beyond are (currently) free for personal use, but commercial
users should obtain a license from the Oracle Corporation.
CHAPTER 1
A Lightning Tour
of Java
Note: Java is verbose, and code lines are often 80 to 100 char-
acters long. Such lines have been split into more but shorter lines
in an attempt to improve readability.
1.1 PROJECTS
A program, or project, consists of one or more packages. A package is a
directory or folder that contains Java files.
Java files contain classes, usually one class per file. A class describes a
new type of object, and bundles together the object’s fields (its data) and
its methods. A class has one or more constructors to create new objects
of that type.
DOI: 10.1201/9781003402947-1 1
2 ▪ Quick Java
package examples.shapes;
public class Circle {
private int radius;
public Circle(int r) {
radius = r;
}
public double area() {
return Math.PI ∗ Math.pow(radius, 2);
}
}
A Lightning Tour of Java ▪ 3
The package declaration says that this code is in a folder (directory) named
shapes which is in a folder (directory) named examples. If any import
declarations were needed (none are), they would immediately follow this line.
The code defines a public class named Circle. The word public means
that the class can be used by any code throughout the program. Because
Circle is a public class, it must be on a file named Circle.java; this
allows other code to find it.
The Circle class has one integer instance variable named radius. Every
new Circle object that is created will have its own radius, and because
radius is marked private, it cannot be seen outside this class.
package examples.shapes;
public class CircleApp {
public static void main(String[] args) {
int size = 10;
Circle c = new Circle(size);
double area = c.area();
System.out.printf(
"The area of a circle " +
"with radius %d is %7.2f",
size, area);
}
}
CircleApp does not have an explicit constructor (it has an implicit one,
but ignore that for now). It does have a main method, which is the
starting point for the program. For complex reasons, the main method is
always defined as public static void main(String[] args)—just
memorize this for now; understanding will come later.
1.3 DATA
Every data value in Java is either a primitive or an object. There are eight
kinds of primitives, most of them numeric types. Objects are defined by
classes, and each class defines a new type of object.
The four most important types of primitive are: int (integers, or whole
numbers), double (numbers containing a decimal point), boolean (the
values true and false), and char (individual characters).
Two important types of object are strings and arrays. Strings are objects
defined by the String class, while arrays are defined using a more tra-
ditional syntax (but they are still objects.)
All variables must be declared before use; this specifies their type. They
can also be defined, or given an initial value.
All the values in an array must be of the same type. The type of the array
is written as the type of the elements, followed by empty brackets. For
example, int[] denotes an array of integers. The length of an array is
not part of the declaration; it is part of a definition.
Arrays are zero-based. The first element in the above numbers array is
numbers [0], and the last element is numbers [99]. The length of this
array, 100, is given by numbers.length.
The values in a newly-declared array will all be zero (for numeric arrays),
false (for boolean arrays), or null (for arrays of objects). Because
characters are treated as numeric values, the values in an array of char
will be the character "NUL" whose code is zero.
1.4 OPERATORS
Java has the usual arithmetic operators: + (add), − (subtract, or unary
minus), ∗ (multiply), / (divide), and % (remainder, or modulus). The
multiplicative operators ∗, /, and % are done before the additive opera-
tors + and −. Operations of the same precedence are done left to right.
6 ▪ Quick Java
Java has the boolean operators && (and), || (or), and ! (not). The
comparison operators <, <=, == (equals), != (not equal), >, and >= all
result in booleans. Booleans are not numbers, and you cannot use a
number where a boolean is expected.
A Java file may contain a package declaration, which names the folder
that the file is in, and some import declarations, to give the current class
access to classes in other packages. (Classes in the same package don’t
need to be explicitly imported.) The code for the class follows these
initial declarations.
package teamMaker;
import java.util.HashSet;
ClassName(parameters) {
declarations
statements
}
returnType methodName(parameters) {
declarations
statements
}
The returnType may be any primitive or object type, or the keyword void.
If the returnType is void, the method will return when a return; state-
ment is executed, or when the end of the method is reached. But if the
method is to return a value, it must terminate with a return expression;
8 ▪ Quick Java
To send a message to an object (that is, to call one of its methods), use the
syntax object.methodName(arguments). The value of this expression will
be the value returned by the method (or null if no value is returned).
1.6 STATEMENTS
The most commonly used statements are assignment statements, blocks
(or compound statements), if statements, while loops, and for loops.
All statements except blocks must end with a semicolon. The println
method may be used to produce output.
if (2 + 2 == 4) {
System.out.println("All is well.");
} else {
System.out.println("What??");
}
System.out.println(count);
count = count - 1;
}
System.out.println("Blast off!");
Java has no “print” statement, but the print and println methods can be
used as if they were statements. System.out.println(arg) takes a single
argument and sends it to standard output, followed by a newline character,
'\n'. System.out.print(arg) does the same but without the newline.
The program will start execution at the main method of a public class.
The main method should have this exact header:
If you are not using an IDE, any plain text editor (not a word processor)
may be used to create a program. Each class should be on a separate file,
and the name of the file should be the name of the class with the.java
extension.
If you are using Java 11 or later, you can run a program by navigating to
the folder containing the Java file and opening a command/terminal
window. In that window, enter java fileName. The file should run and
produce output.
If the above does not work, you may need to first compile the file and
then run it. To do this, execute the pair of commands:
javac ClassName.java
java ClassName.class
If a program consists of multiple files, any file that is used by another file
must be compiled before the file that uses it can be compiled.
There are two methods, main and doSomething. The program begins
execution in the main method. The main method is in a “static context,”
A Lightning Tour of Java ▪ 11
which means it can’t directly use any methods or variables that aren’t
also static. To get out of static context, main creates a new object of type
MyClass and immediately calls its doSomething method; this is where
you would put your code. After all this, you can forget about the word
static until you have a use for it.
Statements end with a semicolon. There are two statements in the above,
one to call doSomething and one to print Hello World.
The names MyClass and doSomething (but not main) may be replaced
with names of your choosing. By convention, class names always begin
with a capital letter, and method names with a lowercase letter.
With HelloWorld as a starting point, you can add methods and code to
make a useful program.
CHAPTER 2
Preliminaries
After some preliminaries, the next chapter describes the inner language
of Java (which is very like C or C++), and the following chapter describes
the outer language.
2.1 IDES
You can create and run complex Java programs with nothing more than
a text editor and the command line, but this is doing things the hard way.
DOI: 10.1201/9781003402947-2 13
14 ▪ Quick Java
reorganizing code, and any number of other services. I have had students tell
me that they succeeded in my course only because their IDE wrote their
programs for them.
The most popular Java IDEs are Eclipse, NetBeans, IntelliJ IDEA, and the
Mac-only Xcode. All are excellent and have ardent users; all have free
versions. All can be (and are) used for a number of other languages. Of
these, IntelliJ IDEA requires no prior knowledge of the interface but
simply guides the beginning user at each step.
That said, sometimes an IDE will simply refuse to work. This could be
the result of an upgrade, so that file versions are incompatible, or some
similar problem. (I have had this problem a lot with Eclipse.) Reinstalling
the IDE may help. Exploring all the possible settings may help. And, of
course, you can switch to a different IDE.
There are simpler IDEs, often written specifically for students, such as
BlueJ, JCreator, and DrJava. The advantage of a simpler IDE is that it is less
intimidating. The disadvantage is that it does less to help the programmer.
It has been said that the hardest program to write in any language is
“Hello World”; all subsequent programs are just elaborations of this one.
In the same way, once you successfully use a professional IDE to write
and execute a program, all the rest is just elaboration.
Example:
/∗∗
∗ Returns the sum of two numbers.
∗ @param a The first number.
∗ @param b The second number. Cannot be negative.
∗ @return the sum of the two numbers.
∗ @throws AssertionError if b is negative.
∗/
int add(int a, int b) {
assert b >= 0; // ignored unless -ea is set
while (b > 0) {
// Move a 1 from b into a
b -= 1;
a += 1;
}
16 ▪ Quick Java
return a;
}
Java is case-sensitive; that is, result, Result, and RESULT are three
different names. The names of the primitive types (int, double, etc.) are
all lowercase, while object type names such as String are capitalized.
DOI: 10.1201/9781003402947-3 17
18 ▪ Quick Java
Many kinds of things in Java have names, not just variables. Proper naming
and capitalization helps the experienced Java programmer know what kind
of thing is being named. There are strong conventions for names:
The other four primitive types (long, short, byte, and float) aren’t
used in most programs, and will be discussed in section 5.2.2.6.
3.2.2 Arrays
An array is an ordered sequence of values, all of the same type. To access
the individual values in an array, use the syntax arrayName[index]. Legal
indices range from 0 (the first value in the array) to arrayName.length -1
(the last value).
baseType[] arrayName;
20 ▪ Quick Java
or:
baseType arrayName[];
For example,
int[] scores;
This declares but does not define the scores variable. That is, its type
has been assigned, but no value of that type has been assigned to it. An
array variable that has been declared but defined will have the special
value null, and attempting to use it will result in an error.
Once an array is defined, you cannot change its size. However, the size of
an array is not part of its type, so an int array of any size can be assigned
to scores. Later, you might assign a different array, of a different size, to
scores. You can find the size of an array by asking it for its length
variable, array.length.
Arrays created as shown above will have its elements set to 0, false, or
null, for numeric, boolean, or object arrays, respectively. Alternatively,
an array can be created with specific values, using the syntax new type[]
{value, …}, for example,
The values in an array must all be of the same type, but the array size is
not part of that type. The following code constructs a “triangular” array
of arrays, in which each sub-array is larger than the one preceding it:
3.2.3 Strings
A string literal is a sequence of zero or more characters enclosed in
quotation (double quote) marks. For example:
Strings are immutable, that is, you cannot change the length or the
characters in a string; you can only create a new string.
3.2.4 Exceptions
Lots of things can go wrong in a program: dividing by zero, going outside the
bounds of an array, reading a file that isn’t there. When one of these things
happens, Java creates a type of object called an Exception. There are many
The “Inner Language” of Java ▪ 23
Exceptions are objects, just like strings and arrays are objects, and there
are two general kinds: checked and unchecked.
&& (and)
|| (or)
• Inequality tests:
< <= >= > (less than, less or equal, greater or equal, greater than)
• Equality tests:
== (equal to) and != (not equal to)
• Assignment operators:
= (simple assignment)
+=, -=, *=, /=, and %= (x op= y is short for x = x op y).
Less important operators (++, -‐, ?:, and the shift and bit manipulation
operators) will be discussed later—see sections 5.2.4.4 (++ and -‐),
5.2.4.2 (?:), and 5.2.4.3 (bit and shift), respectively.
When arithmetic is done using only integral types (including char), the
result is an int. Arithmetic using a double with any numeric type results
in a double.
Java will complain if it thinks you might be using a variable before it has
been given a value. If Java doesn’t catch this mistake, the value used will
be zero for numeric types or false for booleans.
A char variable can hold any of about 65000 UTF-16 characters (see
section 5.2.2.4). Characters are stored internally as numbers, and can be
used in arithmetic as if they were integers. You can write a UTF-16
character in hexadecimal as '\uxxxx', where xxxx is a hexadecimal
number in the range '\u0000' to '\uffff'. For example, '\u0041' is
'A', and '\u03A3' is 'Σ'.
int i = 0;
double d = 2.71828;
i = (int)d;
System.out.println(i); // prints 2
A cast affects the one immediately following value: (int)2 ∗ d casts only
the 2 to an int (which it already is). To cast an expression, put parentheses
around it: (int)(2 ∗ d).
A boolean is not a numeric type, and cannot be cast to or from any other
type.
3.2.7 Constants
Putting the word final in front of a variable declaration makes it into a
constant; its value cannot be changed. For example,
3.2.8 Methods
A method is like a function, except that it belongs to a class. This gives it
special access to the variables and other methods of that class. The syntax is
/**
* documentation comment
*/
access returnType methodName(parameterList) {
declarations
statements
}
Here is an example:
/**
* A leap year is a year divisible by 4 but not
28 ▪ Quick Java
In the body of the method you can have declarations of variables, with
or without an initial value, for example,
int count = 0;
All such declarations are local to the method, that is, they can be seen
and used only within the method. Variable declarations are usually put
first in the method body. A method may make use of the values given to
its parameters, its local variables, and any fields defined by the class it
is in.
There can be multiple methods with the same name, so long as they have
different numbers of parameters or different parameter types. Java looks
at both the name and the parameters (but not the return type) to decide
which method to use.
Within the method, the statements can refer to any fields of the class, any
parameters, and any local declarations. The keyword this refers to “this”
object, the one executing the method. When there is a local variable or
parameter with the same name as a field, then name by itself refers to the
local variable or parameter, while this.name refers to the field.
obj.methodName(arguments)
There must be one argument for each parameter, and it must be of a type
that can be assigned to that parameter. The called method returns a
result that can be used in further expressions.
When a method calls another method in the same class (so that the
object is “talking to itself”), the obj can be the keyword this, or it can be
omitted. For example, if isLeapYear is in the same class as
printLengthOfYear, then in printLengthOfYear you can say either
this.isLeapYear(year) or simply isLeapYear(year).
days = 366;
}
System.out.println(year + " has " +
days + " days.");
}
3.2.10 Overloading
Methods may be overloaded. That is, a class can have two or more
methods with the same name, so long as the methods have a different
number of parameters or different types of parameters. For example, a
class might have two or more methods named bump.
The types do not have to match up exactly. If there is no exact match, but
the argument(s) can be widened to an appropriate type, then the method
can be used. For example, the bump(int n) method could be called with
char argument, but not with a double argument.
3.2.11 Scope
Every variable has a scope, which is the part of the program in which the
variable may be used. The scope depends on where the variable is declared.
Here’s one way to think of it. When a class is first used, Java goes
through and executes all the top-level declarations (that is, those not in
methods), in the order that they appear. After that, the methods in the
class are available for use.
The parameters (in this example, x and y) can be used everywhere in the
method, but are not available outside the method. Variables declared
within the body (sum in this example) follow the scope rules for blocks
(see the next section).
The parameters and the variables declared within the body are local
variables; they are created when the method is invoked (used), and
discarded when the method returns. Local variables do not retain their
values from one invocation (call) of the method to the next; each
invocation starts all over again.
32 ▪ Quick Java
{
x = 1; // illegal!
int x; // scope of "x" starts here
x = 2; // legal
} // scope of "x" ends here
x = 3; // illegal!
● assert booleanExpression;
● assert booleanExpression: expression;
● switch (expression) {
The “Inner Language” of Java ▪ 33
Here is a list of the statements that are essentially the same as those in
C++.
● variable = expression;
● expression;
● { statements }
● if (condition) {
statements
}
● if (condition) {
statements1
} else {
statements2
}
● while (condition) {
statements
}
34 ▪ Quick Java
3.3.1.1 Blocks
A compound statement, or block, is some number (possibly zero) of
declarations and statements, enclosed in braces, {}.
The “Inner Language” of Java ▪ 35
x = 5;
The value of a variable, but not its type, may be changed. For example,
the assignment statement
x = 10;
is shorthand for
You can write a method that takes a variable number of arguments, or var-
args. Simply put three dots after the type name of the last parameter. When
the method is called, Java puts all those last values into an array for you.
3.3.1.4 If Statements
An if statement tests a condition. If the condition is true, the following
statement (typically, a compound statement) is executed. If the condition
is not true, the if statement does nothing. The syntax is:
if (condition) {
statements
}
if (x < 0) {
x = 0;
}
The “Inner Language” of Java ▪ 37
if (condition) {
some statements
}
else {
some other statements
}
For example,
if (x % 2 == 0) {
x = x / 2;
}
else {
x=3*x+1
}
It is good style to always use the braces, even if they include only a single
statement. However, if either part contains just one (non-compound)
statement, it is legal to omit the braces. If you do this, you should put the
single statement on the same line as the if or the else.
if (x % 2 == 0) x = x / 2;
else x = 3 * x + 1;
if (x < 0) {
System.out.println("x is negative");
} else if (x > 0) {
System.out.println("x is positive");
} else {
System.out.println("x is zero");
}
38 ▪ Quick Java
while (condition) {
statements
}
First, the condition is tested; if it is false, nothing more is done, and the
loop exits without ever executing the statements. If the condition is true,
the statements are executed, then the entire loop (starting with the test)
is executed again.
Normally, the statements controlled by the loop must affect the condi-
tion being tested. In the above example, number is compared to 0, and
the statements in the loop change the value of number. If the controlled
statements never make the condition false, then the loop never exits, and
the program “hangs” (stops responding). This is a kind of error is
commonly, if inaccurately, called an infinite loop.
do {
statements
} while (condition);
This kind of loop is most often used when the test doesn’t make any
sense until the loop body has been executed at least once. For most
purposes, the while loop is preferable.
As with a while loop, an infinite loop will result if the exit condition is
never satisfied.
The do-while loop is a little harder to think about than a while loop.
Since we want a number that is divisible by 7, the loop has to test that the
number is not divisible by 7.
do {
int x = rand.nextInt(1000);
} while (x % 7 != 0); // error
Variables declared within a block are local to that block. If the variable x
is declared within the braces of the do-while loop, it cannot be used in
the condition, which lies outside of the block.
Two additional statement types, break and continue, can also control
the behavior of do-while loops. These statements can be used with
statement labels.
The initialization is performed first, and only once. After that, the
condition is tested and, if true, the statements are executed and the
update is performed; then control returns to the condition. In other
words, the for loop behaves almost exactly like the following while
loop:
initialization;
while (condition) {
statements;
update;
}
The scope of any variable declared in the initialization (that is, where the
variable can be used), is the entire for statement.
The “Inner Language” of Java ▪ 41
As an example, an array can be declared and its contents written out by:
Also legal, but much less commonly used, the initialization and the
update may each consist of two or more assignments. For example,
Two additional statement types, break and continue, can also control
the behavior of for loops. These statements, described in sections
3.3.1.11 and 3.3.1.12, can be used with statement labels.
As with a traditional for loop, the type must be omitted if the variable
has been previously declared. Also, as with the traditional for loop, the
scope of the variable is the entire for statement. For example, every
element in a String array names can be printed out as follows:
The for-each loop can also be used with iterable objects (see
section 5.2.3.1).
switch (expression) {
case constant1:
statements1;
break;
case constant2:
statements2;
break;
…
case constantN:
statementsN;
break;
default:
statementsdef;
}
The value of the expression must be one of the integer types (including
char), or a string, or an Enum value (see section 5.3.6). The constants
may be integers, characters, literal strings, or Enum values.
The “Inner Language” of Java ▪ 43
The break statement is not required at the end of each case, just
strongly recommended. Without a break, control will “fall through”
into the next group of statements. This is seldom what you want to
happen. On the rare occasion that this really is the desired behavior,
you should include a comment that the omission is intentional, oth-
erwise you or someone else may “correct” this apparent problem at
some later date.
If the same code should be executed for one or more constants, rather
than duplicating the code, one case constant: can be followed imme-
diately by the next, for example,
case "yes":
case "Yes":
case "YES":
some statements
The default case is optional, and should come last; it will be executed if
no earlier matching expression is found. If no matching expression is
found and there is no default case, the switch statement exits without
doing anything.
It is good style always to include a default case, even if you believe that
all possibilities have been covered. The default case might be empty, or it
could include the statement assert false; to indicate that this code
should never be reached. (Assert statements are covered in section
3.3.2.1.)
int i = 3;
String s;
switch (i) {
case 1:
s = "one";
break;
case 2:
s = "two";
break;
default:
s = "many";
}
identifier: statement;
Any statement may be labeled with an identifier, but it really only makes
sense to label loop statements and switch statements. Labels are used in
conjunction with the break and continue statements.
break label;
int i, j = 0;
int[] ary = {7, 30, 9, 20, 3, 5};
id: for (i = 0; i < ary.length; i += 1) {
for (j = 0; j < ary.length; j += 1) {
if (i!= j && ary[i] == 10 * ary[j]) {
break id;
}
}
}
System.out.println(ary[i] + ", " + ary[j]);
continue label;
The following code computes the average of the positive values in the
array ary, ignoring the zero and negative values.
return;
return expression;
for a method that returns a value. The type of the expression must be the
same as, or narrower than, the type that the method is supposed to return.
and
assert booleanExpression;
assert booleanExpression : expression;
The purpose of the assert statement is to state some condition that you
believe will always be true at that point in the program. It should not be
used to check for possible error conditions that you believe could
happen; for that, you should throw an exception (see section 3.3.2.6).
There is little point in using the second form (with expression) unless
you have something useful to add. For example, if you believe that some
array index i is always within the array bounds, you might say
Finally, the idiom assert false; can be used to indicate that you
believe that a certain section of code (for example, the default case of a
switch statement) can never be reached. However, it is a syntax error
to put this (or any other) statement in a location that the Java com-
piler knows cannot be reached, such as immediately following a
return statement.
System.out.println(value);
and
System.out.print(value);
Although print and println are used as if they were statements, they
are actually methods that have the side effect of displaying something on
your screen. (Method calls which do not have side effects can also be
used as statements, but this is usually pointless, since the return value is
ignored.)
If the value is an object type, print and println will call its
toString method to get a printable representation of the object. This
gives you considerable control over how your objects are printed (see
section 4.4.1).
The “Inner Language” of Java ▪ 49
Printing to the screen is easy, but getting input from the keyboard
requires the use of a Scanner object, covered in section 3.4.1.3.
switch (expression) {
case constants1 -> action1
case constants2 -> action2
…
case constantsN -> actionN
default -> actiondef
}
Despite the name, pattern matching has nothing to do with regular ex-
pressions. Instead, the switching is done on the type of an expression,
and the result of the expression is assigned to a new variable.
switch (expression) {
case Type1 variable1 -> action1
case Type2 variable2 -> action2
…
case TypeN variableN -> actionN
default -> actiondef
}
The value of the expression must be a supertype of the case Types. When
a matching Type is found, the value of the expression is assigned to the
corresponding variable, and the action (expression or statement) is
executed.
Unlike earlier versions of the switch statement, any object type may be
used as a case type, including null. Primitives, however, cannot be used.
where the guard is a boolean expression using the value of the variable.
If the boolean expression is complicated, it should be enclosed in
parentheses.
3.3.2.5 Try-catch-finally
Code that can throw a checked exception must either be in a method that
is declared to throw that exception, or it must be in the try part of a
try-catch-finally statement. Syntax is as follows:
try {
code that might throw the exception
}
catch (SomeExceptionType variable) {
code to handle this kind of exception
}
catch (SomeOtherExceptionType variable) {
code to handle this other exception type
}
finally {
code that is always done before leaving
}
Whether or not the code in the try block completes normally, the
finally block (if present) is always executed. If the code in the try
block or one of the catch blocks attempts to exit some other way (via a
return, break, or continue statement), the finally block “steps in the
way” and executes before that exit statement can occur.
if (b < 0) {
throw new Exception("b is negative");
}
This code creates an object of the very general type Exception (there are
many more specific exception types) and immediately throws the
Exception.
Some exception types are checked. If you execute code that could pos-
sibly throw a checked exception, Java insists that you do something
about it; it is a syntax error if you don’t. One thing you can do is to put
the offending code in the try part of a try-catch statement.
Alternatively, you can say that your method (possibly) throws the ex-
ception. Then whatever called your code has to deal with the exception;
it’s no longer your responsibility.
54 ▪ Quick Java
Now the code that calls myMethod must either call it in the try part of a
try-catch statement, or the header of that calling method must include
a throws part. In this way the exception may be passed up many levels of
method calls before it is finally handled. If it reaches all the way up to the
main method and the main method doesn’t handle it, the program ter-
minates with an error.
The FileReader class has methods that will read characters and return
them as integers. This is inconvenient, so the usual way to read files is to
wrap a BufferedReader around a FileReader object.
• readLine() reads and returns one line (as a String), or null if the
end of the file has been reached.
The “Inner Language” of Java ▪ 55
try { … }
write
Note: The above path has the form it does because this code was
tested on a Macintosh. On a Windows machine, paths typically
begin with C: and use double backslashes rather than forward
slashes.
The above code segment will create the file test2.txt if it does not
already exist, and will replace any existing contents of that file with the
two lines Hello and Goodbye. To add to the end of an existing text file,
use FileWriter's append(string) method.
Simply, each class defines a type, and objects are values of that type.
Here is an analogy: A class is like a recipe, while objects are the things
you can make by following the recipe. Once you have the recipe (class),
you can make many things (objects) from it. Almost everything in a
class is devoted to describing what is in the object, and what it can do.
• The fields (or instance variables) are the data belonging to the
object.
• The constructors create new objects of that type. To call a con-
structor, use the keyword new.
• The methods are code to manipulate that data.
You can get the length of this string by using the length() method:
To send a message to an object: Name the object, put a dot, then say
what method you want the object to execute, and what arguments (if
any) the method needs.
The “Inner Language” of Java ▪ 59
To create a new StringBuilder object (or any other kind of object), use the
keyword new, the name of the class, and any required arguments. Like this:
StringBuilder has lots of methods for changing the string data, all of
which use the standard dot notation. For example, to add text to the end,
you can say
builder.append("Script");
When you are finished, you can ask the StringBuilder object to return
a String version of itself.
Almost all provided classes and objects keep their data private, and the
only way to access their data is by using the methods they provide. When
they do make data available it is usually as a constant, for example
Math.PI and Math.E in the Math class. This is good practice in general.
To read input from the user, first import the Scanner class.
import java.util.Scanner;
The System.in argument says the scanner is to take input from the
keyboard. (The argument could also be a file, or even a string, which is
nice for testing purposes. We don’t explore those options here.)
One way to avoid errors is to check the type of the next token by
“looking ahead” at it, with the methods hasNextInt(), hasNextDouble
The “Inner Language” of Java ▪ 61
The method nextLine() will read in, as a string, the next line.
You seldom need more than one Scanner. If you want to make use of a
scanner in several different classes or packages, use a public static
variable to hold the Scanner object, and put it in an accessible class.
As with most of the classes described in this book, the Scanner class has
many more methods than are mentioned here. For example, a scanner
may use regular expressions to tell it what to read.
3.4.1.4 Console
The class java.io.Console provides a much simpler way to read input
from the user than the Scanner class, but it has a significant disadvantage:
It requires the presence of an interactive “console.” Depending on how the
Java program is being executed, a console may or may not be present. In
many cases, Console can be used when running from the command line,
but not when running from an IDE.
Along with arrays, Java has various types of Collections: Stacks, Lists,
HashMaps, and so on. Originally, any type of object could be pushed onto a
Collection, and there was no way to be more specific. When you got a
value out of the collection, you got an Object, and had to cast it to the
correct type. For backwards compatibility, this style is still allowed.
For example, Java has a Stack type (in the java.util package), with
operations push and pop (among others).
The genericized type name can be used wherever an “ordinary” type name
can be used, such as in the declaration of a method. For example,
3.4.1.6 Maps
One of the most useful objects in the java.util package is the HashMap.
To find the documentation, search online for “java se 17 api” or similar. One
of the top hits should be something like “Overview (Java SE 17 & JDK 17).”
The “Inner Language” of Java ▪ 65
(If you are programming for Android or similar, you will want the Java SE 8
documentation instead.) Following that link should take you to a page with
a long list of modules; click on the one for java.base. Bookmark this page;
it is a good starting point. If you are interested in GUI development, also
bookmark the link to java.desktop.
One of the packages on the java.base page, very near the top of the list,
is java.lang. This package is necessary for every Java program and is
automatically imported into every Java program. Click on java.lang to
go to a page listing all the classes in this package.
You will see some of the classes we have already mentioned, such as
Character and Exception. Scroll down and click on String.
Right under Class String you will see that its superclass is java.lang.
Object (clickable) and that it has implemented some interfaces (also
clickable). The methods inherited from Object will not be described on
this page (unless they have been overridden), but they will be listed
further down. Methods from the interfaces are described below, along
with all the other methods.
We will pick one method on this page to examine. Scroll down to the line
that looks like Table 3.1:
In this line, indexOf and String are bold, meaning that they are
clickable. Often, the description is all you need, but you can click on the
method name to jump down to a detailed description.
There will be a lot on these pages you don’t understand. That’s fine; the
important thing is to get comfortable exploring the documentation, and
using the parts you do understand. If you are working a lot with strings,
it is worthwhile to look through the methods to find ones you might use.
A class defines a type of object. It tells what fields are in each object, and
what methods operate on that object.
Each class has at least one constructor for making new objects of that
type. To create a new Item object, you may have to provide the con-
structor with a description of the item, its shipping weight, its price, and
whatever else is important about the item.
Every object has a type, and the name of that type is the same as the
ClassName. If you define a class Item, then every object created from
that class will be of type Item.
DOI: 10.1201/9781003402947-4 69
70 ▪ Quick Java
Normally, every top-level class goes in a separate file, and the name of the
file must be the name of the class, with the extension.java.
Note: More than one top-level class can be put in a file, but only one
of them can be public, and that is the one the file must be named
after. However, one class per file is the recommended organization.
The name of the class is Password, and each object created from the class
will hold one password. The method matches will tell us if a password is
correct, and the reset method will allow us to change it. Without fur
ther ado, here’s the class:
The name of the class is Password, and it is public, so it can be seen and
used anywhere in the project.
Next in the class is a constructor. It has the same name, Password, as the
class that it is in, and it will return a Password object. (Constructors do
not use an explicit return statement.)
Notice that the constructor has access to two different variables, both
named password. One is the field, or instance variable, while the other is
a parameter. This may look strange, but it is quite commonly done,
especially in constructors. To distinguish between them, the name
password by itself refers to the parameter, while this.password refers
to the instance variable.
Finally, there is a reset method that takes two strings as parameters and
tells whether the reset succeeded. It is not marked public, protected,
or private, so it has package access—it can be used by any class in the
same package.
Fields and methods can be labeled with any one of the above access
types, with “package” as the default. Local variables of a method cannot
be so labeled; they’re just local.
Classes are arranged in a hierarchy, with the Object class at the root
(top) of the hierarchy. Every class except Object extends one other class,
called its superclass, and inherits data and methods from that superclass.
If the superclass is omitted, Object is assumed.
Briefly, inheritance means that if class B extends class A, then all the data
and methods in A are also part of B. B can extend what it receives from A
by defining additional data and methods. This will be examined in detail
in section 4.2.
The class may also implement some interfaces, as described briefly in the
next section.
4.1.3 Interfaces I
An interface is a list of methods—just the method headers, not the body. A
class that implements an interface must supply those methods, with the
same headers but also with a body. For example, the String class imple
ments the CharSequence interface, and that interface requires the String
class to supply several methods, among them charAt(index), length(),
and isEmpty().
A class may extend another class, thus inheriting all its fields and methods.
Similarly, an interface may extend another interface, thus inheriting
additional methods to be implemented.
The “Outer Language” of Java ▪ 73
4.1.4 Fields
A class typically contains fields (or more accurately, field declarations).
This is where data is kept. It is the values in these fields that make one
object different from another object of the same type.
If the word static is present, then there is only one copy of the variable
being defined, and it is shared by all instances of the class. Otherwise,
every object created from this class has its own copy of the fieldName
variable. In the Password class mentioned earlier, every object of that
type has its own password field.
Most fields should be marked private. Any fields that are not private can
be accessed by other classes. As a program is being developed, or later
updated, other classes may come to depend on these non-private variables,
and this (possible) dependency makes it difficult or impossible to update
or modify the class without the danger of breaking some code somewhere.
Instead, all access to fields should be under the control of the methods in
the class. This is how it is done in the Java-supplied classes, and how you
should do it.
74 ▪ Quick Java
Note: Private fields are private to the class, not to the object.
Objects have no privacy from other objects of the same type. For
example, code in the Password class (see section 4.1.1) can
access not only this.password, but also john.password, ja
ne.password, and so on.
The type of a field can be the name of any primitive type (int, double,
etc.) or the name of any class type (String, Exception, Password, etc.).
Examples:
String name;
double length = 22.75;
private int count = 0;
4.1.5 Constructors I
The purpose of a constructor is to create an object in a valid state. No
other work should be done in a constructor.
For example, you might have a class Customer that starts out like this:
The newly created object is returned as the value of the call to the
constructor. No return statement is necessary in a constructor.
The optional documentation comment should tell the user what the
method does and how to use it. It should describe any restrictions on the
parameter values, and what to expect of the return value. It should not
talk about how the method is implemented. The documentation (doc)
comment may also contain tags to add specific kinds of information:
The @param tag describes a parameter, @return describes the result, and
@throws describes an exception that may be thrown. Additional tags are
described in section 5.2.1.2.
The access tells what other classes can use this method. It can be public,
“package” (default), protected, or private.
The returnType tells what kind of value is returned by the method. If the
method does not return a value, the keyword void is required.
In the body of the method you can have declarations of variables, with
or without an initial value, for example,
int count = 0;
Unlike fields, variables cannot have an access specifier; all variables are
local to the method, and cannot be seen or used outside the method.
Variable declarations are usually put first in the method body.
The “Outer Language” of Java ▪ 77
Within the method, the statements can refer to any fields of the class, any
parameters, and any local declarations.
As is right and proper, all access to and modification of the field funds is
handled by methods in the same class. When money is taken from a
different account other, it is done by asking the other object to with
draw money.
The following line suggests one reason that fields should be private:
john.funds = 1_000_000;
A class like this would not normally contain a main method; I put one in
(temporarily) to do some very simple testing. For a much better approach
to testing, see section 7.7.
4.1.8 References
In order to work with objects, it is critical to understand the concept of
references.
type (String, array, Customer, etc.) gets only 4 bytes. This obviously
isn’t enough for most objects.
After the assignment b = a, the variable b has a copy of the value from a,
and either variable can be modified independently.
After the assignment obj2 = obj1, both variables refer to the same
object. Either reference can be used to “talk to” and change the object,
and the data in the object will be the same regardless of which reference
is used to view it.
80 ▪ Quick Java
4.1.9 Constructors II
When an object is constructed, it is actually constructed in layers, with
Object being the foundation layer for every object.
If you have a Customer class, and this class extends Person, and Person
extends Object, then when you create a new Customer object, here’s
what happens:
The result is that the Customer object inherits all the data and methods
from Person, and all the data and methods from Object. It can use these
things just as if they were defined here in the Customer class.
The first action in any constructor must be to call a constructor for its
superclass. You can write an explicit call like this: super(parameters);.
A call like this must be the very first line in your constructor because the
foundation must be built before you can begin adding to it.
The “Outer Language” of Java ▪ 81
If you don’t explicitly call a constructor for the superclass, Java supplies
an implicit (“invisible”) call for you. If you could see it, it would look like
this: super();.
If the Person class has an explicit constructor that takes parameters, and
you write Customer as a subclass of Person, you must write a con
structor that calls the Person constructor with the proper arguments.
In this example, Customer objects have the instance variables name and
address because they are inherited from the Person class. These vari
ables should not be declared again in the Customer class.
If, in a constructor, you say this(parameters) as the very first action, then
that other constructor will be called, and it is responsible for calling the
82 ▪ Quick Java
4.1.10 Static
An object bundles together data about a thing, and methods to operate
on that thing. But objects are defined by classes, and a class may have its
own data and methods.
There is only one copy of each static variable, shared by all objects of that
class. Static variables are used to say something about the class or
something that is the same for every object in the class.
Suppose you had a Customer class, and each Customer object holds
information about that particular customer. Now suppose you wanted to
keep track of how many customers you have; that is, how many times a
Customer object has been created. You can add a howMany field to the
class, but it doesn’t make sense for every Customer object to have its own
(possibly different) value for howMany. The solution is to add a howMany
field, but make it static.
howMany += 1;
}
}
Note: We don’t need an object of the class to use its static fields
and methods, but if we have one, we can use it. That is, if
richGuy is a Customer object, we can say richGuy.howMany and
get the same result as Customer.howMany, or the same as
poorGuy.howMany. This can seem confusing because it is
sending a message to a particular object, but getting a response
from the object’s class.
Static methods (another name for class methods) work the same way;
they are attached to the class, not to particular objects. We can “talk”
(send a message) to the class directly, or indirectly by talking to any
object of that class. For example,
Methods that don’t depend on anything in the class, but are in it simply
because every method has to be somewhere, should also be made static.
84 ▪ Quick Java
If what you want to do is simple enough, you might want to just write
one class with a handful of methods. In that case, you can make every
method and field static, but this gets annoying in a hurry. Alternatively,
you can create one object of the class that you are in, and call a non-static
method on that object. That is what we did very early in this book.
This program starts, as does every Java program, in the static method
main. Then it creates a new MyClass object and immediately calls
that object’s run method. Now everything else can proceed from the
run method, and you are no longer forced to make everything static.
(I used the name “run” for this method, but you can name it whatever
you like.)
• public: The class and the method must both be public, that is,
available from anywhere. In particular, it has to be available to your
operating system.
• static: Compiling the program defines the class MyClass (and any
other classes in your program), but there are no objects yet, just
classes. Since there are no objects, neither are there any instance
methods. But the main method is static and it belongs to the class
MyClass, which does already exist. Therefore, the operating system
can send the message main to the class MyClass.
• void: The main method does not return a result.
• main: The operating system always starts a Java program by sending
it the message main(arguments). Specifically, since it is trying to
run a program on the file named MyClass.class (compiled from
MyClass.java), it sends the message main to the class MyClass.
• More than one class can have a main method, so you can have more
than one possible starting point in a program. For example, you
might have one program to both encode and decode messages and
have a main method in both an Encoder class and a Decoder class.
• (String[] args): The main method can take arguments, either
from the command line or from the IDE. Arguments are separated
by spaces, and come in as strings. It’s okay if there are no
arguments—zero-length arrays are legal in Java.
package myPackage;
public class MyClass {
public static void main(String[] args) {
System.out.println(args[0] + args[1]);
}
}
javac myPackage/MyClass.java
abc123
package tools;
/**
* A simple counter class
*/
public class Counter {
private int count; // a field
/** Constructor to make a Counter
* object with an initial value.
*/
The “Outer Language” of Java ▪ 87
The class has one field, int count. Every object made from this class will
have its own count field, so you can have multiple counters keeping
track of different values. The constructor takes a parameter initial to
use as the initial value of count.
The class has three methods, two named bump and one named getCount.
These are declared public so they can be used from outside the package.
The bump() method adds 1 to the count field, while the bump(int n)
method adds n to the count field; neither returns a value. The getCount
method returns the current value of count.
To complete the example, let’s write a program to test our Counter class.
package toolUser;
import tools.*;
c1.bump(2);
c1.bump(8);
c2.bump(100);
c2.bump();
System.out.println(c1.getCount() + ", " +
c2.getCount());
}
}
This class is in a separate folder, named toolUser. The second line says
to import, or make available, everything in the tools package.
The next lines declare variables c1 and c2 of type Counter, create new
Counter objects with different initial values, and assign them to the variables.
The following lines use dot notation to send several bump messages, with
different parameters, to the c1 and c2 objects.
4.2 INHERITANCE
Classes form a treelike hierarchy, with Object at the root. Every class,
except Object, has one and only one immediate superclass, and that
class has its own immediate superclass, and so on all the way up to
Object at the root; all of these are superclasses of the class. The keyword
extends denotes the immediate superclass.
When you define a class you can specify its superclass. If you don’t specify
a superclass, Object is assumed. Thus, the following are equivalent:
The “Outer Language” of Java ▪ 89
class Person { … }
class Person extends Object { … }
Classes inherit all the fields and all the methods of their superclasses.
Every class has not only its own fields and methods but also every field
and every method available to all of its superclasses. Hence, a class
may contain much more information than is obvious from the class
definition.
For example, if you have a Person class that has a name field, and you
write a Customer class that extends Person, then every Customer object
also has a name field. If your Person class has a visit method, then
every Customer object also has a visit method.
Smartly, objects of one type can be put into a variable of a different type
if and only if one of the types is an ancestor (superclass) of the other.
Upcasting is casting to an ancestor type, and can happen automatically;
downcasting is casting to a descendant type, and an explicit cast is
required. For example, if BirthdayCake extends Cake and Cake extends
Object, then the following assignments are possible:
myCake = (BirthdayCake)cake;
myCake = (BirthdayCake)obj;
cake = (Cake)obj;
The usual reason for upcasting is to put an object into a collection of more
general objects; for example, to put a birthday cake into an array of cakes.
The birthday cake does not lose its special features (candles, for example), but
those features are unavailable from a variable of the more general type Cake.
When downcasting an object, Java inserts an implicit check that the object
really is an object of the intended type, and throws a ClassCastException
if it is not. When the object is in a variable of the more specific type, the
added features (fields and methods) are again available.
You can test if an object is of a given type or supertype with the in
stanceof operator.
4.4 OVERRIDING
Objects inherit methods from their superclasses, and Object is the root
superclass of all objects, therefore every object inherits all the methods
defined in the Object class.
The “Outer Language” of Java ▪ 91
The inherited versions of these methods are fairly useless; they exist so
that they can be overridden. By defining them in Object, Java can be
sure that every object has some version of these methods.
@Override
public String toString() {
return "My count is " + count;
}
If any of these aspects do not match the inherited toString method, you
may have a valid method that overloads but doesn’t override the inherited
one. If the method is annotated with @Override, this kind of error will be
caught.
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (! (obj instanceof Counter)) return false;
Counter that = (Counter)obj;
return this.count == that.count;
}
The point to remember is that equal objects must have equal hash codes.
If you use only part of an object to test for equality, use those same parts
to create a hash code. This is absolutely necessary for classes like
HashMap to work correctly.
It is not, repeat not, the case that unequal objects must have different
hash codes. It’s better if they do, but relatively harmless if they don’t. If
you use a hash code of zero for every object, your code may run a
thousand times slower, but it will still work.
We have defined two Counter objects to be equal if they have the same
count value, so the hashCode method practically writes itself.
@Override
public int hashCode() {
return count;
}
If you have a Customer class with a name field, and if the name fields of
two customers have to match for them to be considered equal, you can
use the hash code of name for the hash code of your customer.
@Override
public int hashCode() {
return name.hashCode();
}
Advanced Java
Information is not hidden for any nefarious reason; it is done to limit the
amount of information a human has to deal with. Think of driving a car:
It would be much more difficult if you had to pay attention to the details
of timing, gear ratios, suspension, and so on. Instead, you are given easy
access to only the information you need to drive.
In the same way, each class and each method should provide services to
the code that uses them, while hiding the details of its operation.
DOI: 10.1201/9781003402947-5 97
98 ▪ Quick Java
The getter and setter methods for a weight variable might look like this:
Often these methods do nothing more than get or set the value with the
given Name, with the expectation that they may be extended later.
The use of getters and setters does incur a slight loss in performance.
However, they give you the freedom to revise and update the structure
of your objects without having to worry about what other classes may
be accessing the fields of those objects. It also gives you a lot more
flexibility. For example, your object could lie about its weight.
Similarly, the getter and setter could use pounds but actually store the
weight in kilograms.
While this may seem like a lot of additional typing for minor gains in
safety and flexibility, a professional IDE will create getters and setters for
you with a couple of menu clicks, and you can then edit them as needed.
You may have a class that contains only static methods and variables.
In that case, there is no reason ever to create an object of the class.
However, if you do not supply a constructor, Java automatically supplies
one for you. In this case, the solution is to supply a private
constructor—it doesn’t have to do anything, it just has to exist. Since you
have supplied a constructor, even though it’s one that nobody can use,
Java doesn’t supply a constructor, and no objects can be created.
Another situation is when you want only one unique object to be created.
In that case, a private constructor and a public method to call it may be a
good solution.
The same approach can be used if you want to check the parameters used
for a constructor before actually constructing an object.
• static variables
Advanced Java ▪ 101
• instance variables
• static methods
• instance methods
Within a block, however, variables are available only from the point of
declaration to the first closing brace.
{
x = 1; // not legal here
int x;
x = 2; // legal here
}
x = 3; // not legal here
The braces around a class or interface do not form a block, but the body
of a method is a block, so the above ordering rule applies.
5.2.1.2 Javadoc
Doc comments should be written for the benefit of the programmer who
needs to use your code. That programmer does not care how your code
works, only that it does work. Implementation details should be put in
internal comments; they do not belong here.
If your .java files are in a folder named (say) myProgram, then you can
simply execute javadoc myProgram from the command line. This will
produce several HTML pages which you can view in any browser.
A doc comment must begin with /**, end with */, and be placed directly
before a class, interface, field, constructor, or method declaration. It
consists of a textual description and some optional tags; which tags can
be used depends on the kind of thing being documented. If the
102 ▪ Quick Java
A doc comment for a field should describe the data held by the field.
Most fields should be private; javadoc can be set to include or to
ignore information about private fields and methods.
A doc comment for a constructor should tell how its parameters are
used.
A doc comment for a method should tell the user what the method does
and how to use it, not how it is implemented.
Doc comments may contain javadoc tags. Here are the most common
ones:
A good IDE can generate skeletal doc comments for you, so all you have
to do is fill in the details.
The doc comment for a method should begin with a verb phrase, for
example, “Finds the median value.” In other words, write the doc
comment as if it began with the words “This method … .”
Use the word this when referring to the current object, for example,
“Returns the numerator of this fraction.”
The @param and @return tags do not need to mention the type
of the parameters or of the return value, because javadoc will do
that.
Classes are organized into packages, with each public class on a separate
file. To provide documentation that describes the entire package, you can
write a file with the specific name package-info.java. This file typically
consists of a documentation comment plus one line identifying the
package and its location, like so:
documentation comment
package full.path.to.packageName;
104 ▪ Quick Java
This works because the type is obvious from the initial value.
The var declaration can also be used in the two kinds of for loop and in
the try-with-resources statement. It cannot be used for class or instance
variables (those declared within a class but not within a method).
5.2.1.4 Namespaces
Names are kept in namespaces, and the names in one namespace are
independent of the names in other namespaces. Thus, for example, a
variable may have the same name as a method without causing any
conflict. Java uses six different namespaces:
• package names
• type names
• field (variable) names
• method names
• local variable names (including parameters)
• labels
names are assigned to namespaces according to how they are used in the
code; for example, a method name is always followed by parentheses.
5.2.2 Data
5.2.2.1 Wrapper Classes
Primitive values in Java are not objects, so you can’t talk to them (send a
message to them) the way you would to an object. To make up for this
lack, each primitive type has a corresponding wrapper class. Those
classes are: Boolean, Byte, Character (not Char), Double, Float,
Integer (not Int), Long, and Short. The wrapper classes are in ja-
va.lang, which is automatically imported into every program.
Trap: If a and b are Integer (not int) values, the test a==b tests
whether a and b are equal for values less than 128, but tests for
identity (whether a and b are the same object) for larger values.
The equals method, a.equals(b), tests for equality in all cases.
Each wrapper class has some useful static constants and methods.
Since they are static, you use them by talking to the class, in many
cases providing the primitive as an argument to a method. For example,
there is a special double value named NaN (Not A Number), held in the
static constant Double.NaN. If you have a double variable d and you
want to know if it holds this value, you can ask Double.isNaN(d).
5.2.2.2 Integers
An int is a 32-bit integer that can hold numbers in the minus two billion
to plus two billion range. If you need or want the exact limits, they are
given by Integer.MIN_VALUE and Integer.MAX_VALUE.
Integers are usually written in decimal, using an optional sign and the
digits 0 to 9.
106 ▪ Quick Java
5.2.2.3 Doubles
A double is a 64-bit “real” (floating point) number, with an optional
exponent. As with integers, a double value may contain underscores, but
only between digits. The wrapper class for a double is Double.
Unfortunately, that left one bit free, and if that extra bit were set to 1 rather
than 0, another 128 characters could be added: dashes, “smart quotes,”
French characters, and so on. So every manufacturer did so, and did it
differently, with the result that, say, smart quotes on a Windows machine
came out as garbage characters on the Macintosh, and vice versa. You still
see the occasional garbage character today, from people who unknowingly
use some platform-specific encoding for non-ASCII characters.
When Java adopted Unicode, Unicode used two bytes, 16 bits, per char-
acter. The ASCII character set is a subset of Unicode—'A' is still 65, and
so on. This allowed for 65536 characters, which was enough until Chinese,
Japanese, Arabic, and a few other languages were added to the mix.
Besides the static methods in the Character class that do things like test
if a character is a digit, or test if a character is a letter in some language,
there are two of some interest:
5.2.2.5 Booleans
Booleans are simple. There are only two boolean values, true and false.
The static method Boolean.toString(boolean) will return one of the
two strings "true" or "false".
These additional primitive types exist for the purpose of saving storage
or, in the case of long, for dealing with very large integers.
Note: For integer values too large even for long variables, there
is a java.math.BigInteger class; see section 10.5 for an ex-
ample that uses this class.
A value of one type may not “fit” into a variable a narrower type; bits
could be lost. To ensure that the programmer really means to make this
assignment, Java requires an explicit cast. Casting does not prevent er-
rors, it just allows a questionable assignment. For example, the cast
(byte)250 is legal, and results in the value -6.
sh = sh + 1;
sh = (short)(sh + 1);
sh += 1;
5.2.2.7 Arrays
Arrays are objects, and they have a length field, but most of the methods
on arrays are just those inherited from Object. However, the class
java.util.Arrays provides a number of useful static methods.
Advanced Java ▪ 111
5.2.2.8 Strings
Strings are objects. There are about fifteen constructors for strings, but
the usual way to make a string is just to put some characters between
112 ▪ Quick Java
double quotes. Once this is done, you can send messages to the string in
the usual way.
For example, if s is a string, you can ask how many characters it has by
saying s.length(). You can get an uppercase version of it by asking
s.toUpperCase(). You can ask if it contains “Java” as a substring by
asking s.contains("Java"). And so on, and so on.
Strings have an equals method that you can and should use when
comparing strings. If s and t are strings, you can ask s.equals(t) and get
the results you expect. But there are two potential traps.
Strings are immutable, so if you write the same string in several places in
the program, it only needs to be stored once. Java works hard to intern
identical strings, making only one copy of that string.
Trap #2. Because strings are interned, the test s == t (which for
objects is a test of identity rather than equality) almost always
works. Sometimes Java’s interning strategy fails, and this test
will report false for equal strings. Therefore, don’t use == for
strings.
System.out.println("1234567");
String textBlock = """
First line
Middle line
Last line
""";
System.out.println(textBlock);
1234567
First line
Middle line
Last line
• The text block begins with three double quotes. These double
quotes must be the last things on that line.
• The lines keep their relative indentation. In this example, the first
and last lines are indented four spaces relative to the middle line.
• The indentation of the leftmost line (in this example, the middle
line), is determined by the position of the closing triple double
quotes.
• If the leftmost line in the text is indented more than the closing
quotes, it will be indented that much in the string. In this ex-
ample, the middle line starts two spaces over from the closing
quotes, so it will have two spaces in front of it.
• If the closing quotes are indented at least as much as the leftmost
line, or if they are on the same line as the last line of text, then
the leftmost line will not begin with spaces.
5.2.2.10 Formatter
Sometimes you want more control over printing than System.out.print
and System.out.println give you. For example, you might wish to print
114 ▪ Quick Java
In this code,
Here’s an example:
In the above example, "pi" is substituted for the %s and the value of
Math.PI for the %7.4f; the number occupies 7 character positions, 4 of
Advanced Java ▪ 115
them after the decimal point. The next statement does almost the same
thing for Math.E, but only leaves room for 6 characters.
A Formatter accumulates all the strings sent to its format method, and
has a toString method that can be used by print and println state-
ments. It should be closed when you are done with it.
If you want to format and print a single string, the printf method will
do that:
A format specifier has the following syntax (illegal spaces added for
clarity):
The optional index$ lets you choose which value (counting from 1, not
0) to put in this place. For example, the format code %2$s says to put the
second value in this place, as a string.
%b boolean
%c character
%d integer
%e scientific notation
%f floating point
%s string
%tc complete date and time
%n a newline on this platform
%% the character %
There is a great deal more to the Formatter class than this. In particular,
there are more than 30 conversions specified for dates and times.
You can use these methods without knowing the syntax of regular ex-
pressions. All you need to remember is that many punctuation marks
have special meanings in regular expressions, but letters, digits, and
spaces do not. So any regex composed only of letters, digits, and spaces
stands for itself.
To put a backslash into a string in Java, you need to double it: \\. Thus,
to insert the two characters "\d" into a Java string, you must type the
three characters "\\d". Other character classes can be handled similarly.
5.2.3 Collections
Java provides a large number of collection types, including sets, lists,
maps, stacks, queues, and deques. These types all implement the
java.util.Collection interface. This is a great help in learning to use
these types because it means they all have many of the same methods.
The above code declares items to be a Set, with all the Set operations, but
not any operations unique to HashSet. If at some later point another
implementation is desired, such as TreeSet, then the implementation may
be changed without any harm to the code that uses the items variable.
Here are some of the methods listed in the Collection interface, and
therefore available to all objects of the above types: add(object), addAll
(collection), remove(object), removeAll(collection), clear(), con-
tains(object), equals(object), size(), and toArray().
5.2.3.1 Iterators
An iterable object is any object that can be stepped through. All of Java’s
collection types are iterable objects. This includes various kinds of lists
and sets but does not include arrays.
while (iter.hasNext()) {
System.out.println(iter.next());
}
The method c.remove() will remove the last element returned by next
from the collection. Not all collection types allow this operation.
5.2.4.1 instanceof
The instanceof operator tests whether a given object can be cast to a
given type, but it’s up to the programmer to actually perform the cast:
For example:
larger = a > b ? a: b;
Advanced Java ▪ 121
or even
The valueIfTrue and valueIfFalse do not need to be the same type, but
either type must be legal in the context.
The shorter integer types are converted to 32-bit integers before the
above operations are performed, so the result is always an int value.
The decrement operator, --, subtracts one from a variable, and can also
be used as a prefix or postfix operator.
The prefix versions add or subtract one to the variable before using it in
an expression. The postfix versions add or subtract one to the variable
after using it in an expression. This can get very confusing; the statement
x = x++;
import java.util.*;
public Box() {
contents = new ArrayList<T>();
}
Now you can create a Box that can hold only a specific type of object, for
example, a String.
You can use a type variable, such as T above, almost anywhere you can
use the name of a type. But there are a few exceptions:
The above code defines box to be a box of strings, so if you call box.grab
(), you know you are going to get a string (or maybe null). But within
the Box class T could be any type of object, so you can only use the
methods and fields defined in the Object class. If you need more than
this, you can use bounded type parameters.
The syntax <T extends A> “bounds” the type of T. It specifies that type
T must be either class A itself, or a subclass of A, or a class that
implements interface A. For example, you might say <T extends
Comparable>, and this would allow you to use the compareTo method of
the Comparable interface on objects of type T.
Another legal syntax is <T extends A & B & C>, where A is the name of a
class or interface, and the additional names are names of interfaces.
Generics do not exist in the compiled code. If you declare and use a
variable of type Box<String> and another variable of type Box<Double>,
these will be compiled separately.
5.3.2 Interfaces II
An interface is a list of abstract methods—methods that have a header,
but no body. Any class that implements the interface must supply
complete methods, with the same header (parameter names may be
different) and a body.
and no other changes in the code are required (except possibly for what
you need to import).
In section 5.3.1 we defined a Box class with add and grab methods. We
might later decide to write an unrelated Shelf class that also has these
two methods, and then a Cabinet class, also with add and grab methods.
Each of these classes might store its contents in a completely different
way, possibly in a list or a two-dimensional array. The classes may also
have different data and additional, unique methods.
We can write a generic interface, which we’ll call Storage, to specify the
methods these classes must provide.
interface Storage<T> {
public void add(T thing); // no body
public T grab(); // no body
}
Now each of these classes can implement the new interface, with its own
versions of the add and grab methods.
What this gives us is the ability to write methods that take a Storage
parameter as an argument and use that parameter’s add and grab
methods. The interface name Storage can be used just as if it were the
name of a superclass.
This could go in the Box class, but what if we want to use it for other
Storage types? If we put it in the Box class, then it only works for Box
objects. We certainly don’t want to put identical copies of this method in
all the classes that can use it.
An abstract class is one that may contain abstract methods, each of which
must be marked with the keyword abstract. An abstract class is an
intermediate between a class (in which all methods are fully defined) and
an interface (in which no methods are fully defined).
With this change the Box, Shelf, and Cabinet classes no longer
implement the interface Storage, they extend the abstract class Storage.
Because abstract classes are “incomplete” (they are missing some method
implementations), you cannot create objects directly from such classes.
Abstract classes exist in order to be subclassed, and the subclasses can
provide the missing method definitions.
Starting with Java 16, a class may be sealed, which means that the class
definition specifies exactly which subclasses it has. (A class with no
subclasses cannot be sealed, but it can be final.)
Interfaces may also be sealed; the permits clause lists the classes that are
permitted to implement it. Interfaces may be implemented by classes and
records, or extended by other classes. Aside from replacing the word class
with the word interface, the syntax and requirements are the same.
class MemberClass {
int innerVariable = 20;
outer.run();
}
void run() {
MemberClass localInner = new MemberClass();
System.out.println(localInner.getSum(4));
}
}
When the main method runs, the results will be 123 and 124.
To refer to the static inner class from a class outside the containing class,
use the syntax OuterClassName.InnerClassName.
outer.run();
}
void run() {
StaticMemberClass localInner =
new StaticMemberClass();
System.out.println(localInner.getSum(5));
}
}
When the main method runs, the results will be 223 and 225.
class LocalClass {
int innerVariable = 40;
@Override
public String toString() {
return "I'm an instance of LocalClass";
}
}
When the main method runs, the results will be 12345 (printed from the
run method) and "I'm an instance of LocalClass" (printed from the
main method).
Here, SuperClass is not the name of the class being defined (that class
has no name), but rather the name of the class being extended. The
parameters are the parameters to a constructor for that superclass.
Inner classes are frequently used as event listeners. The example below
uses an anonymous inner class (ActionListener) as a button listener.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
Advanced Java ▪ 133
5.3.6 Enums
An enum (enumeration) is a kind of class. It has a superclass, Enum, from
which it inherits some methods. An enum has all the features of an
“ordinary” class (fields, constructors, methods, etc.), except that an enum
has a fixed, finite number of instances (objects) of the class, defined directly
within the class itself. In other words, when you define an enum, you also
define all its possible values, and you cannot later create additional values.
This example defines the type Weekday and seven instances (values) of
that type. Each of these is a unique constant. Because they are unique, it
is okay to compare them with == as well as with the equals method.
In the Weekday example, each of the instances (SUN, MON, etc.) has been
created by (implicitly) calling the default Weekday constructor. As with
any class, you can write your own constructors; however, (1) those
constructors will be private, and (2) you call them, not by saying new, but
by giving the instance name followed by a parameter list. For example,
In the above,
5.3.7 Records
A record is a kind of class, available in Java since version 14. The purpose
is to encapsulate a small amount of constant data in a full-featured class.
As an example,
For this declaration, the compiler will generate a complete class with:
You can replace the default constructor with your own, using the usual
syntax for constructors. Another option is to write a compact constructor.
public Range {
assert min <= max;
}
You can override any or all of the generated methods with your own, so
long as they have the same signature. You can also add fields, initializers,
and methods, but they must all be static.
5.3.8 Serialization
A serializable object is one that can be converted to a sequence of bytes,
usually so that it can be written to a file. To read it again, it has to be
deserialized. This allows objects to be stored on a file for future use.
To read in a serialized object, the exact same classes used by the object
must be present. Here’s the basic approach to reading in an object.
5.3.9 Modules
A package is a collection of related classes. A very large program,
however, may consist of hundreds of packages. To make a class in one
package available to a class in another package, it had to be made
public, which makes it available everywhere. This isn’t generally
desirable.
module moduleName {
directives
}
module giveModule {
exports com.xyz.giver;
exports com.xyz.secret to takeModule;
}
This specifies that the giver package can be used by anyone that requires
it, while only the takeModule module can require the package secret.
In this example, the directory containing the taker package also con-
tains this module-info.java file:
module takeModule {
requires transitive giveModule;
}
The optional word transitive implies that any module which requires
takeModule will also have access to giveModule.
All the Java-supplied packages have been organized into about 100 modules,
and every module declaration automatically requires java.base.
The java.base module consists of 32 packages, including java.lang,
java.util, java.io, and java.math.
However, all but the simplest programs consist of multiple classes, each
on a separate.java file. A file cannot be compiled successfully until all of
Advanced Java ▪ 139
A build tool takes as input a list of file dependencies, and compiles or re-
compiles only those files that need it. Ant, Maven, and Gradle are
popular build tools. If you are using an IDE, one or both of these tools
will be built-in for you, and you can let the IDE do the work.
CHAPTER 6
Functional
Programming
There are three factors that add to the complexity of functional pro-
gramming in Java. First, Java is designed around methods, which are
associated with classes; functions are a recent inclusion. Second, primi-
tives are treated differently from objects, which leads to a combinatorial
explosion of methods. Third, Java’s data structures are all mutable, which
is inconsistent with the general practice of functional programming.
or
The most common use of function literals is to pass them into methods as
arguments. However, a method must specify the type of each of its
parameters. In the case of a function literal, the type will always be the name
of some kind of functional interface, but that name isn’t obvious. Java
provides 43 types of functional interfaces, each with an associated SAM.
When we call this method with run(x -> x ∗ x, 12), it will print 144.
For a more interesting example, we will define a map method that applies
a function to each element of an integer array and returns an integer
array of the results.
import java.util.function.IntUnaryOperator;
import java.util.Arrays;
public class FunctionTest {
public static void main(String[] args) {
FunctionTest test = new FunctionTest();
int[] a = new int[] {1, 2, 3, 4, 5};
Mapper map = new Mapper();
int[] b = map.apply(a, x -> x ∗ x);
System.out.println(Arrays.toString(b));
}
}
@FunctionalInterface
interface ForEach {
int[] apply(int[] a, IntUnaryOperator f);
}
class Mapper implements ForEach {
public int[] apply(int[] a, IntUnaryOperator f) {
int[] b = new int[a.length];
for (int i = 0; i < a.length; i += 1) {
b[i] = f.applyAsInt(a[i]);
}
return b;
}
}
144 ▪ Quick Java
The main class creates an integer array a and a Mapper object map. It
then calls Mapper’s apply method, giving it the array a and the
function x -> x ∗ x as parameters. The result is the new array b, which
is then printed.
myButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
doSomething();
}});
Java are immutable. If in addition, the new data structure shares some or
all of the unmodified parts with the original data structure, it is said to be
persistent.
For example, if a persistent hash table contains 100 entries, and one of
them is changed, the new hash table may share the other 99 elements
with the original hash table; but each appears to the program to be a
separate, independent hash table.
Unit Testing
7.1 PHILOSOPHY
Testing is an essential part of programming. You can do ad hoc testing
(testing whatever occurs to you at the moment), or you can build a test
suite (a thorough set of tests that can be run at any time).
Deadlines are often used as an excuse for not doing thorough testing—
“There isn’t time!” This is a flawed argument, since thorough testing
reduces total programming time.
That said, programmers are human, and they will only do adequate
testing if (1) the tests are easy to write, and even more importantly, (2)
the tests are effortless to run. A good test framework such as JUnit makes
both of these things possible.
It is very difficult to write tests for methods that were not written with
testing in mind. To be testable:
Fortunately, rules for writing testable methods are also rules for a good
programming style.
After a method has been written and tested, additional errors may be
discovered. There is a specific technique for dealing with this situa-
tion. First, write a test that demonstrates the error; then fix it. This is
useful because, for whatever reason, some errors have a habit of
recurring.
You might, however, want to check that isPrime(15) is false, in case the
method somehow decides that all odd numbers are prime. It’s also worth
checking worth checking that isPrime(2) is true, in case the method
decides that all even numbers are non-prime. In fact, 2 is an edge case,
since it is the only even prime number.
Other edge cases are zero and negative numbers. Primality is not
defined for these numbers, and the programmer must decide what to
do in these cases (and preferably, test that that is what actually hap-
pens). If the decision is “that can’t happen anyway”, the appropriate
thing to do is to put the statement assert n > 0; at the beginning of
the isPrime method, and test that an inappropriate call throws an
exception.
7.3 JUnit
JUnit is a well-established test framework. To use it, here’s the general
approach:
1. Define a class to hold the tests, and import the test framework.
2. Include any number of test methods, annotated (preceded) by
@Test. Each test will call one or more assertion methods.
3. If any of the tests manipulate global variables, you should have a
method annotated with @BeforeEach to initialize them.
150 ▪ Quick Java
4. Execute the class. The class does not define a main method;
that is in the JUnit framework. When run, JUnit will produce a
report that either (1) says all tests passed or (2) tells which tests
failed.
If you have written the tests properly, they will not ask you for input or
otherwise interrupt the running of the tests.
import org.junit.jupiter.api.∗;
import static org.junit.jupiter.api.Assertions.∗;
import static org.junit.jupiter.api.Assumptions.∗;
The first import statement makes the annotations available, the second
makes the test methods (such as assertEquals) available, and the third
makes assumptions (described later) available.
Next, write the methods that will be used by JUnit. Each method should
be public void, should take no parameters, and should have one of the
following annotations:
• @AfterEach annotates a method that will run after each test. This is
rarely used.
• @AfterAll marks a static method that executes after all tests
have been run. Its purpose is to close any resources opened by @
BeforeAll.
• @DisplayName(string) can be put before the test class or in front of
individual tests, to use string in place of the class name or test
method name when reporting results.
The test methods (those annotated with @Test) are ordinary code but
contain one or more assertions. The assertions available for use in the
@Test methods include:
All of these tests except fail may take an optional last argument
message.
152 ▪ Quick Java
Note: The fail method (which, yes, causes the test to fail) is
useful for writing tests that use more complex logic.
If you have a class containing a number of methods, most good IDEs will
write a skeletal test class for you, so that you only have to add the
assertions.
A test class may also contain unannotated methods. These are ignored by
JUnit but may be used by the test methods.
There are two ways to solve this problem. The more convenient way, in
modern Java, is for the second argument to assertThrows to be a
function that calls the method. Like so:
assertThrows(ArithmeticException.class,
() -> divide(0, 0));
Unit Testing ▪ 153
If you do not have functions available, the same test can be written as
follows:
try {
divide(0, 0);
Assertions.fail();
}
catch (ArithmeticException e) { }
7.6 ASSUMPTIONS
In addition to assertions, JUnit 5 provides three kinds of assumptions.
• assumeTrue(booleanExpression)
• assumeFalse(booleanExpression)
If the test is not met, the test method returns without executing the
remainder of the method, and the test is considered “not applicable”
rather than either succeeding or failing.
• assumingThat(booleanExpression, function)
Example: assumeTrue(System.getProperty("os.name")
.equals("Mac OS X"));
tested here.) The code for the Account class is not repeated here, but it
can be easily inferred by looking at the test cases.
package account;
import org.junit.jupiter.api.∗;
import static org.junit.jupiter.api.Assertions.∗;
public class AccountTest {
Account account; // must be global
@BeforeEach
public void setup() {
this.account = new Account(); // global
}
@Test
public void openAnAccount() {
assertEquals(0, account.getBalance());
}
@Test
public void testDeposit() {
account.deposit(100);
assertEquals(100, account.getBalance());
account.deposit(70);
assertEquals(170, account.getBalance());;
}
@Test
public void testIllegalDeposit() {
account.deposit(-10000);
assertEquals(0, account.getBalance());
}
@Test
public void goodWithdrawal() throws Exception {
account.deposit(100);
account.withdraw(35);
assertEquals(65, account.getBalance());
}
@Test
@DisplayName("Exception test, old style")
public void badWithdrawal() {
try {
Unit Testing ▪ 155
account.withdraw(35);
fail("Did not throw exception");
}
catch (Exception e) { }
}
@Test
@DisplayName("Exception test, new style")
public void badWithdrawal2() {
assertThrows(Exception.class,
() -> account.withdraw(35));
}
}
8.2 DIALOGS
A dialog is used to get a simple response from the user. Dialogs can be
used without having to create a full-fledged GUI. To determine the
location of the dialog on the screen, a parent component must be
specified; if it is null, the dialog will be centered on the screen.
All provided dialogs are modal, that is, the user must respond to them
before anything else can be done in the application. Custom dialogs may
be modal or nonmetal.
JOptionPane.showMessageDialog(parent,
"This is a message dialog.");
String userName =
JOptionPane.showInputDialog(
parent, "What is your name?");
See section 3.3.3 for more ways to read from a file. Close the FileReader
and BufferedReader when you are done.
pr.println("Test line");
pr.close();
closeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
myDialog.setVisible(false);
}
});
myDialog.pack();
myDialog.setVisible(true);
CHAPTER 9
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
public class MyGUI extends JFrame implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new MyGUI());
}
public void run() {
// add components to this JFrame
pack();
setVisible(true);
}
}
The name MyGUI can be changed, but run is a method required by the
Runnable interface.
Most listeners also come from the AWT, so you also need to import
java.awt.event.*.
You can create a JFrame in the class that contains the public static
void main method, but it’s often more convenient to have this class
extend JFrame.
A JPanel is both a container (it can have components added to it) and a
component (it can be added to containers). Each JPanel has its own
layout manager. All but the simplest windows consist of a JFrame
containing several JPanels, with each JPanel containing one or more
widgets (visible GUI components).
166 ▪ Quick Java
To create a JPanel:
JPanel panel = new JPanel(); // default: flow layout
JPanel panel = new JPanel(layoutManager);
Since there are only a few more kinds of layout managers, they are listed here:
A tooltip is a small text message that pops up when the user hovers over
a component, usually to give a little more information about the purpose
of the component. Tooltips can be added to almost any component.
widget.setToolTipText("Purpose of widget");
You can also write listeners for mouse clicks, mouse movement, and key
presses, but you don’t need to unless you are doing something unusual.
When using the widget causes an event to occur, my sample code calls a
handleEvent method (not provided) that I wrote for testing purposes.
This should be replaced with your code for handling the event.
The last step is usually to cause the JFrame to be sized, laid out, and
made visible:
pack();
setVisible(true);
9.8.2 JEditorPane
An editor pane is a special kind of container that supports editing plain
text (text/plain) or hypertext (text/html). It implements the key
board shortcuts for cut, copy, and paste, but not undo/redo.
9.8.3 JScrollPane
A scroll pane can be used to hold any large component that you might
want to scroll (in this example, a previously defined JEditorPane named
editor).
9.8.4 JTabbedPane
A tabbed pane (Figure 9.5) is a container that has tabs like a typical
browser window, where clicking each tab reveals different components.
It can be used in place of CardLayout.
To add the tabs, each holding some (previously defined) panel, with
optional text, icon, and tooltip.
tabbedPane.addTab("Smile", smiley,
panel0, "Tooltip 0");
tabbedPane.addTab("Tab 1", null,
panel1, "Tooltip 1");
tabbedPane.addTab(null, frowny,
panel2, null);
or
tabbedPane.setSelectedComponent(panel);
9.8.5 JButton
A button is typically shown as a rectangle with rounded corners, con
taining text. Buttons should always be treated as active widgets.
In this and the following examples, the action being taken is a call to the
method handleEvent(string). That method call is just a placeholder; it
should be replaced with your own code.
9.8.6 JTextField
A text field is a rectangle into which a single line of text can be entered. A
text field can hold an arbitrary number of characters, although the
rectangle may be too small to display them all.
9.8.7 JTextArea
A text area is a rectangle into which multiple lines of text can be entered.
A text area can hold an arbitrary amount of text, although the rectangle
176 ▪ Quick Java
may be too small to display all of it. Scroll bars are not automatically
added to a JTextArea.
To provide the listener (as an inner class) for the JTextArea’s Document:
public class MyJTextAreaListener
implements DocumentListener {
public void insertUpdate(
DocumentEvent arg0) {
handleEvent("JTextArea");
}
public void removeUpdate(
DocumentEvent arg0) {
handleEvent("JTextArea");
}
How to Build a GUI Program ▪ 177
9.8.8 JCheckBox
A checkbox is a small square box with an associated label. The box is either
checked (has a checkmark in it) or is empty. Each checkbox represents a
single yes-no choice and is independent of any other checkboxes.
someJPanel.add(myJCheckBox);
myJCheckBox.addItemListener(event ->
handleEvent("JCheckBox"));
9.8.9 JRadioButton
A radio button is a small open circle with an associated label. The circle
is either selected (filled in) or is empty. Radio buttons are used to select
178 ▪ Quick Java
If the program does not specify one particular radio button to be initially
selected, then when the program runs, none are selected. Once a selec
tion has been made, it is normally impossible to return to a state where
none are selected.
myButtonGroup.add(myJRadioButton1);
myButtonGroup.add(myJRadioButton2);
myJRadioButton1.setSelected(true);
myJRadioButton1.addItemListener(event ->
handleEvent("JRadioButton1"));
myJRadioButton2.addItemListener(event ->
handleEvent("JRadioButton2"));
It’s usually better to treat radio buttons as passive widgets and use
isSelected() when the selected value is needed.
9.8.10 JLabel
Checkboxes and radio buttons have associated labels, but other widgets
do not. You can add labels to things, but those labels are normally
completely inactive; their only purpose is to provide guidance to the
user.
labelPanel.add(myJLabel);
There is no specific listener for a JLabel. In the unlikely event that you
need to listen for mouse clicks on a JLabel, you can add a mouse listener
to either the JLabel itself, or to the JPanel that contains the JLabel.
Like so:
labelPanel.addMouseListener(
new MouseAdapter() {
@Override
public void mouseClicked(
MouseEvent e) {
handleEvent("JLabel");
}
});
180 ▪ Quick Java
9.8.11 JComboBox
To declare and define a JComboBox:
someJPanel.add(myJComboBox);
myJComboBox.addActionListener(event -> {
String selection =
(String) myJComboBox.getSelectedItem();
handleEvent(selection);
});
9.8.12 JSlider
A slider (Figure 9.6) is a scale that can be manipulated by either the user
or the program.
someJPanel.add(myJSlider);
How to Build a GUI Program ▪ 181
myJSlider.setMajorTickSpacing(10);
myJSlider.setMinorTickSpacing(2);
myJSlider.setPaintTicks(true);
myJSlider.setPaintLabels(true);
myJSlider.setValue(45);
myJSlider.addChangeListener(event ->
handleEvent("JSlider"));
9.8.13 JSpinner
A spinner (Figure 9.7) selects a number from a given range of numbers.
someJPanel.add(myJSpinner);
182 ▪ Quick Java
myJSpinner.setValue(20);
myJSpinner.addChangeListener(event ->
handleEvent("JSpinner"));
9.8.14 JProgressBar
A progress bar is a long, thin rectangle that is gradually “filled in” as an
operation progresses. When properly set up, it should finish filling at the
same time as the operation ends.
JProgressBar myProgressBar =
new JProgressBar(min, max);
or
JProgressBar myProgressBar =
new JProgressBar(); // 0 to 100
myProgressBar.setStringPainted(true);
someJPanel.add(myProgressBar);
How to Build a GUI Program ▪ 183
myProgressBar.setValue(20);
9.8.15 Menus
The menu bar of an application holds menus, and each menu holds
menu items (see Figure 9.8).
myJMenuBar.add(myJMenu);
myJMenu.add(myJMenuItem);
To add the JMenuBar (with the JMenu and JMenuItem) to the window:
this.setJMenuBar(myJMenuBar);
myJMenuItem.addActionListener(event ->
handleEvent("JMenuItem"));
have to do anything. For other uses, you may wish to add a KeyListener
to a Container of your choice.
Notes:
9.9 DICEROLLER
Here is a complete (but very small) Swing application:
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
void createAndShowGUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
How to Build a GUI Program ▪ 187
Every one of these classes is far richer than this section would suggest.
Only the basics are described here.
10.1 THREADS
A thread is the flow of control in a program. Modern operating systems
are multiprocessing: they do many things at the same time. This might
be accomplished by assigning different threads to different cores, or by
interrupting one thread to turn over execution to another. Even a simple
Java program uses multiple threads and hides the details so you don’t
have to think about them. You can, however, directly create and
manipulate threads.
There are two ways to create another Thread and start it running:
• Write a class that extends Thread and overrides the public void
run() method.
• Create an object of this class.
• Send the object the (inherited) start() message.
• Write a class that implements Runnable and overrides the public
void run() method.
• Create an object obj of this class.
• Create a new Thread(obj).
• Send the Thread the start() message.
Thread.sleep(milliseconds);
try {Thread.sleep(1000);}
catch (InterruptedException e) { }
Threads and Animation ▪ 191
10.2 SYNCHRONIZATION
There are many cases when it is desirable to have many processes
(threads) running in parallel. For example, other work could be done
while a slow database access or file transfer is in process.
10.3 TIMERS
A javax.swing.Timer is used to schedule code for repeated execution.
The constructor takes two parameters: an int time in milliseconds,
which is used to set both the initial delay and the time between events;
and an ActionListener (usually an anonymous inner class) to do
something at each “tick” of the Timer.
It isn’t necessary for a class to have all the bean characteristics in order to
use the above classes and methods.
10.5 SwingWorker
A worker thread provides a means of running a long-running process on
a background thread so that the main thread can continue to do work.
This is particularly important in a GUI (graphical user interface) pro
gram, where a long-running process can make the GUI unresponsive.
194 ▪ Quick Java
To keep the example short, we will not use a GUI. The long-running
process typically is some file or database manipulation, but for our ex
ample, we will try to find one factor of a big integer.
import java.math.BigInteger;
import javax.swing.SwingWorker;
@Override
public BigInteger doInBackground() {
return findFactor(big);
}
if (big.mod(divisor).equals(BigInteger.ZERO)) {
return divisor;
}
divisor = divisor.add(BigInteger.TWO);
}
return BigInteger.ZERO;
}
}
The class has a constructor which accepts and stores the data it is to
use—in this case, a BigInteger to try to factor. It has one necessary
method, T doInBackground().
import java.math.BigInteger;
public class FactorFinder {
public static void main(String[] args) {
new FactorFinder(args[0]);
}
twiddleThumbs();
}
try { factor = worker.get(); }
catch (Exception e) { }
The main method gets a number, as a String, from the command line
(or from a setting in the IDE). It makes a BigInteger from the string,
creates a Worker object with this BigInteger, and tells the Worker
object to execute().
Note: A good number to try is "41758540882408627201."
Eventually, the get() method returns a result. If called before the worker
thread is finished, the current thread stops and waits for it to finish; this
isn’t what is generally desired. The get() method could throw an
InterruptedException or an ExecutionException, so get() is put in
a try-catch statement to handle these.
The model is treated as a “bean” (although it does not have all the
characteristics of a bean), and PropertyChangeEvents are used to keep
the model as independent as possible from the rest of the code.
In the following we mention only the main points of the Bouncing Ball
program; the complete code is in an appendix.
198 ▪ Quick Java
10.6.1 MVC
MVC, or Model-View-Controller is a useful design pattern when one
thread is used to control another thread, such as when doing animation.
The model is the code doing the actual work of the simulation, anima
tion, or whatever. It should be free of any input/output, and completely
independent of both the view and the controller. If there is a GUI, it
should be completely unknown to the model.
10.6.2 Controller
The controller’s main job is to set up the GUI, so it extends JFrame and
adds Run and Stop buttons. It creates the model and the view. Since the
view has to know about the model, but the model doesn’t have to know
about the view, the model is created first.
Since the ball is to bounce off the edges of the window, it has to know
where those are. The top and left edges are at 0; the right edge is the width
of the window, and the bottom edge is the height of the window. If the
window is resized, the new values must be fetched and sent to the model.
this.addComponentListener(new ComponentAdapter() {
@Override
Threads and Animation ▪ 199
10.6.3 Model
The model has four basic variables: the x and y position of the ball, and the
amount that each of these changes from one frame (still picture) to the next.
For convenience in drawing the ball, the x and y coordinates are given as the
top left corner of a square enclosing the ball. For convenience in creating a
single object for the viewer to see, the x and y are enclosed in a Point object.
At each step, the x position is advanced by dx, and the y position by dy.
A “bounce” occurs when the ball goes too far to the left or too far to the
right, and this is accomplished by changing the sign of dx.
position.x += dx;
if (position.x < 0 || position.x >= xLimit) {
dx = -dx;
position.x += dx;
}
To make the new position available to other classes, the model has a
PropertyChangeSupport object (named pcs). This is public so that it
can be accessed by the view class.
Each time the model completes a step, it tells pcs to fire off an event
containing the new value of the ball’s position.
this.pcs.firePropertyChange("position", null,
position);
10.6.4 View
The task of the view class is simply to clear the window and draw a ball in it
each time it receives a PropertyChangeEvent. This means it has to “listen”
for those events. To do this, it implements PropertyChangeListener.
@Override
public void propertyChange(
PropertyChangeEvent event) {
position = (Point) event.getNewValue();
repaint();
}
But this isn’t enough; one more step is required: The View class is now a
listener, but the same PropertyChangeSupport object used earlier must
be told about it.
model.pcs.addPropertyChangeListener(this);
You can think of the View as “subscribing” to the series of events sent out
by pcs.
Appendix A:
Code for BouncingBall
/**
* This is an example of the basic "Bouncing
* Ball" animation, making use of the Model-
* View-Controller design pattern and the
* Timer and PropertyChangeSupport classes.
*/
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Timer;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* The Controller sets up the GUI and handles
* the controls (in this case, buttons).
* @author David Matuszek
*/
201
202 ▪ Appendix A: Code for BouncingBall
/**
* The Model is the object that does all
* the computations. It is independent
* of the Controller and View objects.
*/
Model model;
/**
* The View object displays what is
* happening in the Model.
*/
View view;
/**
* Runs the bouncing ball program.
* @param args Ignored.
*/
public static void main(String[] args) {
Controller c = new Controller();
c.init();
c.display();
}
/**
* Sets up communication between the
* Model and the View.
*/
private void init() {
model = new Model();
view = new View(model);
}
/**
* Displays the GUI.
*/
private void display() {
layOutComponents();
Appendix A: Code for BouncingBall ▪ 203
attachListenersToComponents();
setSize(300, 300);
setVisible(true);
setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
}
/**
* Arranges the components in the GUI.
*/
private void layOutComponents() {
setLayout(new BorderLayout());
this.add(BorderLayout.SOUTH, buttonPanel);
buttonPanel.add(runButton);
buttonPanel.add(stopButton);
stopButton.setEnabled(false);
this.add(BorderLayout.CENTER, view);
}
/**
* Attaches listeners to the components
* and schedules a Timer.
*/
private void attachListenersToComponents() {
// The Run button starts the Model
runButton.addActionListener( event -> {
runButton.setEnabled(false);
stopButton.setEnabled(true);
model.start();
});
// The Stop button pauses the Model
stopButton.addActionListener(event -> {
runButton.setEnabled(true);
stopButton.setEnabled(false);
model.pause();
});
// When the window is resized,
// the Model is given the new limits
this.addComponentListener(
new ComponentAdapter() {
@Override
public void componentResized(
ComponentEvent arg0) {
204 ▪ Appendix A: Code for BouncingBall
model.setLimits(view.getWidth(),
view.getHeight());
}
});
}
}
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Point;
import javax.swing.Timer;
import java.beans.*;
/**
* This is the Model class for a bouncing ball.
* It defines a PropertyChangeSupport object.
* @author David Matuszek
*/
public class Model {
private Point position = new Point(0, 0);
private int xLimit, yLimit;
private int dx = 6;
private int dy = 4;
private Timer timer;
public PropertyChangeSupport pcs;
public Model() {
pcs = new PropertyChangeSupport(this);
position = new Point(0, 0);
timer = new Timer(
40, new ActionListener() {
@Override
public void actionPerformed(
ActionEvent e) {
makeOneStep();
}
});
timer.stop();
}
Appendix A: Code for BouncingBall ▪ 205
/**
* Sets the "walls" that the ball should
* bounce off from.
* @param xLimit The right wall (in pixels).
* @param yLimit The floor (in pixels).
*/
public void setLimits(int xLimit,
int yLimit) {
this.xLimit = xLimit - 20;
this.yLimit = yLimit - 20;
position =
new Point(Math.min(position.x, xLimit),
Math.min(position.y, yLimit));
}
/**
* @return The balls X position.
*/
public Point getPosition() {
return position;
}
/**
* Tells the ball to start moving. This is
* done by starting a Timer that periodically
* tells the ball to make one "step."
*/
public void start() {
timer.start();
}
/**
* Tells the ball to stop where it is.
*/
public void pause() {
timer.stop();
}
/**
* Tells the ball to advance one step
* in the direction that it is moving.
* If it hits a wall, its direction
* of movement changes. The method
206 ▪ Appendix A: Code for BouncingBall
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.beans.*;
import javax.swing.JPanel;
/**
* The View displays what is going on in
* the Model. In this example, the Model
* is only a single bouncing ball.
* @author David Matuszek
*/
public class View extends JPanel
implements PropertyChangeListener {
Point position = new Point(0, 0);
/** This is what we will be viewing. */
Model model;
Appendix A: Code for BouncingBall ▪ 207
/**
* Constructor. Adds a listener for
* PropertyChange events.
* @param model The Model whose working
* is to be displayed.
*/
View(Model model) {
this.model = model;
model.pcs.addPropertyChangeListener(this);
}
/**
* Displays what is going on in the Model.
* Note: This method should NEVER be
* called directly; call repaint() instead.
* @param g The Graphics on which to paint.
* @see javax.swing.JComponent#paint(
* java.awt.Graphics)
*/
@Override
public void paint(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.RED);
position = model.getPosition();
g.fillOval(position.x, position.y, 20, 20);
}
/**
* Repaints the JPanel when a
* PropertyChangeEvents is received.
* @param evt Contains the ball's position.
*/
@Override
public void propertyChange(
PropertyChangeEvent evt) {
position = (Point) evt.getNewValue();
repaint();
}
}
Index
Note to editor: To help you distinguish the computer font (Inconsolata) from the text
font, I have made the computer font larger and blue. Notice in particular that all the
symbols in the first group (from ! to ~) should be in the computer font. For the edited
index, the color should be removed and the same font size used throughout.
Note: Page numbers in bold indicate defined terms.
! (not), 6 arguments, 29
& (bitwise and), 121 arithmetic operators, 5
&& (and), 6 ArithmeticException, 23
++ (add 1), 121 array, 19
−− (subtract 1), 121 ArrayList class, 118
:: (method reference operator), 142 Arrays class, 110
<< (left shift)@, 121 ASCII, 107
>> (right shift with sign fill), 121 assert statement, 32, 47
>>> (right shift with zero fill), 121 assertion methods, 149
^ (exclusive or), 121 assignment statement, 8, 35
| (bitwise or), 121 assumptions, 153
|| (or), 6 AWT (Abstract Window Toolkit), 157
~ (bitwise not), 121
backslashes, doubling, 117
abstract classes, 126 bank account example, 77
abstract method, 124 bean, 193
access specifier, 27 BigInteger, 110
AccountTest example, 153 BirthdayCake class, 89
active widget, 168 bit operators, 121
ad hoc testing, 147 block, 8, 31, 34
annotation, 91 BlueJ, 14
annotations in JUnit, 150 body, of a method, 31
anonymous inner classes, 132 boolean, 19
Ant, 139 boolean values, 109
API (Application Programmer BorderLayout, 166
Interface), 64 Bouncing Ball example, 197
applyAsInt, 143 bounded type parameter, 124
209
210 ▪ Index