Comments 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). Spaces and blank lines 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. /* ... */ comments -- multiple lines After the /* characters, Java will ignore everything until it finds a */. This kind of comment can cross many lines, and is commonly used to "comment out" sections of code -making Java code into a comment while debugging a program. For example, /* Use comments to describe variables or sections of the program. They are very helpful to everyone who reads your programs: your teacher, your boss, but especially yourself! */ javadoc comments Comments that start with /** are used by the javadoc program to produce HTML documentation for the program. The Java documentation from Sun Microsystems is produced using javadoc. It is essential to use this kind of comment for large programs. 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 Write Sweet-Smelling Comments by Mike Clark. Otaku, Cedric's weblog 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. Apple This is a different legal name. Uppercase implies it's a class or 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 Using Uppercase, Lowercase, and "Camelcase" Letters 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. Class and interface names - Start with uppercase Class and interface names start with an uppercase letter, and continue in lowercase. For multiple words, use camelcase. Eg, Direction, LogicalLayout, DebugGapSpacer. Variable and method names - Lowercase Lowercase is used for variable and method names. If a name has multiple words, use camelcase. Eg, top, width, topLeft, roomWidth, incomeAfterTaxes. Constants - All uppercase, use _ to separate words The names of constants (typically declared static final) should be in all uppercase. For example, BorderLayout.NORTH. When constant names are made from multiple words, use an underscore to separate words, eg, JFrame.EXIT_ON_CLOSE Readable names are more important than most comments 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 semireadable LogicalGapInfo topBorder = m_logicalLayout.getGapInfo(LogicalLayout.AXIS_V, 0); Could be translated into I001O I00I0 = O1001.OI001(O1OOI.IO010, 0); Packages and Import Package = directory. Java classes can be grouped together in packages. A package name is the same as the directory (folder) name which contains the .java files. You declare packages when you define your Java program, and you name the packages you want to use from other libraries in an import statement. 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. Package declaration syntax The statement order is as follows. Comments can go anywhere. 1. Package statment (optional). 2. Imports (optional). 3. Class or interface definitions. // This source file must be Drawing.java in the illustration directory. package illustration; import java.awt.*; public class Drawing { . . . } Imports: three options 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. import javax.swing.*; used. // Make all classes visible altho only one is 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. import javax.swing.JOptionPane; // Make a single class visible. class ImportTest { public static void main(String[] args) { JOptionPane.showMessageDialog(null, "Hi"); System.exit(0); } } Alternately we can the fully qualified class name without an import. 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 java.awt.*; Common GUI elements. import java.awt.event.*; The most common GUI event listeners. import javax.swing.*; More common GUI elements. Note "javax". import java.util.*; Data structures (Collections), time, Scanner, etc classes. import java.io.*; Input-output classes. import java.text.*; Some formatting classes. import java.util.regex.*; Regular expression classes. 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. 3. Q: Doesn't it provide better documentation to import each class explicitly? A: This shows good intentions, but ... 4. o It's hard to remember to remove classes when they are no longer used, so the import list is surprisingly often wrong. It can seriously slow down reading because unusual or unexpected class imports make me look for that class, only to discover that it must have been used in an earlier version. o Explicit class imports permit accidentally defining classes with names that conflict with the standard library names. This is very bad. Using "*" to import all classes prevents this dangerous naming accident. o It's annoying to always update this list, altho if you use NetBeans, fixing the list is only a click away (see below). Q: I've imported java.awt.*, why do I also need java.awt.event.*? A: The wildcard "*" only makes the classes in this package visible, not any of the subpackages. 5. Q: Why don't I need an import to use String, System, etc? A: All classes in the java.lang package are visible without an import. 6. Q: Is the order of the imports important? A: No. Group them for readability. NetBeans creates packages by default 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. NetBeans will create your imports If you forgot to write import statements, or don't remember which package a class is in, no problem. Just right click on the source file and choose Fix Imports. It will add all necessary import statements. Static imports in Java 5 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! The Many Meanings of final The final modifier can be applied to four Java constructs: 1. variables: a final variable can be set once and only once. 2. fields: a final field can also be set only once, by the constructor of the class which defines it. 3. methods: a final method cannot be overridden nor hidden. 4. classes: a final class cannot be extended. 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. Anonymous Local Classes The second situation involving final variables is actually mandated by language semantics. In that situation, the Java compiler won't let you use a variable unless it is declared final. This situation arises with closures, also known as anonymous local classes. Local classes can only reference local variables and parameters that are declared final. public void doSomething(int i, int j) { final int n = i + j; // must be declared final Comparator comp = new Comparator() { public int compare(Object left, Object right) { return n; // return copy of a local variable } }; } 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 class MyClass { private final int i; 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 compiletime. 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. Aggregation vs. Acquaintance In the words of Gamma et al.'s Design Patterns: Aggregation implies that one object owns or is responsible for another object. Generally we speak of an object having or being part of another object. Aggregation implies that an aggregate object and its owner have identical lifetimes. Acquaintance implies that an object merely knows of another object. Sometimes acquaintance is called "association" or the "using" relationship. Acquainted objects may request operations of each other, but they aren't responsible for each other. Acquaintance is a weaker relationship than aggregation and suggests much looser coupling between objects. It's easy to confuse aggregation and acquaintance, because they are often implemented in the same way. Ultimately, acquaintance and aggregation are determined more by intent than by explicit language mechanisms. Aggregation relationships tend to be fewer and more permanent than acquaintance. Acquaintance, in contrast, are made and remade more frequently, sometimes existing only for the duration of an operation. Acquaintances are more dynamic as well, making them more difficult to discern in the source code. As it turns out, the Java language does offer an explicit mechanism to differentiate aggregation relationships from mere acquaitances: the object of this article, the keyword final. Use it to flag and make explicit aggregations. But why should this be important to you? The short answer is: to improve code quality. Enforce Atomicity of Object Creation Once a field is determined to be an aggregation of another object, and it is declared final, an interesting property emerges. The aggregating object is guaranteed to be created in full, or it won't be created at all; either all final fields are initialized successfully, or an exception terminates the constructor. Say an object Car aggregates another object Engine, and therefore is defined as absolutely requiring an Engine instance to function. Declaring the reference to the Engine as final ensures any Car instance is correctly initialized in full – or the constructor was terminated abruptly by a thrown exception. The Car class doesn't even compile without the Engine reference being initialized. public class Car { private final Engine engine; // always has an engine 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 reinitialization 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. Conclusion on Final Fields Extensive use of final fields leads to a new and interesting programming idiom. By statically enforcing field initialization at construction time, objects can be designed to be correct, fully initialized, once their construction is complete. Doing so is a simple yet powerful way to increase both the correctness and robustness of a given object: since it cannot fail to be correctly initialized, subsequent methods are free to deal with their own processing, and use whatever fields they need to do said processing, without concern for the correct initialization sequence of the object. This idiom strongly relates to eager initialization: all fields are initialized as soon as possible, at construction, and never changed once the initialization phase is over. In my experience, developers shun eager initialization because it is perceived as more expensive than lazy initialization. "I don't need this field until later, so let's not bother with it now," their thinking goes. Unfortunately, this line of thinking leads to more complex code that simply initializing all fields right away. Every usage of the field has to check whether the field has been initialized, and initialize it if it hasn't. It's akin to premature optimization, which, as we all know, is the root of all evil. Compare the two following examples. While it may look like a trivial transformation, in a real class with potentially dozens of fields, eager initialization will clear up a lot of code by removing extraneous tests. By declaring all fields final, initialization is gathered in one place (the constructor), yielding simpler, more maintainable, code. public class LazyCar { private Engine engine; // lazily initialized public void drive() { if (engine == null) { engine = new Engine(); } // ... } } public class BetterCar { private final Engine engine = new Engine(); // using final public void drive() { // the engine is always present // ... } } 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. Enforce Invariant Code The Template Method pattern declares an abstract method solely for the purpose of overriding it in a subclass. This allows the base class to delegate parts of an algorithm to subclasses. Final methods cannot be overridden, therefore they create an almost exact anti-"template method" pattern. But in fact, they are best used in conjunction with template methods. By specifying explicitely which parts of the algorithm can vary (using abstract methods) and which cannot (using final methods), the class's author conveys a precise picture of the work expected by subclasses. Final methods are used with template methods to declare the invariant parts of an algorithm. public abstract class AbstractBase { public final void performOperation() { prepareForOperation(); doPerformOperation(); } // cannot be overridden protected abstract void doPerformOperation(); // must override } 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. Enforce Composition over Inheritance Since final classes cannot be extended, the only way to reuse them is by composing them with other objects. And encouraging that practice in your own code might prove very healthy; inheritance, while a powerful technique that should not be dismissed, has it own share of issues. It introduces a very tight coupling between classes, sometimes leading to the infamous Fragile Base Class problem. It is also more complex, forcing users to bounce up and down a class hierarchy in order to understand what a given class does. And finally, it can break encapsulation by allowing less restrictive access to methods. Thus final classes are used to enforce composition. This is particularly important with core classes, classes that define the base functionality of a framework. We look at this case next. 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: they are simple to understand and easy to use they are inherently thread-safe: they require no synchronization they make great building blocks for other objects 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: 1. Declare all fields private final. 2. Set all fields in the constructor. 3. Don't provide any methods that modify the state of the object; provide only getter methods (no setters). 4. Declare the class final, so that no methods may be overridden. 5. Ensure exclusive access to any mutable components, e.g. by returning copies. 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. ... // Do these statements before. if (condition) { ... // Do this clause if the condition is true. } ... // Do these statements after. or ... // Do these statements before. if (condition) { ... // Do this clause if the condition is true } else { ... // Do this clause if the condition is false } ... // Do these statements after. Example - EvaluateScore.java This displays one of two messages, depending on an input value. 1 2 // Description: Evaluate a test score. Illustrates if statement. // File : if/EvalScore.java // Author: Fred Swartz - 2007-04-09 - Placed in public domain. import javax.swing.*; public class EvalScore { 3 4 public static void main(String[] args) {//... Input a score. String scoreStr = JOptionPane.showInputDialog(null, "Enter your score?"); int score = Integer.parseInt(scoreStr); 5 //... Create a message. String comment; // Message to the user. if (score >= 60) { comment = "Not so bad"; } else { comment = "This is terrible"; } 6 7 8 //... Output the message. JOptionPane.showMessageDialog(null, comment); 9 } } 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Flowchart representation of if statement The flow of execution in a program is sometimes represented by a flowchart. Flowcharts are sometimes a good way to outline the flow in a method, especially if it gets complex. They may be useful in user documentation, but most flowcharting is done in quick sketches, which are thrown away once the program is written. 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. 3. 4. 5. 6. String comment; // Message to the user. if (score < 60) { comment = "This is terrible"; } else { 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. 9. 10. String comment = "Not so bad; // Message to the user. if (score < 60) { 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. 13. 14. 15. 16. 17. 18. // BAD BAD BAD BAD BAD BAD BAD BAD BAD String comment; // Message to the user. if (score < 60) { comment = "This is terrible"; } if (score >= 60) { 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. 'else' Not Required 'else' is not required It is not necessary to have the else part of an if statement. Maybe only 50% of the time there is an else part. 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. public void paintComponent(Graphics g) { super.paintComponent(g); // draw background etc. if (marks < 50) { g.setColor(Color.red); } g.drawString("Score = " + marks, 10, 50); } When the paintComponent() method begins, the Graphics context g uses Color.black by default. Therefore there is no need to set the color to black. Braces are your friend Braces { } not required for one statement (but are always good) 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: // Legal, but dangerous. if (condition) Exactly one statement to execute if condition is true else Exactly one statement to execute if condition is false Examples showing what can go wrong A sample written with braces. //... Good style - Indented with braces. String comment = "Not so bad."; if (marks < 60) { comment = "This is terrible."; } System.out.println(comment); Without braces it's still correct, but not as safe. //... Less good style - Indented but without braces. String comment = "Not so bad."; if (marks < 60) comment = "This is terrible."; System.out.println(comment); What can go wrong? Q1: What does this "legal" version print? //... What does this print? String comment = "Not so bad."; if (marks < 60); comment = "This is terrible."; System.out.println(comment); 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. Q2: What's wrong with this? So your program is working OK without the braces and you decide to add a grade. The compiler is very happy with this, but you won't be. Why? //... What does this print? String comment = "Not so bad."; String grade = "A"; if (marks < 60) comment = "This is terrible."; grade = "F"; System.out.println("Your grade is " +grade); System.out.println(comment); 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. Other Java constructions use braces 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. 'if' Statement - Indentation Indent to make programs readable 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!). Example 1 - No indentation - BAD BAD BAD Here is the paintComponent() method from a previous page without indentation. This is small, so it's easy to see which statements are in the true and false parts. If the if statement is much larger, it will be unreadable without indentation. 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); } Example 2 - No indentation and no line breaks 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);} Statement - if inside if 'if' if inside if You can put an if statement inside another if statement. Nearest 'else' If you use braces, there is no problem with deciding which else goes with which if For example, if (age < 24) { if (height > 200) { c = Color.RED; } } else { c = Color.BLUE; } Because the true and false parts are both single statements, you might be tempted to omit braces and write: if (age < 24) if (height > 200) c = Color.RED; else // DANGER: which 'if' goes with this 'else' c = Color.BLUE; But this is WRONG, because 'else' always goes with the nearest 'if' when there are no braces. This code is the same as: if (age < 24) { if (height > 200) c = Color.RED; else c = Color.BLUE; } Advice: Always use braces on if statements These kinds of errors are very hard to find. This is another good reason to always use braces. Watch out for semicolons on your if statements 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. 'if' Statement - 'else if' style Series of tests It is common to make a series of tests on a value, where the else part contains only another if statement. If you use indentation for the else part, it isn't easy to see that these are really a series of tests which are similar. It is better to write them at the same indentation level by writing the if on the same line as the else. Example -- series of tests - cascading ifs 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); } } } } Example -- using 'else if' style for formatting Here is the same example, using a style of writing the if immediately after the else. This is a common exception to the indenting rules, because it results in more readable programs. Note that it makes use of the rule that a single statement in one of the Java clauses doesn't need braces. 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. switch Statement - Overview Purpose of switch: select one of many possible statements to execute The if statement allows you to select one of two sections of code to execute based on a boolean value (only two possible values). The switch statement allows you to choose from many statements based on an integer (including char) or enum value. Syntax example 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. String comment; // The generated insult. int which = (int)(Math.random() * 3); // Result is 0, 1, or 2. 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. Error-prone. It is error-prone and a common source of bugs - forgetting break or default silently ignores errors. Some languages have eliminated these dangerous situations. switch Example - Random Insults The following class could be useful for generating random insults in response to erroneous user input. Source code formatting. Some of the cases are formatted on a single line. This is a common style when they do similar short actions. It makes the switch statements much easier to read. 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. Random Insult Model 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. 1 2 3 4 5 6 7 8 9 10 11 // // // // // // // // // // // // // // // // // File : flow-switch/insult/InsultGenerator1.java Purpose: Generates random insults. Author : Fred Swartz 2006 Aug 23 Placed in public domain Comments: This switch statements were written in the most conservative style -- a default clause and no returns in them. The structure of the random generation is entirely in executable code, A much better way to write this is as a data-Driven program, where this information is represented by data structures, with a simple program to process the data. The data-driven style allows the data to be read in from user-editable files for example, so the program need not be recompiled for changes. 12 13 14 15 16 17 18 19 20 21 public class InsultGenerator1 { //============================================ badInputInsult public static String badInputInsult() { String insult; switch (rand(2)) { case 0: insult = "What kind of " + infoAdjective() + " " + infoNoun() + " is this, you " + personAdjective() + " " + person() + "?"; break; 22 case 1: insult = "Never enter this kind of " + infoAdjective() + " " + infoNoun() + " again!!!!"; break; 23 24 25 26 default:insult = "Oops -- bad switch statement"; } return insult; 27 28 29 30 } //==================================================== person 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 private static String person() { String name; switch (rand(3)) { case 0 : name = "idiot" ; break; case 1 : name = "imbecile"; break; case 2 : name = "moron" ; break; default: name = "bad value from person???"; } return name; } //=========================================== personAdjective private static String personAdjective() { String adj; switch (rand(4)) { case 0 : adj = "clueless"; break; case 1 : adj = "witless" ; break; case 2 : adj = "stupid" ; break; case 3: adj = "hopeless"; break; default: adj = "bad value from infoAdjective???"; } return adj; } //============================================= infoAdjective private static String infoAdjective() { String adj; switch (rand(5)) { case 0: adj = "revolting" ; break; case 1: adj = "insulting" ; break; case 2: adj = "meaningless"; break; case 3: adj = "useless" ; break; case 4: adj = "idiotic" ; break; default:adj = "bad value from infoAdjective???"; } return adj; } //================================================== infoNoun private static String infoNoun() { String noun; switch (rand(4)) { case 0: noun = "nonsense"; break; case 1: noun = "crap" ; break; case 2: noun = "swill" ; break; case 3: noun = "garbage" ; break; default:noun = "bad value from infoNoun???"; } return noun; } //===================================================== rand // Utility method to generate random numbers in range 0..bound- 66 1. // Starting the range at zero was simply to match the typical // Java ranges (eg, switch, subscripts) that start at zero. // Returns random int in range 0...bound-1 private static int rand(int bound) { return (int) (Math.random() * bound); } 67 68 69 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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // // // // // File : Purpose: Author : License: Date : flow-switch/insult/TestTextGenerator1.java Show some random insults. Fred Swartz public domain 2006 May 3 import javax.swing.*; public class TestTextGenerator1 { public static void main(String[] args) { String display; do { display = InsultGenerator1.badInputInsult() + "\n\nWould you like another opinion?"; } while (JOptionPane.showConfirmDialog(null, display) == JOptionPane.YES_OPTION); } } 17 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. 2. 3. 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 private static String chooseRandom(String[] words) 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); for statement - Combines three parts 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); do..while statement - Test at end When you want to test at the end to see whether something should be repeated, the do..while statement is the natural choice. String ans; do { . . . ans = JOptionPane.showInputDialog(null, "Do it again (Y/N)?"); } while (ans.equalsIgnoreCase("Y")); "foreach" statement - Java 5 data structure iterator 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"}; //... Display array of names in a JTextArea. for (String s : names) { nameTextArea.append(s); nameTextArea.append("\n"); } Similar to the 'if' statement There are three general ideas that you will see in many parts of Java. Braces {} to enclose multiple statements in the body. Indentation to show the extent of the body clearly. Boolean (true/false) conditions to control whether the body is executed. Scope of loop indicated with braces {} 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 } Condition is true or false The value of condition must be true or false (ie, a boolean value). It is often a comparison (see example below). Example: Loop continues while the condition is true public void paintComponent(Graphics g) { super.paintComponent(g); int count = 0; while (count < 50) { g.drawLine(20, count*5, 80, count*5); count = count + 1; } g.drawString("Loop is finished. count="+count, 10, 300); } This repeats the drawLine() call 50 times. The first time the while condition is tested, it is true because the value of count is 0, which is less than 50. After the statements in the body are done, the while loop comes back to the top of the loop and makes the test again. Each time the value of count is larger. Finally, count is 50, and the value of the condition will be false. When the loop stops, the program continues with the statement after the end of the loop (the drawLine() call). This will display the string "Loop is finished. count=50". Example with flowchart The following shows some code and the equivalent flowchart. int n = 0; int i = 1; while (i < 4) { n++; i++; } . . . Here is another example of code and an equivalent flowchart int n = 0; int i = 1; while (i < 4) { int j = 1; while (j<=i) { n += 1; j++; } i = i + 1; } '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 The for and equivalent while statements have these forms. for (init-stmt; condition; nextstmt) { init-stmt; while (condition) { body body next-stmt; } } There are three clauses in the for statement. 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. Example - Printing a table of squares 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)); } Example - Counting doubled characters 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. // Start at second char (index 1). for (int pos = 1; pos < sentence.length(); pos++) ( // Compare each character to the previous character. if (sentence.charAt(pos) == sentence.charAt(pos-1)) { doubleCount++; } } Summary 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. For-each loop Equivalent for loop for (type var : arr) { body-of-loop } for (int i = 0; i < arr.length; i++) { type var = arr[i]; body-of-loop } for (type var : coll) { body-of-loop } for (Iterator<type> iter = coll.iterator(); iter.hasNext(); ) { type var = iter.next(); body-of-loop } Example - Adding all elements of an array Here is a loop written as both a for-each loop and a basic for loop. double[] ar = {1.2, 3.0, 0.8}; int sum = 0; for (double d : ar) { // d gets successively each value in ar. sum += d; } And here is the same loop using the basic for. It requires an extra iteration variable. double[] ar = {1.2, 3.0, 0.8}; int sum = 0; for (int i = 0; i < ar.length; i++) { successively. // i indexes each element sum += ar[i]; } Where the for-each is appropriate 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. Only forward. It's possible to iterate only forward by single steps. At least Java 5. Don't use it if you need compatibility with versions before Java 5. Example: String reverse The following program reverses a string in a very straightforward, but rather inefficient way. When you learn about StringBuilder (or the equivalent StringBuffer), you can do this more efficiently. But the purpose of this is to see how looping over a string works. Nested loops. There are two nested loops in the is program, the outer while loop reads more input. The inner for loop gets every character from the input string starting at character 0. 1 2 3 // // // // // // // // File : loops/reverse/Reverse.java Purpose: Reverse a string using a loop. Author : Fred Swartz Date : Oct 23 2005 Comments: Building a String one character at a time is very inefficient because it requires creating a new object for each concatenation. StringBuilder is better, and it already // has a reverse() method! 4 import javax.swing.*; 5 public class Reverse { public static void main(String[] args) { 6 7 8 9 String input; // Used for the input string. String reversed; // Reversed form or the input string. while (true) { input = JOptionPane.showInputDialog(null, "Enter a string"); if (input == null) break; 10 11 reversed = ""; for (int i=0; i<input.length(); i++) { reversed = input.substring(i, i+1) + reversed; } JOptionPane.showMessageDialog(null, "Reversed:\n" + 12 reversed); } } 13 } 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 While loop vs For loop Counting. A for loop is preferred to a while loop when counting through a series of numbers -in this case all character positions in a string. Equivalent. A for loop has the same condition as the equivalent while loop, but also incorporates an initialization, which would be before the while statement, and the increment, which would be at the end of the while body. You can write the loop either way, but putting the initialization, condition, and increment in one statement increases the readability. For loop for (int i=0; i<input.length(); i++) { reversed = input.substring(i, i+1) + reversed; } While loop int i = 0; while (i<input.length()) { reversed = input.substring(i, i+1) + reversed; i++; } A single character - String or char? This program uses substring(...) to get a single character. It would be more efficient to use charAt(...), which returns a single primitive char value. for (int i=0; i<input.length(); i++) { reversed = input.charAt(i) + reversed; } 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. Two forms of the assert statement. Usual form 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."; assert connector != null : "merge: Connector null for " + rel; When asserts are enabled (more on that below), the assert statement checks the condition (queue empty, connector is not null, etc) which must be true for the program to function correctly.. If it's true, execution continues. If it's null, an exception containing the message is thrown. This message is for the programmer, so it doesn't have to be user friendly. I typically include the name of the method and sometimes other information that will help make sense of the error. 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; How to figure out if assertions are turned on Try this program to see if assertions are turned on. 1 2 /** flow-assertion/AssertTest.java - test assertions. * @author Fred Swartz * @version 1.01 2005-10-03 * Compile: javac AssertTest.java * Run : java -ea AssertTest */ 3 4 5 6 class AssertTest { //=========================================================== main public static void main(String[] args) { // The following assert statement will stop execution // with a message if assertions are turned on. assert false : "Assertions are turned on."; // The following statement will only be printed if // assertions are turned off because assertions // were not allowed at run time by the -ea parameter. System.out.println("Assertions are not active."); 7 8 } } 9 10 11 12 13 14 15 16 17 18 19 20 Test for consistency 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. Check for "impossible" conditions, not bad input assert shouldn't be used for checking for bad input. Input should be checked by code that gives the user a meaningful response and perhaps a chance to correct the input. 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". Enabling assertions when running in NetBeans or TextPad 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. See the TextPad Editor description for how to enable assertions. Shouldn't runtime assertion checking default on? 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 Java throws an exception 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. try...catch statement catches exceptions 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 Common Exceptions To Catch 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. InputMismatchException IOException A Scanner method, eg nextDouble() will throw this exception when the next input text is not the right type, eg double. 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. Suggestions for catching exceptions If you catch an exception, do something. Don't silence exceptions. Some programs catch exceptions, then do nothing with them. This is almost always a mistake, and the underlying error should be fixed. 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. } Another example where exceptions are typically ignored is in calls to sleep. 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. Printing the call stack 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. Use exceptions for exceptional conditions, NOT normal control flow 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. Readability. Experienced programmers expect exceptions to have something to do with errors, so it is very uncomfortable to read code where it is used for normal flow. A programmer has to stop and examine the code in the try clause to see what might have caused the exception. 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). Example: Test for end of array index range Good int[] a = new int[1000]; for (int i=0; i < a.length; i++) { a[i] = i; } BAD int[] a = new int[1000]; try { for (int i=0; ; i++) { // No range check. a[i] = i; } } catch (ArrayIndexOutOfBoundsException e) { } You might wonder how inefficient this is because the loop must compare the index with the array size 1000 times, but only the final test is important. Because Java always checks the subscript range anyway, why not Exceptions are so slow that this won't be faster unless make use of its check? the array is extremely large (much, much larger than 1000). Avoiding edges in looking for adjacent array cells. Problem: You must invert the values in a cell in a rectangular grid and its non-diagonally adjacent cells. The difficulty is in dealing with the edge cases, where you must avoid referencing non-existent adjacent cells. 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 cell[col ][row ] = try { cell[col+1][row ] = {} try { cell[col-1][row ] = {} try { cell[col ][row+1] = {} try { cell[col ][row-1] = {} } col) { !cell[col][row]; !cell[col+1][row ];} catch(Exception e) !cell[col-1][row ];} catch(Exception e) !cell[col ][row+1];} catch(Exception e) !cell[col ][row-1];} catch(Exception e) // Much better (faster and less worrisome to the normal reader) public void flipB(int row, int col) { cell[col ][row ] = !cell[col ][row ]; if (col < SIZE-1) cell[col+1][row ] = !cell[col+1][row ]; if (col > 0 ) cell[col-1][row ] = !cell[col-1][row ]; if (row < SIZE-1) cell[col ][row+1] = !cell[col ][row+1]; if (row > 0 ) cell[col ][row-1] = !cell[col ][row-1]; } Another solution to avoid edge cases is to define extra rows and columns of boundary cells, and translate the subscripts, thereby replacing the if tests with two additions. This requires translating subscript references in all methods. If the class is properly encapsulated, users of the class will not know about it. private boolean[][] cell . . . public void flipC(int r, int row = r + 1; int col = c + 1; cell[col ][row ] = cell[col+1][row ] = cell[col-1][row ] = cell[col ][row+1] = cell[col ][row-1] = } = new boolean[SIZE+2][SIZE+2]; int c) { !cell[col ][row ]; !cell[col+1][row ]; !cell[col-1][row ]; !cell[col ][row+1]; !cell[col ][row-1]; Other examples There are numerous cases in addition to subscription where the use of exceptions is entirely inappropriate. Danger from the intermediate layers - finally 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 Exception-Handling Antipatterns by Tim McCune, today.java.net/pub/a/today/2006/04/06/exception-handling-antipatterns.htm, is a good article if you're ready for some advanced exception usage. Three Rules for Effective Exception Handling by Jim Cushing, http://today.java.net/pub/a/today/2003/12/04/exceptions.html, has some useful "rules", but even more useful is the list of links what was posted in response to this article. Throwing Exceptions Prev: Exceptions Throwing predefined 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. Defining your own exceptions 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: Basic purpose of methods. Term: call = Execution proceeds to the code in a method. Term: return = Execution of a method finishes and then continues after point of call, possibly using a value form the method. Term: static method = Method requiring no extra object. Term: instance method = Method that operates on the object before the dot. New Java language features Static call syntax: className.methodName( arguments ) Instance call syntax: object.methodName( arguments ) Basic idea - A named group of statements - Verbs By now you have used a lot of the predefined library methods, and written many main methods. This chapter explains methods in more detail. 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. Business analogy - services provided by an organization You could think of classes as corresponding to departments in an organization, and methods as being the services they provide. Let's take an example of calling the telephone information service to get someone's phone number. When you make the call, you pass information, the name of the person whose number you want, to the method (information service). This called "method" then does something, and returns a value to you (the desired phone number). Just as you don't have to know how the information service performs its job, you typically don't need to know exactly how a method does its work, unless of course, you are writing it. 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. Terms: call and return Call. When a method call is encountered in a program, the program remembers where it was and execution goes to the method (calls the method). After a small amount of initialization, the statements in the method are executed starting at the beginning. Return. When the end of the method is reached or a return statement is executed, the method returns to the where it was called from, and execution continues in the calling method from that point. A method may return a value (eg, parseDouble) or not (showMessageDialog). The callreturn terminology is almost universal. Static (class) methods Static. This starts with static (also called class) methods because all applications start with the static method main, and many of the early library methods that you use are static methods. Static methods are different than instance methods because they don't have an extra object passed to them. Instance methods are associated with an object (an "instance" of a class). 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. 1 2 3 4 5 6 7 8 9 10 11 12 13 // File : // Purpose: output. // Author : // Date : methods/KmToMiles.java Convert kilometers to miles. Use JOptionPane for input / Fred Swartz 22 Apr 2006 import javax.swing.*; public class KmToMiles { //============================================================ constants private static final double MILES_PER_KILOMETER = 0.621; //================================================================= main public static void main(String[] args) { //Note 1 //... Local variables String kmStr; // String km before conversion to double. double km; // Number of kilometers. double mi; // Number of miles. //... Input kmStr = JOptionPane.showInputDialog(null, "Enter kilometers."); km = Double.parseDouble(kmStr); //... Computation mi = km * MILES_PER_KILOMETER; //... Output JOptionPane.showMessageDialog(null, km + " kilometers is " + mi + " miles."); 14 } } 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 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. Identifying instance methods Object precedes. Instance method calls are identified in the following program. Note that they are all preceded by an object reference. This object is used by the methods to do their work. In this case, the objects are strings. In addition to supplying the object's data to the method, the class of the object, eg String, is where the method is defined. 1 2 3 // File : // Purpose: first use. // Author : // Date : dialog/capitalize/Capitalize2.java Capitalize first letter of each name. Declare with Fred Swartz - placed in public domain. 30 Mar 2006 import javax.swing.*; public class Capitalize2 { 4 5 public static void main(String[] args) { //.. Input a word String inputWord = JOptionPane.showInputDialog(null, "Enter a word"); 6 7 8 9 //.. Process - Separate word into parts, change case, put together. String firstLetter = inputWord.substring(0,1); // Get first letter String remainder = inputWord.substring(1); // Get remainder of word. String capitalized = firstLetter.toUpperCase() + remainder.toLowerCase(); 10 11 12 13 14 //.. Output the result. JOptionPane.showMessageDialog(null, capitalized); } } 15 16 17 18 19 20 21 22 What's before the dot tells whether it's a class or instance method What's before the dot? If it's a class name, then it's a static (class) method; if it's an object, it's an instance method. 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. Methods 2 - Actual arguments (parameters) Purpose of this lesson: Left-to-right argument evaluation Term: actual argument = value which is passed in a method call. Term: void method = method that doesn't return a value. Term: value-returning method = method that does return a value. Terms: actual argument, argument, actual parameter, parameter The values that are passed to a method are called actual arguments in the Java specification. However, it is very common for them to be called just arguments, actual parameters, or just plain parameters. These terms are so used interchangeably so often that even the Java specification isn't entirely consistent. For a value which is passed in a call I'll try to stick to actual argument or just argument, which are generally regarded as the "best" terms. Identifying method arguments When you call a method, you can pass information for it to use. These actual arguments are inside parentheses following the method name. Use commas to separate arguments if there is more than one. The previous program is shown below, but this time the arguments in the calls are highlighted. // File : // Purpose: / output. // Author : // Date : 1 2 3 metho Conve Fred 22 Ap 4 import javax.swin 5 6 public class KmTo //=========== constants private stati 7 8 9 10 //=============== main public static //... Loc String km double km double mi 11 12 13 14 15 //... Inp kmStr = J kilometers."); km = Doub 16 17 18 //... Com mi = km * 19 20 //... Out JOptionPa 21 22 } 23 Methods 3 - Defining a static method Purpose of this lesson: Show how to define a method. Explain parts of method header. Term: formal parameter = variable in method which gets the argument value. New Java language features } Syntax of method header Method header syntax A method header is the part of the method definition that occurs at the beginning. The following definition leaves out a few obscure features, but gives the syntax of ordinary method headers. See Syntax Notation to understand how to read the following. [visibility] ["static"] returnType methodName "(" [parameterList] methodHeader = visibility = "public" | "private" | "protected" . parameterList = parameterDeclaration {"," parameterList} . ")" . parameterDeclaration = type ParameterName . returnType = "void" | type How to define your own method The previous program is rewritten below to define a method to convert from kilometers to miles. The method call, and the first line (header) of the method definition are highlighted. // File : // Purpose: 1 JOptionPane // 2 // Author : // Date : 3 methods/KmToMilesMethod.java Convert kilometers to miles using a method. IO. Highlight call and method definition header. Fred Swartz 22 Apr 2006 import javax.swing.*; 4 public class KmToMilesMethod { //============================================================ constants 5 private static final double MILES_PER_KILOMETER = 0.621; 6 //================================================================= main 7 public static void main(String[] args) { //... Local variables 8 String kmStr; // String km before conversion to double. double km; // Number of kilometers. double mi; // Number of miles. 9 10 11 //... Input kmStr = JOptionPane.showInputDialog(null, "Enter kilometers."); km = Double.parseDouble(kmStr); //... Computation mi = convertKmToMi(km); 12 //Note 1 13 //... Output JOptionPane.showMessageDialog(null, km + " kilometers is " + mi + " miles."); 14 } 15 //========================================================= convertKmToMi private static double convertKmToMi(double kilometers) 16 { //Note 2 double miles = kilometers * MILES_PER_KILOMETER; 17 return miles; } 18 } 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 Notes 1. 2. 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. 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. Anatomy of the convertKmToMi method header We'll take a look at each of the parts of the method header in order. Visibility - public, private, or package private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; } For greatest reliability and flexibility in your programs, you should always give methods the lowest visibility to others that you can. 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. Class (static) or instance method private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; } A method should be declared static if it doesn't user instance variables or methods. A static method must use only only parameters, local variables, and static constants, and other static methods in the same class. If the static keyword is omitted, the method will be an instance method. This example uses static, but soon you will learn about instance methods too. Return type private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; } Method name private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; } Method names should begin with a lowercase letter. Method names are typically verbs, whereas variable names are usually nouns. 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; } Order of method definitions doesn't matter If you define multiple methods in a class, you don't have to worry about the order of the definitions, unlike some other languages. 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. Void and value-returning methods A method may return a value. In the example above, showInputDialog returns a String and parseDouble returns a double value. These method calls can be used anywhere in an expression where a String or double value is required. Here they simply provide the value for the right side of an assignment. void. If a method has a "side effect", but doesn't produce a value, it is called a void method. The showMessageDialog method shows something to the user, but doesn't return a value, and is a void method. When a method is defined, you need to specify the keyword void if it doesn't return a value. You can see this on line 13 where the main method definition starts. Methods 4 - Local variables Purpose of this lesson: Local variables are declared within a method. Local variable lifetime is from method entry to method return. Local variable visibility is only within the method. Local variables have no initial value. Parameter variables are local variables initialized from the argument values. New Java language features final modifier to prevent assignment to parameters. Principles / Style Don't assign to parameter variables. 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. private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; } Visibility: Only in defining method No code outside a method can see the local variables inside another method. There is no need, or even possibility, of declaring a local variable with a visibility modifier -- local variables are automatically known only in the method itself. Lifetime: From method call to method return Local variables are created on the call stack when the method is entered, and destroyed when the method is exited. You can't save values in local variables between calls. For that you have to use instance variables, which you'll learn about a little later. Initial value: None Local variables don't have initial values by default -- you can't try to use their value until you assign a value. It's therefore common to assignment a value to them when they're declared. 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; miles. // Won't compile because nothing was assigned to } Parameters are preinitialized local variables Method parameters are basically implemented as local variables. They have the same visibility (none outside the method) and lifetime (created on method call, destroyed on method return). 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; } Style: Don't assign to a parameter You can assign to a parameter variable, just as you would to a local variable, but this is often considered bad style because it can deceive the casual reader in two ways: Unexpected meaning change.. Programmers assume parameter variables represent actual argument values. Assigning to parameters breaks that assumption. Doesn't change actual argument. Because formal parameter variables are really local variables, assigning new values to them doesn't have any effect on the actual parameters. However, in some programming languages assignment to a parameter can assign to the corresponding actual parameter (eg, C++ reference parameters). Therefore if you write an assignment to a formal parameter variable, it may mislead the careless programmer with a C++ background. Or the reader may pause and try to decide if you thought you were assigning to the actual argument. In either case it reduces the readability. 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; this, altho it works. // BAD - Don't do return kilometers; } Style: final keyword prevents assignment Some programmers recommend using the final keyword for each parameter. This prevents assignment to the parameter. Few programmers do this because it adds extra clutter, which in a different way reduces the readability. The use of self-restraint in assigning to parameters is usually suffcient, but specifying final isn't a bad idea. private static double convertKmToMi(final double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; } Methods 7 - How call works Purpose of this lesson: Examine the method call/return process in more detail. Term: call stack = Memory that is used to save return address and local variables. Term: stack frame = The storage on the call stack that is used by one method. New Java language features 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. Dynamic changes in the call stack memory allocation 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 main args kms miles main args kms miles 3 main args kms miles getDouble getDouble prompt prompt str str showInputDialog ??? 4 main args kms miles 5 main args kms miles getDouble getDouble prompt prompt str str 6 main args kms miles getDouble prompt str 7 main args kms miles 8 main args kms miles convertKmToMi kilometers miles parseDouble ??? Typical call sequence 1. 2. 3. 4. 5. Evaluate arguments left-to-right. If an argument is a simple variable or a literal value, there is no need to evaluate it. When an expression is used, the expression must be evaluated before the call can be made. Push a new stack frame on the call stack. When a method is called, memory is required to store the following information. o Parameter and local variable storage. The storage that is needed for each of the parameters and local variables is reserved in the stack frame. o Where to continue execution when the called method returns. You don't have to worry about this; it's automatically saved for you. o Other working storage needed by the method may be required. You don't have to do anything about this because it's handled automatically. Initialize the parameters. When the arguments are evaluated, they are assigned to the local parameters in the called method. Execute the method. After the stack frame for this method has been initialized, execution starts with the first statement and continues as normal. Execution may call on other methods, which will push and pop their own stack frames on the call stack. Return from the method. When a return statement is encountered, or the end of a void method is reached, the method returns. For non-void methods, the return value is passed back to the calling method. The stack frame storage for the called method is popped off the call stack. Popping something off the stack is really efficient - a pointer is simply moved to previous stack frame. This means that the current stack frame can be reused by other methods. Execution is continued in the called method immediately after where the call took place. Methods 5 - Example with three methods Purpose of this lesson: Show definition of multiple methods. 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. One method is void, which means it doesn't return a value. Three methods call other methods. The main program consists mostly of calls to other methods. Source code 1 // // // // File : Purpose: Author : Date : methods/KmToMilesMethods.java Converts kilometers to miles using two methods. Fred Swartz - placed in public domain 22 Apr 2006 2 import javax.swing.*; 3 4 public class KmToMilesMethods { //========================================================= constants private static final double MILES_PER_KILOMETER = 0.621; 5 //============================================================== main 6 7 public static void main(String[] args) { double kms = getDouble("Enter number of kilometers."); double miles = convertKmToMi(kms); displayString(kms + " kilometers is " + miles + " miles."); } 8 9 //===================================================== convertKmToMi // Conversion method - kilometers to miles. private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; 10 return miles; } 11 //========================================================= getDouble 12 // I/O convenience method to read a double value. private static double getDouble(String prompt) { String tempStr; 13 tempStr = JOptionPane.showInputDialog(null, prompt); return Double.parseDouble(tempStr); 14 } //===================================================== displayString // I/O convenience method to display a string in dialog box. private static void displayString(String output) { 16 JOptionPane.showMessageDialog(null, output); } 17 } 15 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 Methods 6 - Overloading Purpose of this lesson: Explain overloading = multiple methods with the same name. 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. One method is void, which means it doesn't return a value. Three methods call other methods. The main program consists mostly of calls to other methods. 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 1 2 3 // File : methods/avg3/AvgThreeOverloaded.java // Description: Averages three numbers -- meaningless, but // Purpose: Show an overloaded method, getDouble, with three definitions, // differing in the number of parameters. // Issues : Input isn't checked for legality (non-null number) because // 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) { //... 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); double average = (n1 + n2 + n3) / 3.0; 10 displayString("Average is " + average); } 7 11 //========================================================= getDouble 12 // I/O convenience method to read a double value. // This version of the getDouble method simply calls on another 13 // version passing it a generic input message. private static double getDouble() { 14 return getDouble("Enter a number"); } 15 //========================================================= getDouble // I/O convenience method to read a double value given a prompt. 16 // This version of getDouble displays the user supplied prompt. private static double getDouble(String prompt) { 17 String tempStr; tempStr = JOptionPane.showInputDialog(null, prompt); 18 return Double.parseDouble(tempStr); } 19 //========================================================= getDouble 20 // I/O convenience method to read a double value in a range. // It builds a new prompt and calls another version to get 21 // the value, looping until a value in the range is found. private static double getDouble(String prompt, double low, double high) { 22 double result; String rangePrompt = prompt + " Value must be in range " 23 + low + " to " + high; 24 //... Read and loop back if the number is not in the right range. do { 25 result = getDouble(rangePrompt); } while (result < low || result > high); 26 return result; } 27 //===================================================== displayString 28 // I/O convenience method to display a string in dialog box. private static void displayString(String output) { 29 JOptionPane.showMessageDialog(null, output); } } 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 Don't confuse overloading and overriding This two terms are easily confused because they both have to do with multiple definitions of methods. Better terms would have been nice, but these are what we have. Overloading is making multiple method definitions which differ in the number or types of parameters, as described here. Overriding is redefining a method in a super class, using exactly the same number and types of parameters. OOP 1. Introduction to Classes and Objects Purpose of this lesson: 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 Instance variable = Variable declared in class outside a method. Typically private. Field = Synonym for instance variable, attribute. Common informal term. Attribute = Synonym for instance variable, field. Often used in the design phase. Property = Synonym for instance variable, field. Common term if field is known publicly. New Java language features Declaring fields (instance variables). Object-Oriented Programming (OOP) concepts Class = data + methods. Everything (data and methods) in Java is contained in classes. So far you've been using classes to hold methods (main and perhaps a few other static methods). These methods use local variables, which are completely private to the method, and which disappear when the method returns. 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. Classes reduce complexity. Another advantage of classes is reducing complexity. Complexity limits the size and reliability of programs. Complexity is reduced by increasing cohesion (putting things together that belong together) and reducing coupling (interconnections). The proper use of classes can make large improvements in both of these. 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. A class stores the attributes (data) of something Group values. Classes are used to group a number of related, named, data values associated with an entity. By entity we mean something that is typically a noun when you are talking about a problem you are solving. For example, in a university computing system, you might have a class to represent a student, an instructor, a classroom, a department, a course, a section of a course, .... 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. public class Student1 { public String firstName; public String lastName; public int } id; 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. Does your problem require classes or simple variables? If the data you are working with, for example a temperature, can be expressed as a simple value and the operations on it are all defined by operators, then just use a simple variable for it (int, double, String, ...). Often the data associated with an entity in your problem is not a simple value, but has multiple attributes. Examples showing classes as groups of attriutes. Instead of working with simple temperature numbers, you might have TemperatureMeasurement objects, which have several attributes: the temperature, the time, and the location. A Student class would represent information about a student: name, id, address, ... Each object of this class would have a data about a specific student. A Classroom class would have information about a classroom's building, room number, capacity, whether it has a projector, etc. 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. Similarity to database table If your are familiar with databases, a class is very similar to a table definition. If you're not familiar with databases, don't worry because these lessons don't assume you are. OOP 2. Data - Student Class Purpose of this lesson: Classes versus objects. How to create objects and assign values to the instance variables (fields). Good practice: One class per file is the standard. New Java language features Using new to create an object. Referencing fields using dot notation. One class per file is standard practice Here is the class again that represents information about a student. Typically there is one class definition per file, so this would be stored in Student1.java. // File : oop/dataclass/Student1.java // Purpose: Information about a student. public class Student1 { public String firstName; // First name public String lastName; // Last name public int // Student id id; } Class versus object A class is a template that defines what attributes an object can have. You make one class definition, then create objects of that class using the new keyword. Some analogies might make this clearer. 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. Use new to create a new object A class defines what fields an object will have when it's created. When a new Student1 object is created, a block of memory is allocated, which is big enough to hold these three fields -- as well as some extra overhead that all objects have. Student1 tatiana; tatiana = new Student1(); // Create Student1 object with new. "new" and parentheses To create a new object, write new followed by the name of the class (eg, Student1), followed by parentheses. Later we'll see that we can specify arguments in the parentheses when creating a new objects. Default field values - null, zero, false 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. Student1 tatiana; Student1 object. // Declare a variable to hold a //... Create a new Student1 object for Tatiana. tatiana = new Student1(); // Create a new Student1 object with default values. tatiana.firstName = "Tatiana"; // Set values of the fields. tatiana.lastName = "Johnson"; tatiana.id = 9950842; JOptionPane.showMessageDialog(null, "One student is named: " + tatiana.lastName + ", " + tatiana.firstName); Awkward? This simple example with one student is somewhat awkward, but we'll get to examples that show real advantages soon. A class definition is a template for creating objects A class defines which fields an object has in it. You need to use new to create a new object from the class by allocating memory and assigning a default value to each field. A little later you will learn how to write a constructor to control the initialization. It's not very interesting to create only one object of class, so the following example creates a couple of them. // 1 2 3 4 File : oop/dataclass/TestStudent1.java import javax.swing.*; public class TestStudent1 { public static void main(String[] args) { Student1 tatiana; Student1 pupil; //... Create new Student1 object with new. tatiana = new Student1(); tatiana.firstName = "Tatiana"; 5 tatiana.lastName tatiana.id 6 = "Johnson"; = 9950842; //... Create another Student1 object. pupil = new Student1(); pupil.firstName = JOptionPane.showInputDialog(null, "First 7 name"); 8 9 pupil.lastName pupil.id = Integer.parseInt(JOptionPane.showInputDialog(null, "ID")); JOptionPane.showMessageDialog(null, "One student is named: " + tatiana.lastName + ", " + tatiana.firstName + "\n and another is named: " + pupil.lastName + ", " + pupil.firstName); 10 11 } 12 13 14 15 16 17 18 19 20 21 22 23 24 25 = JOptionPane.showInputDialog(null, "Last name"); } 26 27 OOP 3. Constructor - Student Class Purpose of this lesson: To introduce the concept of constructors. Purpose of constructors is both guaranteed initialization and convenience. New Java language features Constructor syntax - like a method but with class name and implicit type/value. Add a constructor for better initialization Avoid bad initializations. One problem with the Student1 class is that the user has to explicitly initialize all fields. This requires extra typing, but more importantly, it is error-prone. If we forget to initialize a field, the default value could have bad consequences. Convenience. Defining a constructor makes creation of an object easier to write. 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. Student2 example with a constructor Here is the Student1 class with a constructor which simply initializes the fields (instance variables) from its parameters. Often constructors do more work in initialization, including checking for legal values, but for now we'll just simply copy the parameter values. // File : oop/dataclass/Student2.java // Purpose: Information about a student. Defines constructor. public class Student2 { public String firstName; // First name public String lastName; // Last name public int // Student id id; //======================================== 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. 1 // File : oop/dataclass/TestStudent2.java // Purpose: Tests Student2 constructor. import javax.swing.*; 2 3 public class TestStudent2 { public static void main(String[] args) { Student2 tatiana; Student2 pupil; 4 //... Create new Student2 object with new. tatiana = new Student2("Tatiana", "Johnson", 9950842); 5 //... Create another Student2 object. String first = JOptionPane.showInputDialog(null, "First 6 name"); 7 8 String last int studID= Integer.parseInt(JOptionPane.showInputDialog(null, "ID")); pupil = new Student2(first, last, studID); 9 JOptionPane.showMessageDialog(null, "One student is named: " + tatiana.lastName + ", " + tatiana.firstName + "\n and another is named: " + pupil.lastName + ", " + pupil.firstName); 10 11 12 13 14 = JOptionPane.showInputDialog(null, "Last name"); } } 15 16 17 18 19 20 21 22 23 24 25 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(); constructor. // ILLEGAL. someone = new Student2("Michael", "Maus", 1); values. There is no default // OK. Must specify 3 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. Class and Interface Concepts 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. Other views on OOP OOP Is Much Better in Theory Than in Practice at www.devx.com. 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. Differences between methods and constructors. 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. Example of explicit this constructor call public class Point { int m_x; int m_y; //============ Constructor public Point(int x, int y) { m_x = x; m_y = y; } //============ Parameterless default constructor public Point() { this(0, 0); // Calls other constructor. } . . . } super(...) - The superclass (parent) constructor 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; } Why you might want to call super explicitly 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 1 /////////////////// class WITHOUT a parameterless constructor.////////////////// class Parent { 2 int _x; Parent(int x) { _x = x; } 3 4 // Constructor with a parameter. } 5 6 7 8 9 But why won't this subclass compile? 1 ////////////////// Why won't this class compile? /////////////////////////////// class Child extends Parent { int _y; 2 Child(int y) { _y = y; } 3 // This line mysteriously generates an error! } 4 5 6 7 8 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? Constructor chaining - implicit or explicit constructor call as first statement 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. Possible solution 1 - Explicit constructor call 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; } Possible solution 2 - Define a parameterless constructor 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): 1 2 /////////////////// class with parameterless constructor. ////////////////////// class Parent { int _x; Parent() { // Parameterless constructor this(-666); 3 // Call other constructor with default value. } 4 Parent(int x) { _x = x; } 5 // Constructor with a parameter. } 6 7 8 9 10 11 12 13 Example class where a default constructor would be a disaster It's common to have a class with no legal default values. For example, what should the default constructor do for this class? 1 2 3 4 5 6 7 8 // A parameterless constructor would be wrong here. public class Student2 { private String firstName; // First name private String lastName; // Last name private int id; // Student id //====================================================== constructor public Student2(String fn, String ln, int idnum) { firstName = fn; lastName = ln; id = idnum; } //======================================== parameterless constructor public Student2() { ???? // No possible legal values. } //========================================================== setters public void setID(int id) { this.id = id; 10 } 9 11 . . . } 12 13 14 15 16 17 18 19 20 21 22 23 24 25 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. Never define a parameterless constructor unless it can create a valid object. Constructor Chaining Exercise 1 Name _______________________________ The first line of every constructor must be either A this call to another constructor in the same class. A super call to a parent constructor. 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 What is printed by this program? // 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(); } } class Child extends Parent { Child() { System.out.println("Child() constructor"); } } class Parent extends Grandparent { Parent() { this(25); System.out.println("Parent() constructor"); } Parent(int x) { System.out.println("Parent(" + x + ") constructor"); } } class Grandparent { Grandparent() { System.out.println("Grandparent() constructor"); } } You can check your answer with Constructor Chaining Answer. 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. Classes versus Interfaces Classes are used to represent something that has attributes (variables, fields) and capabilities/responsibilities (methods, functions). Interfaces are only about capabilities. For example, you are a human because you have the attributes of a human (class). You are a plumber because you have the ability of a plumber (interface). You can also be an electrician (interface). You can implement many interfaces, but be only one class. 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. Interfaces replace multiple inheritance 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(...). public class MyPanel extends JPanel implements ActionListener, MouseMotionListener { public void actionPerformed(ActionEvent e) { /* Method body */ } public void mouseDragged(MouseEvent me) { /* Method body */ } public void mouseMoved(MouseEvent me) { /* Method body */ } // Everything else in this class. } It is common for a panel that does graphics and responds to the mouse to implement its own mouse listeners (but not action listeners) as above. Declaring an interface 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. Common tagging interfaces that you might see are: 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 shortterm 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. Older, but common, solution 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. Defining an enum type 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. public enum Shape { RECTANGLE, CIRCLE, LINE } Declaring enum variables and using enum values 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. Shape drawing = Shape.RECTANGLE; assigned. // Only a Shape value can be Printing enum values The enum class has a toString() method defined that returns the unqualified string version of the value. This means that it's easy to print these values without any special conversion effort. System.out.println(drawing); // Prints RECTANGLE Looping over all enum values with foreach loop The static values() method of an enum type returns an array of the enum values. The foreach loop is a good way to go over all of them. //... Loop over all values. for (Shape shp : Shape.values()) { System.out.println(shp); // Prints RECTANGLE, CIRCLE, ... } 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; } Getting an integer equivalent of an enum value 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. System.out.println(drawing.ordinal()); // Prints 0 for RECTANGLE. 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. Related data structure classes: EnumSet and EnumMap 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. java.util.EnumMap provides an efficient implementation of a map for enums based on an array. 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.