Professional Documents
Culture Documents
Java Tutorial
Java Tutorial
Computer programs are read by both computes and humans. You write Java instructions to
tell the computer what to do. You must also write comments to explain to humans what the
program does. Of course, Java can't understand them because they are written in English, or
Spanish, or Thai, or ... .
Java ignores all comments. There is, however, a program called javadoc which reads certain
kinds of comments and produces HTML documentation (see below).
One of the most effective ways to make a program readable is to put spaces in at key points. There
are several styles for doing this. Even more important is to put blank lines in your program. These
should separate sections of code. There should be a blank line between each "paragraph" of code.
By paragraph, I mean a group of statements that belong together logically; there is no Java concept
of paragraph.
Java comments
// comments -- one line
After the two // characters, Java ignores everything to the end of the line. This is the most
common type of comment.
//--- local variables ---
int nquest; // number of questions.
int score; // count of number correct minus number
wrong.
Best Practices
• Don't write comments to document obvious statements. Assume the reader knows Java.
• Every comment has the potential to create an inconsistency between what the comment
says, and what the code does. One cause of "software rot" is that code is changed over
time, but comments are not updated. To avoid this, keep comments next to the code that is
documented so that they may be more easily synchonized.
Interesting comments
Identifier Names
Getting the names of things right is extremely important. It makes a huge difference in readability.
Many IDEs support refactoring, and specifically renaming. I will sometimes rename classes several
times before I hit on exactly the obvious name. It's worth the effort.
Legal Characters
Every name is made from the following characters, starting with a letter:
• Letters: a-z, A-Z, and other alphabetic characters from other languages.
• Digits: 0-9
• Special: _ (underscore)
No names can be the same as a Java keyword (eg, import, if, ...).
Examples
apple This is a legal name. Lowercase implies it's a variable or method.
This is a different legal name. Uppercase implies it's a class or
Apple
interface.
APPLE Yet a different legal name. All uppercase implies it's a constant.
topleft Legal, but multiple words should be camelcase.
top_left Better, but camelcase is preferred to _ in Java.
topLeft Good Java style
top left ILLEGAL - no blanks in a name
import ILLEGAL - same as the Java keyword
The conventions for the use of upper- and lowercase is not enforced by compilers, but it is so widely
observed, that it should have been. Camelcase is the practice of capitalizing the first letter of
successive words in multi-word identifiers. Camelcase is much preferred in the Java community over
the use of underscores to separate words, or even worse, no distinction made at word boundaries.
Java doesn't care if your names are readable, but it's really important to make your names readable
to humans.
I once worked on a project where we had to distribute the source code so that it could be compiled
on another machine, but we didn't want to reveal our algorithms. We deleted all comments and
indentation, and wrote a small program to change all variable names to combinations of "I", "1",
"O", and "0", figuring that it would be too much effort for them to decode it. For example, the semi-
readable
LogicalGapInfo topBorder =
m_logicalLayout.getGapInfo(LogicalLayout.AXIS_V, 0);
Could be translated into
I001O I00I0 = O1001.OI001(O1OOI.IO010, 0);
Package declaration
The first statement, other than comments, in a Java source file, must be the package declaration.
Following the optional package declaration, you can have import statements, which allow you to
specify classes from other packages that can be referenced without qualifying them with their
package.
Default package. Altho all Java classes are in a directory, it's possible to omit the package
declaration. For small programs it's common to omit it, in which case Java creates what it calls a
default package. Sun recommends that you do not use default packages.
2. Imports (optional).
package illustration;
import java.awt.*;
public class Drawing {
. . .
}
The JOptionPane class is in the swing package, which is located in the javax package. The wildcard
character (*) is used to specify that all classes with that package are available to your program.
This is the most common programming style.
class ImportTest {
public static void main(String[] args) {
JOptionPane.showMessageDialog(null, "Hi");
System.exit(0);
}
}
Classes can be specified explicitly on import instead of using the wildcard character.
class ImportTest {
public static void main(String[] args) {
JOptionPane.showMessageDialog(null, "Hi");
System.exit(0);
}
}
class ImportTest {
public static void main(String[] args) {
javax.swing.JOptionPane.showMessageDialog(null, "Hi");
System.exit(0);
}
}
Common imports
There are 166 packages containing 3279 classes and interfaces in Java 5. However, only a few
packages are used in most programming. GUI programs typically use at least the first three
imports.
import FAQ
1. Q: Does importing all classes in a package make my object file (.class or .jar)
larger?
A: No, import only tells the compiler where to look for symbols.
2. Q: Is it less efficient to import all classes than only the classes I need?
A: No. The search for names is very efficient so there is no effective difference.
A: The wildcard "*" only makes the classes in this package visible, not any of the
subpackages.
• The project name is used as the default package name, but you can change it.
• A directory / folder is created with this project name. This directory name is the name of
your package.
• A package declaration is automatically inserted into each new source file it creates.
• When you build a main project, the double-clickable .jar file uses this
project/package/directory name.
Java 5 added an import static option that allows static variables (typically constants) to be
referenced without qualifying them with a class name. For example, after
import static java.awt.Color;
It would then be possible to write
Color background = RED;
instead of
Color background = Color.RED;
Adding this "feature" wasn't the best idea because it leads to name pollution and confusion about
which class constants come from. Even Sun (see References below) basically advises not to use it!
Notice how using final is an entirely negative act. The final keyword works by
subtracting, limiting default language mechanisms: the ability to override a method, to set
a variable or a field. The motivations behind using final fall into three broad categories:
correctness, robustness, and finally performance.
Final Variables
A final variable can be set only once, allowing you to declare local constants. Such a
variable can be left un-assigned at the point of declaration, creating blank finals. But all
final variables must be assigned exactly once. Final variables come in handy in mostly
two situations: to prevent accidental changes to method parameters, and with variables
accessed by anonymous classes.
Final Parameters
The following sample declares final parameters:
public void doSomething(final int i, final int j)
{
// ...
}
final is used here to ensure the two indexes i and j won't accidentally be reset by the
method. It's a handy way to protect against an insidious bug that erroneously changes the
value of your parameters. Generally speaking, short methods are a better way to protect
from this class of errors, but final parameters can be a useful addition to your coding
style.
Note that final parameters are not considered part of the method signature, and are
ignored by the compiler when resolving method calls. Parameters can be declared final
(or not) with no influence on how the method is overriden.
The reason for this restriction becomes apparent if we shed some light on how local
classes are implemented. An anonymous local class can use local variables because the
compiler automatically gives the class a private instance field to hold a copy of each local
variable the class uses. The compiler also adds hidden parameters to each constructor to
initialize these automatically created private fields. Thus, a local class does not actually
access local variables, but merely its own private copies of them. The only way this can
work correctly is if the local variables are declared final, so that they are guaranteed not
to change. With this guarantee in place, the local class is assured that its internal copies of
the variables accurately reflect the actual local variables.
Final Fields
A final field can be assigned once and only once, and must be initialized by every
constructor of the class that declares it. It is also possible to assign the field directly, in
the same statement where it is defined. This simply reflects the fact that such shortcut
assignments are compiled into a synthetic constructor. E.g. both the following code
samples are correct and strictly equivalent; the first is preferred for being shorter.
public class MyClass
{
private final int i = 2;
}
public MyClass()
{
i = 2;
}
}
Declare Constants
Coupled with static, final is used to flag constants. This usage is well-known to all
Java programmers, so I won't expand much on it. It is useful to know that the value of a
field declared constant in that manner will be computed statically if possible, at compile-
time.
private static final int ERROR_CODE = 1 + 3 * 4 / 2;
public static final String ERROR_MESSAGE = "An error occurred with
code=" + ERROR_CODE;
The compiler will compute the value for ERROR_CODE, concatenate the string equivalent
of the result, and assign the resulting String to ERROR_MESSAGE.
public Car()
{
engine = new Engine();
}
}
Simply by tagging a field with final, we have just created a very strong condition on all
Car instances: namely, they must have an Engine to exist. This simple property can
dramatically raise the quality of your code, by enforcing correct aggregation relationships
between objects. The object thus defined, and all its aggregated dependents, always exists
in a stable state.
Declare Invariants
Design by Contract is an effective programming methodology for designing robust
software components: by declaring (and verifying) conditions specific to a given
component, its behavior can be asserted correct, even at runtime. final is a great tool to
enforce field invariance: since final fields can only be set once, any attempt to reset their
value (accidental or not) is detected by the compiler. This idiom is also of great help
during refactoring: it catches refactoring mistakes by acting as a safeguard against the re-
initialization of a field.
A caveat applies here: if a final variable holds a reference to an object, the object may be
modified, in spite of it being final. This is because final only applies to the reference
holding the object, not the object itself. The final variable will always refer to the same
object, but the object itself may change through its methods.
This applies also to arrays and collections, because they are both objects. If a final
variable holds a reference to an array, then the components of the array may be changed
by operations on the array, although the variable will always refer to the same array. The
same restriction applies to collections as well. E.g. a list may be declared final and thus
always exist as far as the aggregating object is concerned, its content is undetermined,
and can be changed at will. Elements can be added/removed from the collection, even
though it is declared final.
For Performance
The revised memory model proposed by JSR 133 includes special provisions for final
fields, provisions that are absent from the existing specification. Newer VMs already
implement this specification, and treat final fields accordingly. Because final fields are
assigned exactly once, aggressive optimizations in a multithreaded context become
possible. Specifically, a field doesn't need to be ever reloaded, since its value is
guaranteed never to change.
// ...
}
}
public class BetterCar
{
private final Engine engine = new Engine(); // using final
Final Methods
A final method is implemented exactly once, in the declaring class. Such a method cannot
be overridden: subclasses cannot substitute a new definition for the method. Note that
either modifier private or static also implies final, which is therefore redundant,
when applied to methods. Private and static methods are always implicitely final, since
they cannot be overridden.
Be aware that final methods impose a very strict restriction on subclass implementors. In
a framework context, think long and hard before declaring methods final, as it will
severely limit the extensibility of the framework, and the possibilities of adapting the
framework to situations unforeseen by the original developers.
For Security
In Java all methods are by default overridable. While this gives maximum flexibility to us
programmers, this liberal attitude can sometimes lead to conflicting situations. Let's look
at the Object class for example. It declares methods that certainly must be overridable:
Object.equals and Object.toString are two well-known examples. But Object also
includes methods such as Object.wait and Object.notify – system-level methods
which implement core language capabilities. It simply cannot be allowed for
Object.wait to be substituted by a different implementation. It would alter the
semantics of the language itself.
Final methods come to the rescue again in this case: Object.wait is declared final, and
therefore it cannot be changed, accidentally or not. This reasoning also applies to entire
JDK classes, as discussed below.
For Performance?
Since a final method is only implemented in the declaring class, there is no need to
dynamically dispatch a call to a final method, and static invocation can be used instead.
The compiler can emit a direct call to the method, bypassing entirely the usual virtual
method invocation procedure. Because of this, final methods are also candidates for
inlining by a Just-In-Time compiler or a similar optimization tool. (Remember,
private/static methods are already final, therefore always considered for this
optimization.)
Static invocation is faster than dynamic method lookup, leading to the widespread use of
final methods as an optimization technique. But this "optimization" is next to useless in
recent virtual machines: they are able to detect if a non-final method is overridden, and if
not, use static invocation. Therefore, final should be used first and foremost for sofware
engineering reasons, as discussed in the rest of this article.
Final Classes
A final class cannot be subclassed, or extended, in any way. Final classes can be regarded
as a generalization of final methods: a final class has all its method declared final. On the
other hand, fields of a final class do not have any special property.
For Security
One of the very best feature of the Java environment is its ability to dynamically load
classes. Necessarily, this flexibility comes at a price, including a more complex security
model. If classes can be loaded dynamically, at any time, the virtual machine must be
able to enforce security policies on the running code. Final classes are used in this context
to prevent malicious code from altering the semantics of classes essential to the
framework.
The best known example of a final class is certainly java.lang.String. This class is so
vital to the operation of the Java compiler and interpreter that it must be guaranteed that
whenever code uses a string, it gets exactly a java.lang.String and not an instance of
some other class. Because java.lang.String is final, it cannot be subclassed, none of
its methods can be overriden, and therefore any String instance is guaranteed to always
behave the way it is intended.
Immutable Objects
I would like to conclude this article with a section about immutable objects and what a
useful pattern they form.
An immutable object is an object which state is guaranteed to stay identical over its entire
lifetime. While it is perfectly possible to implement immutability without final, its use
makes that purpose explicit, to the human (the software developer) and the machine (the
compiler).
Immutable objects carry some very desirable characteristics:
Clearly final is going to help us define immutable objects. First in labelling our object
as immutable, which makes it simple to use and understand by other programmers.
Second in guaranteeing that the object's state never changes, which enable the thread-safe
property: thread concurrency issues are relevant when one thread can change data while
another thread is reading the same data. Because an immutable object never changes its
data, synchronizing access to it is not needed.
Create an immutable class by meeting all of the following conditions:
Conclusion
I hope you have enjoyed this scrutiny of a sometimes forgotten feature of the Java
language. My references section lists additional resources useful to the reader eager to
keep on learning about final and its uses.
if Statement - Overview
Purpose
The purpose of the if statement is to make decisions, and execute different parts of your program
depending on a boolean true/false value. About 99% of the flow decisions are made with if. [The
other 1% of the decisions use the switch statement.]
General Forms
The if statement has this form, where condition is true or false.
Example - EvaluateScore.java
Decisions (if statements) are written in diamonds, and computational processes are written in
boxes. There are several styles, and here is one of the most common.
Alternate ways to write the above if statement
There are lots of ways to write the above if statement. Here are some.
1. Reverse the condition. Which to put first? There are two practices: Either put the normal
case first, or the case that makes the boolean condition easiest to read.
2. String comment; // Message to the user.
3. if (score < 60) {
4. comment = "This is terrible";
5. } else {
6. comment = "Not so bad";
}
7. Initialize the variable to a default value, and only change it if necessary. This is often used
when the condition is only rarely true.
8. String comment = "Not so bad; // Message to
the user.
9. if (score < 60) {
10. comment = "This is terrible";
}
11. BAD: Two ifs. This is almost always a bad way to write an if-else. It's confusing to read,
border values can slip through, and both conditions must be evaluated (inefficiency).
12. // BAD BAD BAD BAD BAD BAD BAD BAD BAD
13. String comment; // Message to the user.
14. if (score < 60) {
15. comment = "This is terrible";
16. }
17. if (score >= 60) {
18. comment = "Not so bad";
}
Brace style
Always write braces. It is good programming style to always write the curly braces, {}, altho
they are not needed if the clause contains only a single statement. There are two reasons this is
good.
• Reliability. When code is modified, the indentation is such a strong indicator of structure
that the programmer may not notice that the addition of a statement at the "correct"
indentation level really isn't included in the scope of the if statement. This is a suprisingly
common error.
• Readability. It is faster to read code with the braces because the reader doesn't have to
keep in mind whether they are dealing with an un-braced single statement or a braced
block.
History. Braces have been used in most language that have descended from Algol, including C, C+
+, Java, C# etc because language designers want to make it easy for programmers in earlier
languages to make the transition. Braces are an annoying and error prone, and numerous
languages, eg, Visual Basic and Python, have tried to choose better notation.
Form
The if statement without an else has this form:
if (condition) {
do this if the condition is true
}
Example
Here is a paintComponent() method with an if statement without an else clause.
If the true or false clause of an if statement has only one statement, you do not need to use
braces (also called "curly brackets"). This braceless style is dangerous, and most style guides
recommend always using them.
Braceless form
The if statement doesn't need braces if there is only one statement in a part. Here both the true
and false parts have only one statement:
A: it always prints "This is terrible" because of that semicolo after the if clause. The semicolon
indicates an empty statement, which satisfies the compiler, but is surely not what you intended.
Putting a beginning brace after the if condition prevents programmers from also adding a semicolon
and creating this kind of error.
A: Although the comment will be appropriate to the score, the grade will always be "F". Although
the second grade assignment is indented, it isn't inside the if because the unbraced clause only
includes one statement! This appearance of being included is a major source of programming
errors.
There are many kinds of Java statements that use braces to group things. You've already seen class
and method (eg, main) declarations, which enclose their contents in braces. In addition to ifs, you'll
learn about loops (for, while, and do), try...catch, and switch statements which use braces to
enclose other statements.
There are several meathods to make programs readable. How can you easily make the reader see
which statements are inside the true part and false part of an if statement.
The best way to show this is to indent the statements that are inside. To do this you move the
statements to the right by a few spaces. People commonly use two, three, or four spaces. Choose
one number (eg, I use 2 or 3), and use it for all programs.
Java doesn't care about your indentation -- it is for humans (including yourself!).
Even a very short method is almost unreadable when you take out the line breaks and
spaces. Here is the same method:
public void paintComponent(Graphics g) {super.paintComponent(g);if
(marks<50) g.setColor(Color.red);else
g.setColor(Color.black);g.drawString("Score = " + marks,10,50);}
Nearest 'else'
If you use braces, there is no problem with deciding which else goes with which if For example,
These kinds of errors are very hard to find. This is another good reason to always use braces.
Why does the following code always say it thinks the user is lying?
String ageStr = JOptionPane.showInputDialog(null, "How old are you?");
int age = Integer.parseInt(ageStr);
if (age > 120 || age < 0);
System.out.println("I think you're lying about your age!");
It's the semicolon! if you put a semicolon directly after the condition in an if statement, Java
thinks it's finished with the body of the statement. The indentation of the next line, which is so
important to human readers, is ignored by Java.
This is another error that's harder to make if you always follow the condition by an opening brace.
This code is correctly indented, but ugly and hard to read. It also can go very far to the right if
there are many tests.
if (score < 35) {
g.setColor(Color.MAGENTA);
} else {
if (score < 50) {
g.setColor(Color.RED);
} else {
if (score < 60) {
g.setColor(Color.ORANGE);
} else {
if (score < 80) {
g.setColor(Color.YELLOW);
} else {
g.setColor(Color.GREEN);
}
}
}
}
Other languages
Some programming languages recognize this common construction with a special elseif keyword.
Although it is hardly necessary, this kind of small touch can make a language a little nicer to use.
The Java language designers are very conservative about adding keywords to the language, so
don't expect it.
Syntax
switch (expr) {
case c1:
statements // do these if expr == c1
break;
case c2:
statements // do these if expr == c2
break;
case c2:
case c3:
case c4: // Cases can simply fall thru.
statements // do these if expr == any of c's
break;
. . .
default:
statements // do these if expr != any above
}
Switch keywords
switch
The switch keyword is followed by a parenthesized integer expression, which is followed
by the cases, all enclosed in braces.. The switch statement executes the case corresponding
to the value of the expression. Normally the code in a case clause ends with a break
statement, which exits the switch statement and continues with the statement following the
switch. If there is no corresponding case value, the default clause is executed. If no case
matched and there is no default clause, execution continues after the end of the switch
statement.
case
The case keyword is followed by an integer constant and a colon. This begins the
statements that are executed when the switch expression has that case value.
default
If no case value matches the switch expression value, execution continues at the default
clause. This is the equivalent of the "else" for the switch statement. It is written after the
last case be convention, and typically isn't followed by break because execution just
continues out the bottom of switch if this is the last clause.
break
The break statement causes execution to exit to the statement after the end of the switch.
If there is no break, execution flows thru into the next case. Flowing directly into the next
case is almost always an error.
Example - Random comment
String comment; // The generated insult.
int which = (int)(Math.random() * 3); // Result is 0, 1, or 2.
switch (which) {
case 0: comment = "You look so much better than usual.";
break;
case 1: comment = "Your work is up to its usual standards.";
break;
case 2: comment = "You're quite competent for so little
experience.";
break;
default: comment = "Oops -- something is wrong with this code.";
}
Equivalent if statement
A switch statement can often be rewritten as an if statement in a straightforward manner. For
example, the preceding switch statement could be written as follows. When one of a number of
blocks of code is selected based on a single value, the switch statement is generally easier to
read. The choice of if or switch should be based on which is more readable.
if (which == 0) {
comment = "You look so much better than usual.";
} else if (which == 1) {
comment = "Your work is up to its usual standards.";
} else if (which == 2) {
comment = "You're quite competent for so little experience.";
} else {
comment = "Oops -- something is wrong with this code.";
}
Defensive programming
Always include a default clause in your switch statement as a general policy of defensive
programming - assume there will be bugs in your code and make sure they are caught.
Where to use switch?
The ability of switch to choose between many sections of code seems to make it more powerful
than if. However, selecting sections of code depending on specific integer values turns out not to be
very common. If you are handling specific coded values (eg, the number of the button that was
clicked in a JOptionPane), or processing characters (whose codes are treated like numbers), you
may find it useful.
Efficiency? Some compilers can produce more efficient code for certain switch statements than
for equivalent if statements. I haven't bothered to test the Java compiler because, if there is a
speed difference, it would be extremely small and the choice between switch and if should be
based on readability.
Comments on switch
Java's switch statement, which was taken directly from C++ to increase its attractiveness to C++
programmers, is not well loved.
• No ranges. It doesn't allow ranges, eg case 90-100:. Many other languages do.
• Integers only. It requires integers and doesn't allow useful types like String. Many other
languages do.
Separate model (logic) from user interface. This program is separated into two classes: one
contains the logic (or "model" as it's more often called) for generating an insult as a string. It knows
nothing about the user interface, and could equally well be used in a dialog program (as in the test
program below), console I/O, a GUI program, or a web-based application.
This is the logic of the program, and does no I/O so it would be equally suitable as the logic behind
a console program, GUI program, or web server program.
// File : flow-switch/insult/InsultGenerator1.java
1
// Purpose: Generates random insults.
2 // Author : Fred Swartz 2006 Aug 23 Placed in public domain
// Comments: This switch statements were written in the
3
// most conservative style -- a default clause
4 // and no returns in them.
//
5
// The structure of the random generation is
6 // entirely in executable code,
// A much better way to write this is as a
7
// data-Driven program, where this information is
8 // represented by data structures, with a
// simple program to process the data.
9
//
10 // The data-driven style allows the data to be
// read in from user-editable files for example,
11
// so the program need not be recompiled for changes.
12
public class InsultGenerator1 {
13
14 //============================================ badInputInsult
public static String badInputInsult() {
15
String insult;
16 switch (rand(2)) {
case 0: insult = "What kind of "
17
+ infoAdjective() + " "
18 + infoNoun()
+ " is this, you "
19
+ personAdjective() + " "
20 + person()
+ "?";
21
break;
22
case 1: insult = "Never enter this kind of "
23
+ infoAdjective() + " "
24 + infoNoun()
+ " again!!!!";
25
break;
26
default:insult = "Oops -- bad switch statement";
27
}
28 return insult;
}
29
30 //==================================================== person
private static String person() {
31
String name;
32 switch (rand(3)) {
case 0 : name = "idiot" ; break;
33
case 1 : name = "imbecile"; break;
34 case 2 : name = "moron" ; break;
default: name = "bad value from person???";
35
}
return name;
36
}
37
//=========================================== personAdjective
38
private static String personAdjective() {
39 String adj;
switch (rand(4)) {
40
case 0 : adj = "clueless"; break;
41 case 1 : adj = "witless" ; break;
case 2 : adj = "stupid" ; break;
42
case 3: adj = "hopeless"; break;
43 default: adj = "bad value from infoAdjective???";
}
44
return adj;
45 }
46
//============================================= infoAdjective
47 private static String infoAdjective() {
String adj;
48
switch (rand(5)) {
49 case 0: adj = "revolting" ; break;
case 1: adj = "insulting" ; break;
50
case 2: adj = "meaningless"; break;
51 case 3: adj = "useless" ; break;
case 4: adj = "idiotic" ; break;
52
default:adj = "bad value from infoAdjective???";
53 }
return adj;
54
}
55
//================================================== infoNoun
56
private static String infoNoun() {
57 String noun;
switch (rand(4)) {
58
case 0: noun = "nonsense"; break;
59 case 1: noun = "crap" ; break;
case 2: noun = "swill" ; break;
60
case 3: noun = "garbage" ; break;
61 default:noun = "bad value from infoNoun???";
}
62
return noun;
63 }
64
//===================================================== rand
65 // Utility method to generate random numbers in range 0..bound-
1.
66
// Starting the range at zero was simply to match the typical
67 // Java ranges (eg, switch, subscripts) that start at zero.
// Returns random int in range 0...bound-1
68
private static int rand(int bound) {
69 return (int) (Math.random() * bound);
}
70
}
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
Main program
// File : flow-switch/insult/TestTextGenerator1.java
// Purpose: Show some random insults.
1
// Author : Fred Swartz
// License: public domain
2 // Date : 2006 May 3
import javax.swing.*;
3
public class TestTextGenerator1 {
4 public static void main(String[] args) {
String display;
do {
5
display = InsultGenerator1.badInputInsult()
+ "\n\nWould you like another opinion?";
6 } while (JOptionPane.showConfirmDialog(null, display) ==
JOptionPane.YES_OPTION);
}
7
}
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
Data-driven programming
Replace methods with data structure? This version is written with executable Java code. It is
usually very desirable to replace executable code with some kind of data structure. There are
several reasons for this.
• Data can be stored in user-editable files, which allows modifying the functioning of the
program without recompiling, or even having access to the source code.
• Every line of code is a liability! Keeping code small is a very good goal. It looks like nothing
can go wrong here, but surely it will sometime when the program is updated.
Programming problems
1. Problem (using arrays): Get rid of the methods, and replace them with arrays of strings.
You'll find it useful to define a method to choose a random element from an array of
Strings. To keep this problem simple don't read the data in from files. It might look like
2. private static String chooseRandom(String[] words)
3. Problem (using Map and File I/O): Another way to think about this problem is to have a
special syntax to denote something that should be replaced -- I'll use "angle brackets" to
surround terms that should be replaced by a something that is dynamically generated. For
example, the starting element could be the string "<insult>".
The program would then look up the definition of "insult" in something like
HashMap<String, ArrayList<String>> and randomly choose one of the strings
from the array list. For example, it might replace "<insult>" with "Never enter this kind of
<infoAdj> <infoNoun> again!!!!"
The program would then find each thing surrounded by angle brackets and replace it with a
randomly chosen values from its associated arrays. This process is repeated until all angle
bracketted symbols have been replaced.
Read data in from a file. One plausible format would be to have the the "meta-symbols"
start in column 1, and all possible definitions follow on lines that start with a blank. For
example,
<insult>
Never enter this kind of <infoAdj> <infoNoun> again!!!!
What kind of <infoAdj> <infoNoun> is this, you <personAdj>
<person>?
<infoAdj>
revolting
insulting
meaningless
useless
idiotic
. . .
Loops - Introduction
The purpose of loop statements is to repeat Java statements many times. There are several kinds of
loop statements in Java.
while statement - Test at beginning
The while statement is used to repeat a block of statements while some condition is true. The
condition must become false somewhere in the loop, otherwise it will never terminate.
//... While loop to build table of squares.
String result = ""; // StringBuilder would be more efficient.
int i = 1;
while (i <= 20) {
result = result + i + " squared is " + (i * i) + "\n";
i++;
}
JOptionPane.showMessageDialog(null, "Tables of squares\n" + result);
The following example has an assignment inside the condition. Note that "=" is assignment, not
comparison ("=="). This is a common coding idiom when reading input.
//... Add a series of numbers.
JOptionPane.showMessageDialog(null, "Enter ints. Cancel to end");
String valStr;
int sum = 0;
while ((valStr = JOptionPane.showInputDialog(null, "Number?")) !=
null) {
sum += Integer.parseInt(valStr.trim());
}
JOptionPane.showMessageDialog(null, "Sum is " + sum);
Many loops consist of three operations surrounding the body: (1) initialization of a variable, (2)
testing a condition, and (3) updating a value before the next iteration. The for loop groups these
three common parts together into one statement, making it more readable and less error-prone
than the equivalent while loop. For repeating code a known number of times, the for loop is the
right choice.
//... For loop to build table of squares.
String result = ""; // StringBuilder would be more efficient.
for (int i = 1; i <= 20; i++) {
result += i + " squared is " + (i * i) + "\n";
}
JOptionPane.showMessageDialog(null, "Tables of squares\n" + result);
Java 5 introduced what is sometimes called a "for each" statement that accesses each successive
element of an array, List, or Set without the bookkeeping associated with iterators or indexing.
//... Variable declarations.
JTextArea nameTextArea = new JTextArea(10, 20);
String[] names = {"Michael Maus", "Mini Maus"};
There are three general ideas that you will see in many parts of Java.
If the body of a loop has more than one statement, you must put the statements inside braces. If
there is only one statement, it is not necessary to use braces {}. However, many programmers
think it is a good idea to always use braces to indicate the scope of statements. Always using
braces allows the reader to relax and not worry about the special single statement case.
Indentation. All statements inside a loop should be indented one level (eg, 4 spaces), the same as
an if statement.
'while' Statement
Purpose - to repeat statements
The purpose of the while statement is to repeat a group of Java statements many times. It's
written just like an if statement, except that it uses the while keyword.
General Form
The while statement has this form:
while (condition) {
statements to repeat while the condition is true
}
The value of condition must be true or false (ie, a boolean value). It is often a comparison
(see example below).
'for' Loop
Purpose
The for statement is similar to the while statement, but it is often easier to use if you are counting
or indexing because it combines three elements of many loops: initialization, testing, and
incrementing.
General Form
1. The init-stmt statement is done before the loop is started, usually to initialize an iteration
variable.
2. The condition expression is tested before each time the loop is done. The loop isn't
executed if the boolean expression is false (the same as the while loop).
3. The next-stmt statement is done after the body is executed. It typically increments an
iteration variable.
Here is a loop written as both a while loop and a for loop. First using while:
int number = 1;
while (number <= 12) {
System.out.println(number + " squared is " + (number * number));
number++;
}
And here is the same loop using for.
for (int number = 1; number <= 12; number++) {
System.out.println(number + " squared is " + (number * number));
}
This code will look at each character in a string, sentence, and count the number of times any
character occurs doubled.
String sentence = ...;
int doubleCount = 0; // Number of doubled characters.
The for loop is shorter, and combining the intialization, test, and increment in one statement makes
it easier to read and verify that it's doing what you expect. The for loop is better when you are
counting something. If you are doing something an indefinite number of times, while loop may be
the better choice.
For-each Loop
Purpose
The basic for loop was extended in Java 5 to make iteration over arrays and other collections more
convenient. This newer for statement is called the enhanced for or for-each (because it is called this
in other programming languages). I've also heard it called the for-in loop.
Use it in preference to the standard for loop if applicable (see last section below) because it's much
more readable.
Series of values. The for-each loop is used to access each successive value in a collection of
values.
Arrays and Collections. It's commonly used to iterate over an array or a Collections class (eg,
ArrayList).
Iterable<E>. It can also iterate over anything that implements the Iterable<E> interface (must
define iterator() method). Many of the Collections classes (eg, ArrayList) implement
Iterable<E>, which makes the for-each loop very useful. You can also implement Iterable<E> for
your own data structures.
General Form
The for-each and equivalent for statements have these forms. The two basic equivalent forms are
given, depending one whether it is an array or an Iterable that is being traversed. In both cases an
extra variable is required, an index for the array and an iterator for the collection.
Altho the enhanced for loop can make code much clearer, it can't be used in some common
situations.
• Only access. Elements can not be assigned to, eg, not to increment each element in a
collection.
• Only single structure. It's not possible to traverse two structures at once, eg, to compare
two arrays.
• Only single element. Use only for single element access, eg, not to compare successive
elements.
• At least Java 5. Don't use it if you need compatibility with versions before Java 5.
// File : loops/reverse/Reverse.java
1
// Purpose: Reverse a string using a loop.
2 // Author : Fred Swartz
// Date : Oct 23 2005
3
// Comments: Building a String one character at a time
4 // is very inefficient because it requires
// creating a new object for each concatenation.
5
// StringBuilder is better, and it already
// has a reverse() method!
6
7 import javax.swing.*;
8
public class Reverse {
9 public static void main(String[] args) {
10
String input; // Used for the input string.
11 String reversed; // Reversed form or the input string.
12
while (true) {
13 input = JOptionPane.showInputDialog(null, "Enter a
string");
14
if (input == null) break;
15
reversed = "";
16
for (int i=0; i<input.length(); i++) {
17 reversed = input.substring(i, i+1) + reversed;
}
18
19 JOptionPane.showMessageDialog(null, "Reversed:\n" +
reversed);
20
}
21 }
}
22
23
24
25
26
27
28
29
30
31
Assertions
Assertions are used to stop execution when "impossible" situations are
detected
Impossible conditions. Program debugging is filled with "impossible" problems ("But that
parameter can't possibly be null"). If you're lucky, the problem is detected immediately in some way
you can easily diagnose. If not, the error may propagate thru the program, finally crashing, but so
far from the original bug that diagnosis is difficult. Even worse, the bug may not produce visible
symptoms until after it has altered permanent data. Assert statements provide an easy means to
check for impossible conditions, with little or no runtime cost.
Programmer, not user problems. The purpose or asserts is to detect programming errors, and
they should not be used in the case of erroneous user input or actions.
Crash as quickly as possible. Discovering bugs as early as possible is good. Every program starts
with bugs, and the debugging process is faster and simpler when the bugs are detected early. It's
better to discover a problem at compile time than at run time, and it's better to discover a run-time
bug as early as possible. Often a run-time bug doesn't cause an immediate, visible, disaster.
Instead, the consequences of the bug distort the following execution, and the bad effects may not
become visible for a long time. The crippled program may corrupt files or have other bad
consequences. Tracing symptoms back to the original cause can be a long, tedious process. The
goal is to detect bugs as early as possible. Assertions provide a relatively painless way to stop many
bugs before they go too far.
An assert statement has two parts separated by a colon. The boolean condition must be
true for execution to continue. If it is false, an AssertionError is thrown, which
terminates execution and display the message string. Some examples.
assert jobQueue.size() == 0 : "processB: queue should have been
empty.";
Abbreviated form
The simplest form the assert statement specifies only a boolean expression that must be
true. This is OK when there's not much to say, or the likelihood of failing seems so remote
it isn't worth the extra typing.
assert n > 0;
One path to early bug detection is to test variables to see if they have expected values. If
something is wrong, the program can stop and indicate that an unexpected inconsistency was
discovered. Later, when the program is released, this checking may either be disabled to increase
speed, or left in if a "crash" is better than uncontrolled bug propagation (usually the case). If the
checking code is removed or disabled, it should be reinserted or activated during testing all future
updates. Writing checking code can be a major headache, so it isn't done in many cases. The
assert statement makes testing conditions relatively easy, and allows easy activation or
deactivation of some or all of the checking code.
Assertions are used to check for things that can't possibly be wrong! This is what bugs are -- things
that shouldn't happen do happen because there is something wrong with the code. Assertions are
often used in the following cases.
• Check situations which must be true, but aren't obviously so. For example, the result of a
complicated calculation must be in a certain range.
• All switch statements should have default clauses. If this path is impossible, use an
assert that will always fail.
• default:
assert false: "You shouldn't be here!"
• Add an assert where control should never flow, eg, when looking up and returning an entry
that "must" be in an array, the code after the loop should never be executed. Put an
assert false: "some message" there.
• There is less of a need to check conditions which produce immediate execution errors. For
example, there is no need to check if an array reference is null when the array is used
immediately after that, because a NullPointerException would stop execution. An assert
would allow a better error message, and you must decide if the extra code is worth the
better error diagnostic. In many cases the answer is "no".
Assertion checking defaults to off at runtime, unfortunately. You should always turn them on.
See NetBeans 4.1 IDE for how to enable assertions. This also applies to the NetBeans 5 beta
version.
1. Some argue that a production program should not have the overhead of evaluating asserts.
Asserts are not slow, but there is some cost. If they are not turned on at at execution time,
the class loader actually strips out all the assertion code so they really don't take up any
time or memory. But this small amount of time is surely unnoticeable in all but the most
critical tasks.
2. The user may be presented with an unfamiliar error message. This seems like an especially
bad argument. Does the user really prefer bad results to a strange error message?
Why don't the same people that want assertion checking to default off also want subscript checking
to default off?
Before Java 5
The assert statement was added to Java in version 1.4, but it didn't default on for the compiler
until version 5. You have to explicitly turn it on in Java 1.4 by specifying the "-source 1.4" option to
the compiler.
Exceptions
Exceptions | Exception Usage | Exceptions - More
When your program causes an error, Java throws an exception. Java then throws this exception
to a part of the program that will catch it. You shouldn't try to catch most exceptions, but you
should catch all exceptions that are caused by events which you have no control over - exceptions
caused by bad user input or I/O problems.
Processing an exception
When an exception is thrown, execution of that statement stops immediately and Java looks for
someone to catch the exception.
1. It looks to see if the code that caused the exception is inside a try statement that can
handle the exception. If the try statement has a catch clause that can handle this type of
exception, then it goes to that code. After catch clause is executed, execution resumes after
the end of the entire try statement. It's not possible to return to the point at which the
exception was thrown.
2. If there is no try statement around the code that threw the exception, Java goes up the
call stack and looks at the statement that called this method, and checks for a try
statement surrounding the call. If it finds an enclosing try statement that has a catch clause
for this kind of exception, the catch clause is executed and then execution continues after
that try statement. Java continues moving up the call stack until it finds an enclosing try
statement.
3. If no enclosing try statement and catch clause is found, the exception is caught by the
initial Java system method that called main initially. It prints an error message and
terminates the program.
Put a try...catch statement around any section of code that might generate a user generated
exception (eg, converting text field input to numbers). The simplest form is:
try {
. . . // Normal statements that might cause a problem
} catch (exception-name parameter-name) {
. . . // Statements to execute if exception-name occurred.
}
Example
If the user types an illegal value into a JTextField that expects an integer (eg, "123X45"),
attempting to convert with Integer.parseInt will throw a NumberFormatException.
txt = aTextField.getText();
try {
. . . // other code
i = Integer.parseInt(txt);
. . . // process the input
catch (NumberFormatException nfe) {
aTextField.setText("Enter an integer");
}
Exception Usage
Exceptions Exception Usage | Exceptions - More
The most common exceptions to catch are number conversion exceptions and I/O exceptions. Here
are some common exceptions to catch:
Exception Cause
NumberFormatException You tried to convert a number from an illegal String form.
A Scanner method, eg nextDouble() will throw this exception
InputMismatchException
when the next input text is not the right type, eg double.
IOException Catch an IOException to get either of its subclasses below.
FileNotFoundException The specified file didn't exist.
EOFException Tried to read past end of file.
MalformedURLException This can be generated if you are using the java.net package.
There are a few cases where you might want to silently ignore an exception. For example,
changing the Look and Feel of the GUI may cause an exception. There's nothing to be done
about it, so you don't want to stop execution. For example, I sometimes use the Liquid look
and feel, and have this code.
try {
UIManager.setLookAndFeel(new
net.sourceforge.napkinlaf.NapkinLookAndFeel());
} catch (Exception e) {
// Silently ignore -- there's nothing to be done.
}
try {
Thread.sleep(DELAY);
} catch (InterruptedException ignoredException) {
// Silently ignore. This thread can never cause an
exception.
}
If you do silently ignore exceptions, enclose only one call in the try clause; do not use
larger blocks of code as suggested below. Rather than silently ignoring exceptions, consider
logging them to a file.
Put larger blocks of code in a try clause
Altho an exception is generated by a single statement, an entire block of code is usually
affected. It is often better to put the try around the block, not just single statements.
Don't catch exceptions that you can't really do anything with
If you can't do anything useful, don't catch an exception. Let someone higher up catch it.
Exception handling is usually slow
It is generally not a good idea to use exception handling mechanism instead of simple if
tests because throwing and catching exceptions is typically much slower.
Catch and rethrow exceptions to clean up
If your code has to clean up something (eg, close files, put a data structure into a
consistent state, ...), it can catch exceptions, do the cleanup, and then rethrow the
exception.
For debugging purposes you can print a trace of the current call stack.
e.printStackTrace();
Exceptions - More
Prev: Exception Usage Next: Throwing Exceptions
Kinds of Exceptions
There are many exceptions, but they can be put into two groups: checked exceptions and
unchecked exceptions. There is some controversy about which type you should use. A discussion of
some of the issues can be found at Java theory and practice: The exceptions debate.
• Unchecked Exceptions -- These exceptions are usually something that should have been
prevented by more careful programming. For example, you should never get
NullPointerException or ArrayIndexOutOfBoundsException. If you do, there
is something wrong with your program, and you need to fix it. You usually don't catch
unchecked exceptions. Instead, fix your program so it can't produce one of these.
However, NumberFormatException is the one exception of this type that is usually
caught.
• Checked Exceptions -- These are usually errors in the input data. The programmer has no
control over the input the user gives you, eg, file names, .... If the user gives you a bad
value, it may cause an exception when you use it. You need to check for bad input
using a try statement.
Probably most of your student programming has been "Happy Trails" style, where you didn't have
to worry much about handling errors. But error handling is really a big deal in most real programs,
and exceptions play a central role in dealing with errors.
All experienced programmers agree that using exceptions for normal processing flow is wrong.
Exceptions should only be used only for errors or unusual conditions, and the equivalent if tests
should be used for normal processing. There are good reasons for this.
• Slow. Exceptions are very slow. When an exception occurs, the Java runtime system works
its way up the call stack (you might be surprised at how deep this can get), identifying each
source statement at which a call was made, and building a string that reports this. This
string is then used in creating the exception object that is thrown. This is not fast.
Here are examples where beginning programmers used exceptions, but should NOT have. These are
all done to either speed execution (which they do not) or simplify code (which they arguably do
not).
Two alternate definitions of a method are given, one uses exceptions and the other uses if to
handle the boundary violation cases. The exception solution is very inefficient and might be very
hard to interpret by the reader. The difficulty is increased because the writer chose to use the
Exception class instead of ArrayIndexOutOfBoundsException. The use of Exception suggests that it
is designed to catch other exceptions too. if the body of the try had been larger, it might have been
very difficult decide exactly which exception is being caught. Do you see which other exception
could be thrown by the code, at least in principle?
private boolean[][] cell = new boolean[SIZE][SIZE];
. . .
// BAD
public void flipA(int row, int col) {
cell[col ][row ] = !cell[col][row];
try { cell[col+1][row ] = !cell[col+1][row ];} catch(Exception e)
{}
try { cell[col-1][row ] = !cell[col-1][row ];} catch(Exception e)
{}
try { cell[col ][row+1] = !cell[col ][row+1];} catch(Exception e)
{}
try { cell[col ][row-1] = !cell[col ][row-1];} catch(Exception e)
{}
}
Other examples
There are numerous cases in addition to subscription where the use of exceptions is entirely
inappropriate.
Exceptions provide a good infrastructure for error processing. The simplicity of throwing an
exception at a deep level and catching it at a high level may generate problems at the intermediate,
skipped, levels. Did any of these methods leave any part of a data structure or resource in an
inconsistent state? Each place that this may be true of needs to enclose critical code in a
try...finally block.
References
Throwing Exceptions
Prev: Exceptions
It's common to test parameters of methods or constructors for legality. But if the value is illegal,
what should you do? If your class is designed to be called by other, you should define your own
exceptions, so you can document the errors for them more easily.
But if your methods are only being called by your own code, you can either use an assert or throw
an exception. I often use something like the following, supplying a comment with the class, method,
and meaningful comment.
if (age < 0) {
throw new
IllegalArgumentException("PhysicalExam.scaleBloodPressure: age is
negative");
}
Note that this shouldn't be used for illegal user input -- that should have been checked in the
interface. This should only be thrown if there is a programming error. Only the programmer should
see this exception.
You can also create your own exceptions. [Not yet written]
Define library exceptions to tell programmer they should fix their code
If you write a library that is used by others, throw your own exceptions if your code is called with
illegal values, eg, something isn't initialized. Your exceptions are a way to tell the applications
programmer that they should fix their code.
Methods 1 - Introduction to
methods
Purpose of this lesson:
Java statements are grouped together in methods. Each method must be inside a class. Every
method has a name, which starts with a lowercase character and typically is a verb because it does
something.
Other terms: The idea of method is in every programming language, but different terms are used
in many languages. You might have seen terms like function, procedure, or subroutine. We'll use
method consistently here, but you will hear programmers using these equivalent terms occasionally.
Hierarchical organization. Computer programs are structured in many ways like an organization
-- higher levels rely on others to do much of the work. They "call" on lower levels to do the work,
passing them all necessary "arguments". In a similar way, the top level of a computer program,
main, often consists largely of method calls, and those methods may in turn call on yet other
methods.
Identifying methods
Parentheses follow name. You can identify a method name because it is always followed by left
and right parentheses, which may enclose arguments (parameters). If you see a left parenthesis
with a name preceding it, it will be a method call or definition, or a constructor (constructors are
very similar to methods). In the following example each method name is highlighted.
When calling methods outside of the current class, eg, in the Java library, static methods are
preceded by the class name (followed by a dot), and instance methods are preceded by an object.
When a static method is defined, the keyword "static" will preceded it. The example below has only
static methods.
// File : methods/KmToMiles.java
// Purpose: Convert kilometers to miles. Use JOptionPane for input /
1
output.
// Author : Fred Swartz
2 // Date : 22 Apr 2006
import javax.swing.*;
3
public class KmToMiles {
4 //============================================================
constants
private static final double MILES_PER_KILOMETER = 0.621;
5
//===============================================================
6 == main
public static void main(String[] args)
{ //Note 1
7
//... Local variables
String kmStr; // String km before conversion to double.
8 double km; // Number of kilometers.
double mi; // Number of miles.
9
//... Input
1 kmStr = JOptionPane.showInputDialog(null, "Enter
kilometers.");
0
km = Double.parseDouble(kmStr);
1
1 //... Computation
mi = km * MILES_PER_KILOMETER;
1
2
//... Output
1 JOptionPane.showMessageDialog(null, km + " kilometers is "
3 + mi + " miles.");
}
1
}
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
Notes
1. This defines a method called "main". Everything between the "{" on the end of this line to
the matching "}" second from the end is the "body" of the method.
The above code defines the static main method, which someone (eg, the operating system) will call
with KmToMiles.main(. . .).
To do its work, main calls on other methods: showInputDialog, which is defined in the
JOptionPane class, parseDouble, which is defined in the Double class, and
showMessageDialog, which is also in the JOptionPane class.
Whenever you call a static method in a different class, precede it with the name of the class
containing its definition, followed by a dot. If you don't specify the class name, it assumes the
method is defined in the current class.
In addition to supplying the object's data to the method, the class of the object, eg String, is where
the method is defined.
// File : dialog/capitalize/Capitalize2.java
1
// Purpose: Capitalize first letter of each name. Declare with first
2 use.
// Author : Fred Swartz - placed in public domain.
3
// Date : 30 Mar 2006
4
import javax.swing.*;
5
6 public class Capitalize2 {
7
public static void main(String[] args) {
8 //.. Input a word
String inputWord = JOptionPane.showInputDialog(null, "Enter a
9
word");
10
//.. Process - Separate word into parts, change case, put
11
together.
12 String firstLetter = inputWord.substring(0,1); // Get first
letter
13
String remainder = inputWord.substring(1); // Get
14 remainder of word.
String capitalized = firstLetter.toUpperCase() +
15
remainder.toLowerCase();
16
//.. Output the result.
17
JOptionPane.showMessageDialog(null, capitalized);
18 }
}
19
20
21
22
Nothing at front when calling methods in same class. When calling your own methods, you
don't have to write anything before the method name. The compiler assumes the same class or
object.
// File : metho
1
// Purpose: Conve
2 input / output.
// Author : Fred
3
// Date : 22 Ap
4
import javax.swin
5
public class KmTo
6 //===========
constants
7
private stati
8
//===========
9
==== main
10 public static
//... Loc
11
String km
12 double km
double mi
13
14 //... Inp
kmStr = J
15
kilometers.");
16 km = Doub
17
//... Com
18 mi = km *
19
//... Out
20 JOptionPa
21
}
22 }
The method call, and the first line (header) of the method definition are highlighted.
// File : methods/KmToMilesMethod.java
// Purpose: Convert kilometers to miles using a method.
1
JOptionPane IO.
// Highlight call and method definition header.
2 // Author : Fred Swartz
// Date : 22 Apr 2006
3
import javax.swing.*;
6 //=============================================================
==== main
public static void main(String[] args) {
7
//... Local variables
String kmStr; // String km before conversion to double.
8 double km; // Number of kilometers.
double mi; // Number of miles.
9
//... Input
1 kmStr = JOptionPane.showInputDialog(null, "Enter
0 kilometers.");
km = Double.parseDouble(kmStr);
1
1
//... Computation
1 mi = convertKmToMi(km);
2 //Note 1
1
//... Output
3
JOptionPane.showMessageDialog(null, km + " kilometers is "
1 + mi + " miles.");
4 }
1
//=========================================================
5
convertKmToMi
1 private static double convertKmToMi(double kilometers) {
6 //Note 2
double miles = kilometers * MILES_PER_KILOMETER;
1
return miles;
7
}
}
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
Notes
1. Call our own method below to do the conversion. We could have qualified the name with
our class name, KmToMilesMethod.convertKmToMi(km), but this is unnecessary when
calling a static method in the same class.
2. Altho this method is trivial, just a multiplication, it is good practice to separate the
"model", or "logic", from the user interface. As programs become larger, this separation
becomes essential.
When you define a method, you should think about who can use it. Generally you want to
choose the lowest level of visibility that makes your program usable, either private or
the default (package). Here are the four options, from least visible to most visible.
• private - If you don't want any other class to use it, declare it private.
This is a good choice.
• None (package) - If you don't specify anything, the default visibility
allows only classes in the same package (directory) to see it. This is a common
choice. It's common to use public visibility when package visibility is more
appropriate -- I do it myself. The lack of a keyword for package visibility makes it
a little harder to read.
• protected - Don't use this protected, except in certain cases to let
a child class see it. Even then, its use is controversial.
• public - Let's anyone see it. Choose this if you've defined a method
that will be used by others outside of your project. Note that main must be
declared public so the run-time system can call it.
Parameter(s)
private static double convertKmToMi(double kilometers) {
double miles = kilometers * MILES_PER_KILOMETER;
return miles;
}
Parameters are enclosed in parentheses following the method name. They are also called
formal parameters). There is only one parameter in this example - kilometers, but if
there are more, they must be separated by commas. The type of each parameter is
specified before the name (eg, double). Parameters are local variables that only exist
inside the method. They are assigned initial values from the arguments when the method
is called.
Method body
private static double convertKmToMi(double kilometers) {
double miles = kilometers * MILES_PER_KILOMETER;
return miles;
}
The body of a method is the statements which are executed when the method is called
are enclosed in braces following the the method header. Additional local variables may be
defined (eg, miles).
Return statement
private static double convertKmToMi(double kilometers) {
double miles = kilometers * MILES_PER_KILOMETER;
return miles;
}
A method returns to the caller after it has done what it wants. If the method returns a
value (not a void method), it must contain a return statement that specifies a value to
return. When execution reaches the return statement, control transfers back to the
calling method, passing a return value to it.
Returning an expression
The above example returns the value in the local variable miles. The return statement can
be followed by any expression of the appropriate type, not just a single value. For
example, this method body could have been written as a single return statement.
private static double convertKmToMi(double kilometers) {
return kilometers * MILES_PER_KILOMETER;
}
24
25
26
27
28
29
30
Argument evaluation
Before a method is called, the arguments are evaluated left-to-right. In the example above most
arguments are simple values, except the second argument in the call to showMessageDialog.
Before the call can be made, this argument expression must be evaluated by performing the
conversions to string and the concatenations.
Principles / Style
Local variables
Now that we've written two methods, main and convertKmToMi, you should know a little more
about the variables in them.
Variables that are declared in a method are called local variables. They are called local because they
can only be referenced and used locally in the method in which they are declared. In the method
below miles is a local variable.
Compiler error. If you try to use a local variable before it's been assigned a value, the compiler
will notice it and give an error message. But the compiler doesn't really know the exact order of
execution in a program, so it makes some conservative assumptions. These assumptions can
sometimes be too conservative, and there are cases where you must initialize a local variable even
though you know it will have a value before it's referenced.
// BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD
private static double convertKmToMi(double kilometers) {
double miles;
return miles; // Won't compile because nothing was assigned to
miles.
}
Preinitialized. The difference is that parameters are initialized from the corresponding argument
values.
// Both kilometers and miles are implemented as local variables.
private static double convertKmToMi(double kilometers) {
double miles = kilometers * MILES_PER_KILOMETER;
return miles;
}
Example. The example below shows how a parameter could be reused. The overhead of declaring
an extra variable is just about zero, so this really isn't more efficient, and even this small example is
astoundingly misleading.
// BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD
private static double convertKmToMi(double kilometers) {
kilometers = MILES_PER_KILOMETER * kilometers; // BAD - Don't do
this, altho it works.
return kilometers;
}
• None.
The table below shows how the call stack changes as calls and returns in the KmToMilesMethods
program are made. This shows the first 8 changes to the call stack after main is entered.
There is actually something before main on the call stack, and the library methods that are called
call many methods of their own, which isn't shown here because we don't need to know what they
call.
Stack frame. Each box represents the information that's stored on the call stack for each method.
This block of information is often called a stack frame. There is internal information associated with
the method, for example, it saves the place to resume execution in the calling method. Each stack
frame is labelled with the method name and a list of parameters and local variables that are
allocated on the stack. "???" is written when we don't know (or care) what the local variables are
that are used by a library method.
1 2 3 4 5 6 7 8
main main main main main main main main
args args args args args args args args
kms kms kms kms kms kms kms kms
miles miles miles miles miles miles miles miles
getDouble getDouble getDouble getDouble getDouble convertKmToMi
prompt prompt prompt prompt prompt kilometers
str str str str str miles
showInputDialog parseDouble
??? ???
Programming ideas
• All code is in methods.
• Style: The main method often consists largely of method calls.
• Style: Methods should generally be no larger than one page.
Here is another variation of the program, this time using three methods. Altho there is no real need
for these methods in such a small program, large programs are in fact composed of many small
methods. It is the essential way that all code is structured.
Each of the user-defined method names, both in the call and the definition, is hilited.
Source code
// File : methods/KmToMilesMethods.java
// Purpose: Converts kilometers to miles using two methods.
1
// Author : Fred Swartz - placed in public domain
// Date : 22 Apr 2006
2
import javax.swing.*;
3
public class KmToMilesMethods {
//=========================================================
4 constants
private static final double MILES_PER_KILOMETER = 0.621;
5
//==============================================================
main
6 public static void main(String[] args) {
double kms = getDouble("Enter number of kilometers.");
double miles = convertKmToMi(kms);
7
displayString(kms + " kilometers is " + miles + " miles.");
}
8
//=====================================================
convertKmToMi
9
// Conversion method - kilometers to miles.
1 private static double convertKmToMi(double kilometers) {
0 double miles = kilometers * MILES_PER_KILOMETER;
return miles;
1
}
1
1 //=========================================================
2 getDouble
// I/O convenience method to read a double value.
1
private static double getDouble(String prompt) {
3
String tempStr;
1 tempStr = JOptionPane.showInputDialog(null, prompt);
4 return Double.parseDouble(tempStr);
}
1
5
//=====================================================
1
displayString
6
// I/O convenience method to display a string in dialog box.
1 private static void displayString(String output) {
7 JOptionPane.showMessageDialog(null, output);
}
1
}
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
3
9
Methods 6 - Overloading
Purpose of this lesson:
Programming ideas
• The method name is important to the human programmer as the key to describing an
action to be performed.
• It's often useful to do the "same" action, but with different kinds of parameters.
• The compiler can distinguish methods that have the same name only if they have a
different number and / or type of parameters.
Here is a small program which simply computes the average of three numbers. It uses three
overloaded methods to read the numbers. For such a small program you would not use three
different methods, of course, but this shows how overloaded methods are defined and used. It's
very common for one overloaded method to call another. another variation of the program, this
time using three methods. Altho there is no real need for these methods in such a small program,
large programs are in fact composed of many small methods. It is the essential way that all code is
structured.
Each of the user-defined method names, both in the call and the definition, is hilited.
Good practices
• Coherence. It's important that all the methods do the "same" thing, so that the program is
human comprehensible. All methods sharing the same name should return the same value,
have the same side effects, and all be either static or instance methods. The language
doesn't require this, but doing otherwise is asking for trouble.
• Call each other. Because all overridden methods should be doing the same thing, it is very
common for there to be calls from one to another, supplying extra default parameter values
as required.
• Default parameter values. Some programming languages allow you to specify default
values for parameters, and if a the parameter is not supplied, the default value is used.
Java doesn't have default parameters, but you can easily implement them using overloaded
methods.
Example of overloading - averaging three values
// File : methods/avg3/AvgThreeOverloaded.java
// Description: Averages three numbers -- meaningless, but
1
// Purpose: Show an overloaded method, getDouble, with three
definitions,
2 // differing in the number of parameters.
// Issues : Input isn't checked for legality (non-null number)
because
3
// the point is to show overloading.
// Author : Fred Swartz - 2007-01-11 - placed in public domain
4
import javax.swing.*;
5
public class AvgThreeOverloaded {
6 //==============================================================
main
public static void main(String[] args) {
7
//... Read three numbers using the three different methods.
// Using three different methods is only to show
8 overloading.
double n1 = getDouble();
double n2 = getDouble("Enter the second number.");
9
double n3 = getDouble("Enter last number.", 0.0, 100.0);
1 double average = (n1 + n2 + n3) / 3.0;
0 displayString("Average is " + average);
}
1
1
//=========================================================
1 getDouble
2 // I/O convenience method to read a double value.
// This version of the getDouble method simply calls on
1
another
3
// version passing it a generic input message.
1 private static double getDouble() {
4 return getDouble("Enter a number");
}
1
5
//=========================================================
1 getDouble
6 // I/O convenience method to read a double value given a prompt.
// This version of getDouble displays the user supplied
1
prompt.
7
private static double getDouble(String prompt) {
1 String tempStr;
8 tempStr = JOptionPane.showInputDialog(null, prompt);
return Double.parseDouble(tempStr);
1
}
9
2 //=========================================================
0 getDouble
// I/O convenience method to read a double value in a range.
2
// It builds a new prompt and calls another version to get
// the value, looping until a value in the range is found.
1
private static double getDouble(String prompt, double low, double
2 high) {
2 double result;
String rangePrompt = prompt + " Value must be in range "
2
+ low + " to " + high;
3
2 //... Read and loop back if the number is not in the right
4 range.
do {
2
result = getDouble(rangePrompt);
5
} while (result < low || result > high);
2
6 return result;
}
2
7
//=====================================================
2 displayString
8 // I/O convenience method to display a string in dialog box.
private static void displayString(String output) {
2
JOptionPane.showMessageDialog(null, output);
9
}
3 }
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
3
9
4
0
4
1
4
2
4
3
4
4
4
5
4
6
4
7
4
8
4
9
5
0
5
1
5
2
5
3
5
4
5
5
5
6
5
7
5
8
5
9
6
0
6
1
6
2
6
3
• Overview
o Classes combine data and methods.
o A class defines a data type.
o Advantage: Classes correspond to concepts in the problem domain.
o Advantage: Classes reduce complexity by increasing coherence and reducing
coupling.
• Introduce classes to store data in value objects.
Terminology
Historical development. Classes can also be used to store data. Historically, programming
languages had something similar to classes for grouping data, usually called structs or records.
These were used for storing only data, not methods. Eventually, advantages of combining both data
and the methods to work on that data were recognized.
Classes model problem. One advantage of encapsulating data and methods in a class is to make
programming objects that reflect "objects" in the problem domain. If your problem deals with
orders and products, then you'll very likely have classes called Order and Product.
Class, object, OOP. The name class was almost universally adopted for programming language
structure which combines data and methods, object is used for each instance of a class that is
created, and the practices that developed around these ideas is called Object-Oriented
Programming (OOP).
Value objects - Data-first approach. We'll start with classes that represent data, and then add
constructors and methods. Ultimately you will be more concerned with methods than data, and
you'll see how (and why) methods are used to completely hide the data implementation.
Student example. The information you would store about students, would be their name, id, etc.
We'll keep this example simple and just save name and id information.
Declare each field. A class contains declarations of the fields (instance variables, attributes) that
hold the data associated with a student. These declarations are like declaring a local variable in a
method, except that you will also specify the visibility. We'll start by using the visibility modifier
public, which lets anyone see them. For example, the following Student1 class can be used to
represent a student. As you go through these notes, we'll make improvements to this class.
A class is a type
Noun. Classes are usually given the name of a noun, and the fields (variables) in it are attributes
associated with that noun. Predefined Java classes that you have already used are String, which
contains the characters in the string and the length, JOptionPane, which contains information
necessary to produce a dialog box on the screen, etc. These predefined Java classes are used for
the programming infrastructure that you need. Many common infrastructure classes are available in
the 3000+ predefined Java library classes. But, of course, these don't address your problems.
Business objects. Most classes you define will concern your problem domain, where they
represent business objects (Student, TimeOfDay, Order, ...).
Declaring business object variables is like declaring any other variable. Use the class name as a
type, just as you've used String, int, etc. For example, the following declares two Student1
variables.
Student1 bestInClass; // This variable references a Student1 object.
Student1 t; // And here is another
These don't have values yet, but we'll do that in the next section.
Object-Oriented Design involves deciding which classes you need to represent the things
(entities) in your problem. For simple programs, you often use only simple variables, but as
programs get larger, you will define more and classes to represent the things you are working with.
// File : oop/dataclass/Student1.java
// Purpose: Information about a student.
Analogy: Cookie cutter and cookies. A cookie cutter is like a class definition. It isn't a cookie,
but can be used to create a cookie. Each cookie can will have the same attributes (shape), but each
cookie can have different values for the attributes (type of dough, thickness, ...).
Analogy: Dog and Fido. The concept of Dog is like a class, but there are many possible instances
of this class, eg, my dog Fido, or your dog Rover.
Analogy: Form stamp and filled out forms. There are rubber inkpad stamps that are used to
stamp out a small form. These have been used in several places in my passport, where passport
control stamped my passport, then filled out the fields with the date, how long I could stay, etc. The
rubber stamp is like a class, defining the fields. The filled out form in each passport are the objects,
with specific values for each field.
Student1 tatiana;
tatiana = new Student1(); // Create Student1 object with new.
Unlike local variables in a method, fields do have default values (like the default values in arrays).
Object references are null, numbers are zero, and booleans are false.
Access public fields with dot notation
The fields (firstName, lastName, id) name data which is stored in each object. Another term
for field is instance variable. All public fields can be referenced using dot notation (later we'll see
better ways to access and set fields). To reference a field, write the object name, then a dot, then
the field name.
Awkward? This simple example with one student is somewhat awkward, but we'll get to examples
that show real advantages soon.
It's not very interesting to create only one object of class, so the following example creates a couple
of them.
// File : oop/dataclass/TestStudent1.java
1
import javax.swing.*;
• Constructor syntax - like a method but with class name and implicit type/value.
Constructor Syntax
Similar to method. A constructor is similar to a method -- it's called like a method, has
parameters like a method, and it returns. But it must have the same name as the class for which it
is a constructor. Also, the type and return value are implicit.
// File : oop/dataclass/Student2.java
// Purpose: Information about a student. Defines constructor.
//======================================== constructor
public Student2(String fn, String ln, int idnum) {
firstName = fn;
lastName = ln;
id = idnum;
}
}
Note that a constructor has no return type and the name is the same as the class name.
Using the constructor
Here is the first program rewritten to use the above class definition with a constructor.
// File : oop/dataclass/TestStudent2.java
// Purpose: Tests Student2 constructor.
1
import javax.swing.*;
2
public class TestStudent2 {
public static void main(String[] args) {
3
Student2 tatiana;
Student2 pupil;
4
//... Create new Student2 object with new.
tatiana = new Student2("Tatiana", "Johnson", 9950842);
5
//... Create another Student2 object.
6 String first = JOptionPane.showInputDialog(null, "First
name");
String last = JOptionPane.showInputDialog(null, "Last
7
name");
int studID=
8 Integer.parseInt(JOptionPane.showInputDialog(null, "ID"));
pupil = new Student2(first, last, studID);
9
JOptionPane.showMessageDialog(null, "One student is named: "
1 + tatiana.lastName + ", " + tatiana.firstName
0 + "\n and another is named: "
+ pupil.lastName + ", " + pupil.firstName);
1
}
1
}
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
When you define a constructor, the Java compiler doesn't create a default constructor
if you define a constructor in a class, the Java compiler no longer automatically creates a default
(parameterless) constructor. All object creation therefore must use your explicitly defined
constructor. For example,
Student2 someone;
someone = new Student2(); // ILLEGAL. There is no default
constructor.
someone = new Student2("Michael", "Maus", 1); // OK. Must specify 3
values.
The constructor can check that all fields are defined with legal values. We're not going to extend the
Student2 class any further to test for legal values, but we will in the next example.
For the moment we'll leave the Student class, and move to something different to show the same
ideas.
Here are some of the basic building blocks of Objected-Oriented Programming that you will become
familiar with:
class
A collection of fields (instance and class variables) and methods.
instance variable (aka field variable or member variable
An instance variable is a variable that is defined in a class, but outside of a method. There
is one copy of the variable for every instance (object) created from that class.
A common problem is trying to reference an instance variable from a static method. A static
method (eg, main) can only reference static variables in its own class (or its own local
variables).
class variable (aka static variable)
A class variable or static variable is defined in a class, but there is only one copy regardless
of how many objects are created from that class. It's common to define static final
variables (constants) that can be used by all methods, or by other classes. Color.blue is
an example of a static final variable.
constructor
When an object is created, a constructor for that class is called. If no constructor is defined,
a default constructor is called. It's common to have multiple constructors taking different
numbers of parameters. Before a constructor is executed, the constructor for the parent
class is called implicitly if there is no parent constructor called explicitly on the first line.
inner class
If a class is defined within another class, it is an inner class. There are two common
reasons to do this: to attach an anonymous listener to a control at the point where the
control is being built, and to have access to the fields and methods of the enclosing class.
override (applies to methods)
If a subclass redefines a method defined in a superclass, the method in the superclass is
overridden. A common use of this is in defining a subclass of JPanel that you use for
graphics. When you define the paintComponent method, you are overriding the one that
is already defined in JPanel. In paintComponent, but not in most overriding methods, you
should call the method in the parent class with super.paintComponent. The "super"
keyword is how you refer to the overridden parent method. There is no way to explicitly call
the "grandparent's" method if it was overridden by the parent class.
overload (applies to methods)
A method in a class is overloaded if there is more than one method by the same name. If
the same name is used, the methods must different in the number and/or types of the
parameters so that there is no confusion. This really has nothing to do with classes, only
methods.
abstract class
A class which doesn't define all it's methods is called an abstract class. To be useful, there
must be a subclass which defines the missing methods. The "You must declare this class
abstract" error message from the Java compiler is rather misleading. This usually means
that you declared your class to implement an interface, but failed to write all required
methods -- or more commonly that there's a spelling error in a method header.
interface
An interface is a list of methods that must be implemented. A class that implements an
interface must define all those methods. The method signatures (prototypes) are listed in
the interface. Interfaces may also define public static final "constants". An interface is
essentially the same as an completely abstract class.
• Don't Fear the Oop! - A light hearted, but incomplete intro to OOP. By the late Johannes
Claerbout.
Constructors
When you create a new instance (a new object) of a class using the new keyword, a constructor for
that class is called. Constructors are used to initialize the instance variables (fields) of an object.
Constructors are similar to methods, but with some important differences.
• Constructor name is class name. A constructors must have the same name as the class
its in.
• Default constructor. If you don't define a constructor for a class, a default parameterless
constructor is automatically created by the compiler. The default constructor calls the
default parent constructor (super()) and initializes all instance variables to default value
(zero for numeric types, null for object references, and false for booleans).
• Default constructor is created only if there are no constructors. If you define any
constructor for your class, no default constructor is automatically created.
o There is no return type given in a constructor signature (header). The value is this
object itself so there is no need to indicate a return value.
o There is no return statement in the body of the constructor.
o The first line of a constructor must either be a call on another constructor in the
same class (using this), or a call on the superclass constructor (using super). If
the first line is neither of these, the compiler automatically inserts a call to the
parameterless super class constructor.
These differences in syntax between a constructor and method are sometimes hard to see
when looking at the source. It would have been better to have had a keyword to clearly
mark constructors as some languages do.
• this(...) - Calls another constructor in same class. Often a constructor with few
parameters will call a constructor with more parameters, giving default values for the
missing parameters. Use this to call other constructors in the same class.
• super(...). Use super to call a constructor in a parent class. Calling the constructor for
the superclass must be the first statement in the body of a constructor. If you are satisfied
with the default constructor in the superclass, there is no need to make a call to it because
it will be supplied automatically.
//============ Constructor
public Point(int x, int y) {
m_x = x;
m_y = y;
}
An object has the fields of its own class plus all fields of its parent class, grandparent class, all the
way up to the root class Object. It's necessary to initialize all fields, therefore all constructors
must be called! The Java compiler automatically inserts the necessary constructor calls in the
process of constructor chaining, or you can do it explicitly.
The Java compiler inserts a call to the parent constructor (super) if you don't have a constructor
call as the first statement of you constructor. The following is the equivalent of the constuctor
above.
//============ Constructor (same as in above example)
public Point(int x, int y) {
super(); // Automatically done if you don't call constructor
here.
m_x = x;
m_y = y;
}
Normally, you won't need to call the constructor for your parent class because it's automatically
generated, but there are two cases where this is necessary.
1. You want to call a parent constructor which has parameters (the automatically generated
super constructor call has no parameters).
2. There is no parameterless parent constructor because only constructors with parameters
are defined in the parent class.
Constructor Puzzle
This class compiles without a problem
/////////////////// class WITHOUT a parameterless
constructor.//////////////////
1
class Parent {
2 int _x;
6
7
Hint
The error message from the compiler is:
Child.java:5: cannot find symbol symbol : constructor Parent()
But you defined a constructor for Parent, and anyway, you didn't even call the Parent constructor,
so what's the problem with line 5?
Before you can initialize an object in a constructor, the object's parent constructor must be called
first. If you don't write an explicit call to the super() constructor, Java automatically inserts one in
your constructor. The compiler automatically inserts superclass constructor calls in both
constructors.
Parent(int x) {
super(); // Compiler inserts this statement to call Object().
_x = x;
}
This is fine because there is a parameterless constructor for Object. However, when the Child
class constructor is modified to call its superclass constructor, there's a problem.
Child(int y) {
super(); // Compiler inserts this statement to call Parent().
_y = y;
}
No parameterless constructor
The problem is that the Parent class has no parameterless constructor. When any constructor is
explicitly defined (as in Parent above), the compiler no longer produces a default parameterless
constructor.
Usually the best solution is for the subclass constructor to explicitly call the superclass constructor
so that its fields are correctly initialized.
Child(int y) {
super(-666); // Make explicit call to superclass constructor.
_y = y;
}
But no invalid values please. Advice you will sometimes see is to always define a parameterless
constructor, so that this problem doesn't occur. But an essential element of data encapsulation is
that the value of a object can be guaranteed to be a legal value. A constructor insures that the
initial value of an object is valid. Many objects can't be given a valid value with a default
constructor. This peculiar semantic-free example Parent class might be changed to have a
parameterless constructor as follows (supposing that a value of -666 makes sense for this class):
It's common to have a class with no legal default values. For example, what should the default
constructor do for this class?
If you defined a default constructor for Student2, what would you assign to the fields - null for
the names and zero for the id? Whatever you choose it's illegal. There are setters so you hope that
the user will set the fields to legal values. Or you will check for the illegal initial values and throw an
exception or give some other error when there is an attempt to use them. Perhaps there are times
when this is acceptible in a small one-person project, but it's a disaster waiting to happen in
anything larger.
If no constructor call is written as the first line of a constructor, the compiler automatically inserts a
call to the parameterless superclass constructor.
Question
// File : ConstructorChain.java
// Purpose: Illustrate constructor chaining.
// Author : Fred Swartz
// Date : 5 May 2003
class ConstructorChain {
public static void main(String[] args) {
Child c = new Child();
}
}
Parent(int x) {
System.out.println("Parent(" + x + ") constructor");
}
}
class Grandparent {
Grandparent() {
System.out.println("Grandparent() constructor");
}
}
Interfaces
An interface is a list of methods that must be defined by any class which implements that
interface. It may also define constants (public static final).
Similar to abstract class. An interface is similar to a class without instance and static variables
(static final constants are allowed), and without method bodies. This is essentially what a
completely abstract class does, but abstract classes do allow static method definitions, and
interfaces don't.
Contractual obligation. When a class specifies that it implements an interface, it must define all
methods of that interface. A class can implement many different interfaces. If a class doesn't define
all methods of the interfaces it agreed to define (by the implements clause), the compiler gives an
error message, which typically says something like "This class must be declared abstract". An
abstract class is one that doesn't implement all methods it said it would. The solution to this is
almost always to implement the missing methods of the interface. A misspelled method name or
incorrect parameter list is the usual cause, not that it should have been abstract!
A very common use of interfaces is for listeners. A listener is an object from a class that
implements the required methods for that interface. You can create anonymous inner listeners, or
implement the required interface in any class.
Interfaces are also used extensively in the data structures (Java Collections) package.
This analogy fails in one way however. Capabilities (methods) of a class are unchanging (if a class
implements an interface, it is implemented for all instances), whereas the human skills we're talking
about are dynamic and can be learned or forgotten. The analogy is flawed, as all analogies are, but
it gives some idea of a distinction between classes and interfaces.
Simpler. A C++ class can have more than one parent class. This is called multiple inheritance.
Managing instance variable definitions in multiple inheritance can be really messy, and leads to
more problems (eg, the "Deadly Diamond of Death") than solutions. For this reason Java designers
chose to allow only one parent class, but allow multiple interfaces. This provides most of the useful
functionality of multiple inheritance, but without the difficulties.
Implementing an Interface
You may implement as many interfaces in a class as you wish; just separate them with commas.
For example,
// Note:
// ActionListener requires defining actionPerformed(...)
// MouseMotionListener requires defining mouseMoved(...) and
mouseDragged(...).
For simple programs you are more likely to use an interface than define it. Here is what the
java.awt.event.ActionListener interface definition looks something like the following.
public interface ActionListener {
public void actionPerformed(ActionEvent e);
}
Tagging Interfaces
Java defines a few interfaces that are just used as a boolean property of a class, but don't actually
require the implemenation of any methods. These are called tagging interfaces.
Tagging interfaces are an abuse of the interface principle, but Java makes use of object-oriented
features to solve all problems if possible, rather than invent a more appropriate feature.
Cloneable Implementing this interface indicates that the class has overridden Object's
clone() method. But there is no check that this is true, and because subclasses
inherit interfaces, it will look like all subclasses have defined clone() altho that is
not necessarily true. Yes, this is not the normal spelling of the English word. ???
Why needed.
Serializable This tagging interface indicates that a class can serialized - that an object of this
class can be written out and read back in using ???. This can be useful for short-
term storage of objects, but should not be used for long-term storage because any
change to the class definition makes that persistent copy unreadable!
Enums
Problem: How to represent a set of named constant values. First we'll look at the "old" Java
solution, then see how Java 5 enums substantially improve the situation.
Just define a number of public static final int constants. For example:
//... Constants to represent possible shapes.
public static final int RECTANGLE = 0;
public static final int CIRCLE = 1;
public static final int LINE = 2;
...
int drawing = RECTANGLE; // But any int could be assigned.
These values can then be assigned to an integer variable, and can be used in switch statements.
This style is useful, but is not a great solution.
• Allows illegal values. Any variable containing one of these values could also be assigned
any integer value, although there are only three legal choices. Eg,
drawing = 99; // Illogical value, but allowed by compiler.
• Updates not reflected in other code. If there are additions, deletions, or reorderings,
code from other classes will not automatically be readjusted to reflect these changes. All
code that uses these definitions would have to be recompiled.
• No easy I/O. To convert values to and from a string form requires maintaining an
additional array and lookup code.
• Fragile for loops. There is no obvious first and last value so iterating over all values is
subject to errors which are not diagnosed at compile time if the values are rearranged,
deleted, or added to. There is no way to use the enhanced for loop.
• No behavior. This style is pre-OOP -- there are values, but no behavior defined for them.
An enum type is a kind of class definition. The possible enum values are listed in the curly braces,
separated by commas. By convention the value names are in upper case.
The enum class name can be use like any other class type in declarations. Usually enum values
must be prefixed with the enum type name.
Switch statement
The switch statement was enhanced to allow a convenient use of enums. Note that the case
values don't have to be qualified with the enum class name, which can be determined from the
switch control value.
switch (drawing) {
case RECTANGLE: g.drawRect(x, y, width, height);
break;
case CIRCLE : g.drawOval(x, y, width, height);
break;
case LINE : g.drawLine(x, y, x + width, y + height);
break;
}
Each enum value in an enum class has an associated default value, starting with zero for the first
value and incrementing by one for each additional value. This may be accessed with the
ordinal() method.
Input
The valueOf() method can be used to convert a string value to an enum value. Here is an
example of reading in a Shape value from a Scanner object in.
drawing = Shape.valueOf(in.next());
Defining additional fields, methods, and constants for your enum type
Methods can be defined for an enum class, including defining a different method body for each of
the constants. See the Sun article for examples of this. If you are using switch statements with
cases for each of the enum constants, consider putting the code into the enum class.
The java.util.EnumSet class provides an efficient implementation of sets of enums as bit maps, or
powersets as they were called in Pascal. EnumSet can also generate an Iterable for use with subsets
in the for-each statement.
Further reading
• Enums is a good Sun overview of the Java enum features. It's very readable with good
examples.
• Example: PaintDemo is a small paint program which represents the shape with an enum. It
shows how to use an enum to represent simple constants, and also how to associate a
method with each constant.
• Class Enum<E extends Enum<E>> is the API documentation for the superclass of all
enums. You'll find useful methods in this class such as compareTo(...), ordinal(),
toString(), and valueOf(...). The addition of generics negated the former Java
claim to simplicity, and it's this Enum definition which is often used as an example of the
incomprehensible. It's hard to find anyone who understands this obscure declaration.
Fortunately, the use of enums doesn't require that that you know what this declaration
means.