2: Flow ControlS2C Home « 2: Flow Control
In this lesson we look at the different syntax we can use to affect the flow of logic through our programs. We start by looking at code to implement if
and switch
statements whilst identifying legal argument types for them. We then investigate the different types of loops available in
java and the iterators and their usage within a loop. We will also look at how we can break from a loop, continue from within a loop and label a loop to continue execution from. We continue our study of flow
control by looking at assertions and when, and when not, they should be used. We finish our certification lessons on flow control by looking at exceptions, handling exceptions and how to declare methods and
overriding methods that throw exceptions. We also need to understand what happens to our code when an error or any type of exception occurs in a code fragment and what happens when particular exceptions occur.
Lets take a look at the points outlined at the Oracle Website for this part of the certification.
- Section 2: Flow Control
- Develop code that implements an if or switch statement; and identify legal argument types for these statements.
- Develop code that implements all forms of loops and iterators, including the use of for, the enhanced for loop (for-each), do, while, labels, break, and continue; and explain the values taken by loop counter variables during and after loop execution.
- Develop code that makes use of assertions, and distinguish appropriate from inappropriate uses of assertions.
- Develop code that makes use of exceptions and exception handling clauses (try, catch, finally), and declares methods and overriding methods that throw exceptions.
- Recognize the effect of an exception arising at a specified point in a code fragment. Note that the exception may be a runtime exception, a checked exception, or an error.
- Recognize situations that will result in any of the following being thrown:
ArrayIndexOutOfBoundsException
,ClassCastException
,IllegalArgumentException
,IllegalStateException
,NullPointerException
,NumberFormatException
,AssertionError
,ExceptionInInitializerError
,StackOverflowError
orNoClassDefFoundError
. Understand which of these are thrown by the virtual machine and recognize situations in which others should be thrown programmatically.
- Develop code that implements an if or switch statement; and identify legal argument types for these statements.
The if
StatementTop
Create a conditional expression using one of the relational operators available in Java to test one operand against another or test the result of a logical operation. We can execute one set of statements if the boolean result of the expression evaluates to true
and another if the expression evaluates to false
.
The relational and logical operators are discussed in more detail in the Operators lesson.
The following table shows the different forms of the if
construct that can be used. We are using blocks of code to wrap statements which is optional, but good practice and will be used here.
Construct | Description |
---|---|
Simple if | |
if (condition) { | Execute statements in statement1 if condition expression evaluates to true . |
if....else | |
if (condition) { | Execute statements in statement1 if condition expression evaluates to true ,otherwise execute statements in statement N . |
Nested if | |
if (condition) { | Execute statements in statement1 if condition expression evaluates to true Execute statements in statement2 if condition2 expression evaluates to
true ,otherwise execute statements in statement3 if condition2 expression evaluates to false , otherwise execute statements in statement N if condition expression evaluates to false . |
Multiple if....else if | |
if (condition) { | Execute statements in statement1 if condition expression evaluates to true
Execute statements in statement2 if condition2 expression evaluates to true , Execute statements in statement3 if condition3
expression evaluates to true etc..., otherwise execute statements in statement N . |
if
Rules and Examples
There are a few rules to remember when coding the if
statement:
- The expression we check against, in the parentheses, must evaluate to a
boolean
type:true
orfalse
. - One optional
else
statement can be coded as part of theif
construct and must come after anyelse if
statements. - Multiple
else if
statements can be coded after the initialif
and before the optionalelse
statement (if coded). - As soon as we hit a
true
condition any otherelse if
statements will not be tested.
Following are some examples showing if
statement usage:
/*
Some code showing if statement usage
*/
boolean b = false;
int i = 2;
// Simple if
if (b == false) {
System.out.println("This is executed");
}
if (i = 2) { // Will not compile, does not evaluate to boolean
System.out.println(" ");
}
// if else
if (b = false) { // Assignment not evaluation
System.out.println("This is NOT executed");
} else {
System.out.println("This is executed");
}
// Multiple if else
if (i == 0) {
System.out.println("This is NOT executed");
} else if (i == 1) {
System.out.println("This is NOT executed");
} else if (i == 2) {
System.out.println("This is executed");
} else {
System.out.println("This is NOT executed");
}
if (i == 0) {
System.out.println("This is NOT executed");
} else (i == 1) { // Will not compile, else must come last
System.out.println(" ");
} else if {
System.out.println(" ");
}
The switch
StatementTop
The switch
statement can be used instead of the multiple if....else if
construct when we are doing a multiway test on the same value. When this scenario arises the switch
statement
is often a more efficent and elegant way to write our code
The switch
statement is where we put the expression we are going to evaluate. Each case
constant is evaluated against the switch
expression and the statements within
the case
are processed on a match. We have the option to break
from the switch
after this if required. We can also code an optional default
statement,
which can act as a kind of catch all and is normally placed, at the end, after the case
statements.
Construct | Description |
---|---|
switch | |
switch (expression) { |
expression can be of type char , byte , short or int .constant1 must be a literal of a type compatible with the
switch expression .Execute statements1 on match.Optional break from switch statement.
constant2 must be a literal of a type compatible with the switch expression .Execute statements2 on match.Optional break from switch statement.constantN must be a literal of a type compatible with the switch expression .Execute statementsN on match.Optional break from switch statement. Optional default statement (catch all).Execute defaultStatements .Optional break from switch statement. |
nested switch | |
switch (expression1) { |
This is perfectly legal. |
switch
Rules and Examples
There are a few rules to remember when coding the switch
statement:
- The
switch
expression we check against, in the parentheses, must evaluate to achar
type, or thebyte
,short
orint
signed numeric integer
types or to anenum
. - When not using an
enum
in ourswitch
statement only types that can be implicitly cast to anint
are allowed. - The
switch
statement can only check for equality (==) and so the otherrelational operators
won't work withswitch
. - The
case
constant must evaluate to the same type as theswitch
expression. - The
case
constant is a compile time constant and because it has to be resolved at compile time, any constant or final variables must have been assigned a value. - The value of the
case
constants must be different. - When a
case
constant evaluates totrue
the associated code block and any code blocks following are executed, unless abreak
statement is encountered. - The
default
statement can be placed anywhere within theswitch
statement and when executed, the associated code block and any code blocks following are executed, unless abreak
statement is encountered.
Following are some examples showing switch
statement usage:
/*
Some code showing switch statement usage
*/
final int i1 = 2;
final int i2;
byte b = 25;
String s = "java";
// switch
switch (i1) {
case 1:
System.out.println("This is not executed");
case 2:
System.out.println("This is executed");
case 3:
System.out.println("This is executed");
}
switch (i2) { // Not a compile time constant so won't compile
case 1:
System.out.println(" ");
case 2:
System.out.println(" ");
case 3:
System.out.println(" ");
}
switch (i1) {
case 1:
System.out.println(" ");
case 2:
System.out.println(" ");
case 2: // Same case value so won't compile
System.out.println(" ");
}
switch (b) {
case 25:
System.out.println(" ");
case 128: // Loss of precision so won't compile
System.out.println(" ");
}
switch (s) { // Incompatible switch type of String so won't compile
case "java2":
System.out.println(" ");
case "java":
System.out.println(" ");
case "java":
System.out.println(" ");
}
// switch break
int i3 = 2;
switch (i3) {
case 1:
System.out.println("This is not executed");
case 2:
System.out.println("This is executed");
break;
case 3:
System.out.println("This is not executed");
}
// switch default
int i4 = 2;
switch (i4) {
case 0:
System.out.println("This is not executed");
case 1:
System.out.println("This is not executed");
default:
System.out.println("This is executed");
}
switch (i4) {
case 0:
System.out.println("This is not executed");
default:
System.out.println("This is executed");
case 1:
System.out.println("This is executed");
}
The for
StatementTop
The for
statement will loop through a section of code a set number of times. The for
statement is very versatile and has two different variations known commonly as the for loop and the
enchanced for loop.
The for loop contains three parts. In the first part we initialize a counter variable with a value, this only happens on initial entry to the for loop. The second part is a condition
which tests the variable value at the start of each loop and if the condition is no longer true
the for loop is exited. The final part of the for
statement is an expression to be
evaluated at the end of each iteration of the loop. This normally takes the form of a counter that is decremented or incremented.
The enchanced for loop was introduced in java and implements a for-each style loop that iterates through a collection of objects in a sequential order from start to finish.
The following table shows the different forms of the for
construct that can be used. We are using blocks of code to wrap statements which is optional when using a single statement, but good practice and will be used here.
Construct | Description |
---|---|
for loop | |
for ([initialization]; [condition]; [iteration]) { | The initialization , condition , iteration and
statement body components of a for statement are all optional.The following will create an infinite for loop :for (;;) {...} // Infinite loop.The following will create a for loop with no body:for (int i=1; i<5; i++); // No bodyThe initialization component is generally an assignment statement that
sets the initial value of a control variable used to control iteration of the loop.The condition component is a conditional expression that is always tested againt the control variable
for true before each iteration of the loop. So if this is false to begin with then any statement body component will never be executed.The iteration component
is an expression that determines the amount the control variable is changed for each loop iteration.The statement body is executed each time the condition component
returns true when tested againt the control variable. |
enhanced for loop | |
for (declaration : expression) { | The declaration component declares a variable of a type compatible with the collection to be accessed which will hold a value the same as the current element within the collection.The expression component can be the result of a method call or an expression that evalutes to a collection type.The statement body is executed each time an element of the collection is iterated over. |
Example usage of the different forms of the for statement is shown in the Beginning Java - Loop Statements lesson.
The while
StatementTop
The while
statement can be used to loop through a section of code while a condition remains true
. The while
statement has two different variations known commonly as the while loop and the
do-while loop.
The following table shows the different forms of the while
construct that can be used. We are using blocks of code to wrap statements which is optional when using a single statement, but good practice and will be used here.
Construct | Description |
---|---|
while loop | |
while (condition) { | The condition can be any expression that results in a boolean and the loop will continue while the expression
remains true , processing the statement body on each pass.When the condition returns false the loop ends and control is passed to the next line following the
loop.Therefore if the condition starts as false the loop will never be entered. |
do while loop | |
do { | Unlike the normal while loop the statement body is processed before the condition
is tested. The condition can be any expression that results in a boolean and the loop will continue while the expression remains true .When the condition returns
false the loop ends and control is passed to the next line following the loop.Therefore even if the condition starts as false the loop will always execute at least once. |
while
Rules and Examples
There are a few rules to remember when coding the while
and do while
statements:
- The expression we check against, in the parentheses, must evaluate to a
boolean
type:true
orfalse
. - When coding the
while
statement remember that the loop will never be executed if the expression we check against, in the parentheses resolves to false on loop entry. - When coding the
do while
statement remember that the loop will always be executed at least once, regardless of whether the expression we check against, in the parentheses resolves to false on loop entry.
Following are some examples showing while
and do while
statement usage:
/*
Some code showing while and do while statement usage
*/
boolean b = true;
int i = 2;
// while
while (b) {
System.out.println("This is executed");
break;
}
while (i == 2) {
System.out.println("This is executed");
break;
}
while (i) { // Will not compile, does not evaluate to boolean
System.out.println(" ");
}
while (i = 2) { // Assignment not evaluation, so won't compile
System.out.println(" ");
}
while (true) { // This is fine
System.out.println("This is executed");
break;
}
while (true) { // This is fine but loops endlessly
System.out.println("This is executed");
}
// do while
do {
System.out.println("This is executed once");
} while (false);
do {
System.out.println("This is executed once");
b = false;
} while (b);
Example usage of the different forms of the while statement is shown in the Beginning Java - Loop Statements lesson.
Using the Assertion mechanism has no 'hit' on performance as we enable assertions at runtime using the -ea
option. Compilation of a source file that uses assertions is the same as normal and any assertion code
is ignored at runtime in default mode unless the file is run using the -ea
option. So as an example:
javac OurProgram.java // Compile normally
java OurProgram // Run normal default mode
java -ea OurProgram // Run enable assertions mode
We would compile and run the OurProgram
class in normal default mode. Then we would run the program with assertions enabled, and assertion code would be invoked as part of the block of code it belongs to. The
assertion code leaves no footprint and is just ignored when the class is run without the -ea
option.
Using the assert
KeywordTop
The following table shows the two forms of the assert
statement which are only active when running our code with the -ea
option. The second form just allows us to pass more information to an
AssertionError and we must ensure that the expression returns a value.
Assert Form | Example | Description |
---|---|---|
form1 | ||
assert condition; // Other code | assert (a > 0); | Throw AssertionError if condition equates to false Run this code when assertion equates to true . |
form2 | ||
assert condition: expression; // Other code | assert (a > 0): "a = " + a; | Throw AssertionError if condition equates to false passing the value returned from expression .Run this code when assertion equates to true . |
Appropriate Assertion UsageTop
Assertions should not be used to validate command-line arguments. We would have to run the code everytime using the -ea
option to ensure assertions run the validation. Using exceptions is
more appropriate for validating command-line arguments as these run regardless of deployment and the use of the -ea
option.
Assertions should never be used that cause side-effects such as changing a value used elsewhere in the code. If we do so we are reliant on code being run using the -ea
option to get the values changed. What
happens when someone else runs the code without assertions enabled! Unreliable results and a difficult bug to find, that isn't really a bug, just an incorrect use of the assertion mechanism.
When considering whether to use assertions to validate arguments to a method, we need to consider the access modifier of the method:
- Methods marked as
public
are not considered appropriate for assertions;public
methods are available to anyone and should be robust enough to guarantee the validation and robustness of their interfaces. Using exceptions is more appropriate forpublic
methods as these run regardless of deployment and the use of the-ea
option. - Methods marked as
protected
are not considered appropriate for assertions;protected
methods are available to subclasses outside the package and so should be robust enough to guarantee the validation and robustness of their interfaces. Using exceptions is more appropriate forprotected
methods as these run regardless of deployment and the use of the-ea
option. - Methods with no access modifier are appropriate for assertions if you control the package;
package-private
methods are available only to programs within the package they belong to. If you have control then you can be reasonably assured that logic calling yourprotected
method is correct. - Methods marked as
private
are considered appropriate for assertions as you control the code that calls the method;private
methods are available only to the class they are written in. Therefore you have control and can be reasonably assured that logic calling yourprivate
method is correct.
Assertions should be used anywhere in code when you have code that should never be reached, such as a switch default
statement, that you know will never be invoked. In these situations you set the assertion
mechanism to false
rather than test a condition. This ensures that if the statement is ever reached, when assertions are enabled, we will get an AssertionError
.
See the Flow Control - Using Assertions lesson for example usage.
Exception OverviewTop
An exception refers to an exceptional condition that has occurred to alter the normal flow of our programs. When an exception occurs it will get thrown by the JVM or we can determine conditions to throw an exception ourselves when required. We can catch thrown exceptions and the code we write for this purpose is known as an exception handler. We can also declare exceptions in our method definitions, when we know for instance that the method will try to read a file that may or may not be present.
At the top of the exception hierarchy is the Throwable
class, which all other error and exception classes inherit from. The Throwable
class creates a snapshot of the stack trace for exceptions
when they occur and may also contain information about the exception. We can use this information for debugging purposes. Only instances of the Throwable
class, or subclasses of it, can be
thrown by the JVM or be thrown by us.
Two subclasses inherit from the Throwable
class and these are the Error
and Exception
classes. These classes, and subclasses
thereof, are used to create an instance of the appropriate error or exception along with information about the exception:
- The
Error
class and its subclasses handle error situations from within the JVM itself and so are outside our control as programmers. As a general rule we can't recover from anError
situation and because of this we are not expected to handle anError
when it occurs. - The
Exception
class and its subclasses are what concern us more as programmers and these can be split into two categories:- Runtime exceptions: Are exceptions that are not checked for by the compiler and for this reason are also known as unchecked exceptions. Generally exceptions of type
RuntimeException
originate from problems in our code, such as an attempt to divide by zero which gives anArithmeticException
. These sorts of errors are within our control and as such should be handled by the code itself. - Checked exceptions: Are exceptions that are checked for by the compiler and if present and not declared, will give a compiler error. An example of this is a
FileNotFoundException
where a file we want to read may or may not be available. Whether the file is available or not is outside our control. So when we read the file, we need to handle or declare that this exception, or a superclass of it may occur.
- Runtime exceptions: Are exceptions that are not checked for by the compiler and for this reason are also known as unchecked exceptions. Generally exceptions of type
Exception Hierarchy DiagramTop
The diagram below is a representation of the exception hierarchy and by no means a complete list, but should help in visualisation:
In the diagram above each box represents a class and as you can see the Exception
class, which interests us as programmers, has lots of subclasses attached to it. We are just showing some of them in
the above diagram as space permits, but I am sure you get the idea. When an exception happens an exception object of the appropriate class is created and we can use code to handle the exception.
try catch finally
ConstructTop
The following table shows the different forms of the try catch finally
construct.
Construct | Description |
---|---|
try catch | |
try { |
Execute statements in try code block.Execute statements in catch code block. |
try catch finally | |
try { |
Execute statements in try code block.Execute statements in catch code blockExecute statements in finally code block. |
try finally | |
try { |
Execute statements in try code block.Execute statements in finally code block. |
try with multiple catch | |
try { |
Execute statements in try code block.Execute statements in catch code block 1.
Execute statements in catch code block 2.Execute statements in catch code block N. |
try with multiple catch and a finally | |
try { |
Execute statements in try code block.Execute statements in catch code block 1.
Execute statements in catch code block 2.Execute statements in catch code block N.Execute statements in finally code block. |
try catch finally
Rules
When using the try catch finally
construct there are certain rules that must be adhered to or you get a compiler error:
- When using a
try
block it must be accompanied by acatch
block, afinally
block or both. - When using a
catch
block it must immediately follow thetry
block. - When using multiple
catch
blocks they must go in order from the most specific error to the most generic as discussed in Exceptions And Polymorphism. - When using a
finally
block it must immediately follow the lastcatch
block, or thetry
block when nocatch
block is present.
Declaring ExceptionsTop
We can use the throw
keyword to throw exceptional conditions from within our code. At the top of the exception hierarchy is the Throwable
class, which all other error and
exception classes inherit from. So we can throw any subtype of the Throwable
class if we want to, which includes objects of type Error
, Exception
and RuntimeException
.
The compiler demands that we either handle or declare exceptions which are neither error or runtime exceptions, in other words checked exceptions. See the
Declaring Exceptions lesson for example usage.
Overridden Methods & Exceptions
There are a few things to remember when overriding methods that throw exceptions:
- An overriding method can throw any
Error
orRuntimeException
exceptions, whether these are declared in the overridden method or not. - An overriding method must not throw any new checked exceptions or any checked exceptions that are higher up the inheritance tree than those declared in the overridden method.
- An overriding method can throw checked exceptions that are lower in the inheritance tree than those declared in the overridden method, or throw fewer or none of the checked exceptions that were declared in the overridden method.
Certification Exceptions & ErrorsTop
The following table lists the exceptions and errors we need to know for the certification:
Error/Exception | Description |
---|---|
ArrayIndexOutOfBoundsException | Attempt to access array with an illegal index. An example of this exception is shown in the Arrays lesson when we look at java.lang Array Exceptions. |
ClassCastException | Attempt to cast an object to a subclass of which it is not an instance. An example of this exception is shown in the Generics lesson when we look at a Raw Type/Generic Type Comparison. |
IllegalArgumentException | Method invoked with an illegal argument. |
IllegalStateException | Method invoked while an application isn't in the correct state to receive it. |
NullPointerException | Attempt to access an object with a null reference.An example of this exception is shown in the Reference Variables lesson when we look at The Heap. |
NumberFormatException | Invalid attempt to convert the contents of a string to a numeric format. An example of this exception is shown in the Exception Handling lesson when we look at Using try catch finally . |
AssertionError | Assertion boolean test returns false .An example of this exception is shown in the Using Assertions lesson when we look at Using the assert Keyword. |
ExceptionInInitializerError | An unexpected exception has occurred in a static initializer. |
StackOverflowError | A stack overflow occurs because an application recurses too deeply. |
NoClassDefFoundError | Try to load in a class that can no longer be found. |
Related java Tutorials
Beginning Java - Conditional Statements
Beginning Java - Loop Statements
Beginning Java - Primitive Variables
Beginning Java - Operators
Flow Control - Using Assertions
Flow Control - Exception Overview
Flow Control - Exception Handling
Flow Control - Declaring Exceptions