Flow Control, Assertions and Exception Handling
Write code using if , and switch statements and identify legal argument types for these
statements. |
Consult a text book for the basics of these, if unsure. If you do know the basics, here are a few things to watch out for:
Number 1
Be wary where if
is used without braces, and with an else
statement. This is referred to as the
dangling else problem, and occurs in C and C++ aswell. The following example is from Boone (p.154):
if (result >=0) if (result > 0) System.out.println("positive"); else System.out.println("negative");
The indentations are misleading. It might appear that the above code will print "positive" if result is greater than 0,
"negative" if is less than zero, and print nothing if result is equal to 0. In fact, it will print "positive" if result
is greater than 0, it will print nothing if is less than zero, and print "negative" if result is equal to 0. This is because
the else statement belongs to the second if
statement, and only executes if result >=0
but not if result>0
, in other words if result equals 0. Using braces (curly brackets) would fix this and is
the best practice if you want readable code that is not potentially misleading. The following indentation shows the real
relationship, of course the compiler doesn't care about indentation:
if (result >=0) if (result > 0) System.out.println("positive"); else System.out.println("negative");
A good practice is to use blocks with all your if
and else
statements to avoid this ambiguity.
Number 2
After switch
/case
construct has executed the correct case, it will continue to execute all
those after it (including default:
if it is there, after the selected case) on to the end of the
switch
/case
block, unless you put in a break
, return
or throw
statement. This is referred to as "falling through". For example:
switch (a) { case 1: System.out.println("one"); case 2: System.out.println("two"); case 3: System.out.println("three"); default: System.out.println("some other number"); }
If a is 1, this will print "one", "two", "three" and then "some other number" in succession. If a is 3, this will print "three" and then "some other number".
In some cases, this kind of behaviour might desirable, but here it isn't. This block of code fixes it:
switch (a) { case 1: System.out.println("one"); break; case 2: System.out.println("two"); break; case 3: System.out.println("three"); break; default: System.out.println("some other number"); }
Note that in switch blocks, it is legal to put default:
anywhere in the block, it doesn't have to be the last one.
Number 3
The argument for an if()
statement must be a boolean or an expression which evaluates to a boolean. A common
beginners mistake is to use a single =
rather than ==
to compare values. The following gives a compiler
error:
public static void main(String[] args) { int a=1; if(a=2) System.out.println("a is two"); }
a=2
assigns the value 2 to a.
The argument for a switch statement must be a byte
, a char
, a short
or an
int
, or an expression which evaluates to one of those.
Write code using all forms of loops including labeled and unlabeled, use of break and continue, and state the values taken by loop counter variables during and after loop execution. |
An loop example:
for(int i=0;i<3;i++){ System.out.println("i is "+i); for(int j=0;j<3;j++) { System.out.println("j is"+j); } }
Will print:
i is 0 j is 0 j is 1 j is 2 i is 1 j is 0
etc.
Note: Don't get thrown if the for
loop uses pre-increment instead of post-increment i.e.
for(int i=0;i<3;++j)
instead of for(int i=0;i<3;j++)
.
This does not make any difference to the behavior of a for
loop.
break
will cause the current loop to be abandoned. continue
causes execution to skip the rest of the code
in the current iteration of the loop, and start at the top of the loop with the next iteration.
These (unlabeled) versions will only affect the execution of loop that they are in. If you have nested loops, and want to break out of, or skip to the next iteration of, an outer loop, from an inner loop, you used the labeled versions. These jump to the wherever the label is, allowing you to break out of, or skip several nested loops, by placing the label in front of the outer loop.
Labels are a name followed by a colon, i.e. ":", placed before the loop.
Write code that makes proper use of exceptions and exception handling clauses (try , catch() ,
finally ) and
declares methods and overriding methods that throw exceptions. |
Place code which is likely to throw an exception inside a try { }
block. Create one or more catch() { }
blocks with code to deal with the types of exceptions that might be thrown in the try block. The type of exception goes inside
the round
brackets of the catch() statement, as you would when declaring a method.
Exceptions are objects, which belong to a class hierarchy. If the exception thrown is an instance of the class, or a subclass
of the
class, specified in catch()
, that catch block is the one executed. Your catch()
block therefore can handle a
range of exceptions if they are subclasses of the class specified. If you want to handle one specific subclass one way, and
all the other
subclasses differently, put a catch statement for the specific subclass first, and a more general catch block for the superclass
second.
Then when an exception is thrown, if the exception is a member of the subclass, that catch block only executes, but if it
is a different
subclass of the parent class, the general catch block executes. If you put the superclass first, you will get a compiler error.
For example:
void mymethod(int i) throws Exception { }
Methods can throw more than one class of exception, you list all the exceptions after the throws
keyword, separated by
commas.
Essentially, a method can throw the same or fewer, but not more, exceptions than the superclass method it is overriding. This has to do with object orientation, if you could broaden the number of exceptions in the subclass method, anything which can deal with the superclass might not be able to deal with the subclass, because the are new exceptions there that it was not designed to handle. You want all members of subclasses to be able to be handled as if there were members of the parent class ("upcasting" or polymorphism).
The hierarchy of exceptions is important here, you can replace a exception class in the overridden method with one or more of its subclasses, but you can't replace it with its superclass. To do this would be to broaden the range of exceptions the method could throw.
For example:
throw new SomeKindOfException();
If an exception is thrown, then the rest of the code in the try block is not executed. If any catch block matches the exceptions class or a super class of the exception, that block executes. If the exception is not caught correctly, then after the finally block executes, the rest of the code in the method is not executed.
finally
blocks execute no matter what, in other words, whether the code executes without an exception, or an exception
is thrown and successfully caught, or an exception is thrown and not caught. This is useful because, except for code in a
finally block,
if an exception is thrown and not caught, the execution of the rest method is abandoned.
It is legal to have a try
block, followed by a finally
block, without any catch blocks.
One thing (probably not important for the exam) which could stop a finally clause from executing, is a call to
System.exit(0)
.
RuntimeExceptions
differ from normal exceptions in that they are not required to be declared or handled within a try block.
An Error
indicates serious problems that a reasonable application should not try to catch. Examples are the
VM running out of memory.
Write code that makes proper use of assertions, and distinguish appropriate from inappropriate uses of assertions. |
For more information see: http://java.sun.com/j2se/1.4/docs/guide/lang/assert.html.
The simplest form of assertion consists of the assert
keyword followed by an expression which evaluates to a boolean.
Example:
assert someObject != null;If the expression evaluates to
false
then an AssertionError
is thrown.
The other form adds a colon followed by a second expression which evaluates to a value of some kind.
If the assertion fails, the value is included in the AssertionError
for information.
Example:
assert someObject != null : "someObject should not be null at this point!";
Identify correct statements about the assertion mechanism. |
See the previous objective, or look in a textbook or on the web.
©1999, 2000, 2002 Dylan Walsh.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1
or any later version published by the Free Software Foundation;
with the Invariant Sections being the disclaimer,
no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".