Flow Control, Assertions and Exception Handling

In this section you should be able to:

1.      Write code using if and switch statements and identify legal argument types for these statements.

2.      Write code using all forms of loops including labelled and unlabeled, use of break and continue, and state the values taken by loop counter variables during and after loop execution.

3.      Write code that makes proper use of exceptions and exception handling clauses (try, catch, finally) and declares methods and overriding methods that throw exceptions.

4.      Recognise the effect of an exception arising at a specified point in a code fragment. Note: The exception may be a runtime exception, a checked exception, or an error (the code may include try, catch, or finally clauses in any legitimate combination).

5.      Write code that makes proper use of assertions, and distinguish appropriate from inappropriate uses of assertions.

6.      Identify correct statements about the assertion mechanism.

 

Flow Control, Assertions and Exception Handling

The while() loop

while(expression)

{

     //statements

} //end of while loop

The expression must evaluate to a boolean true or false result. If it is true then the statements within the code block will be executed, this will continue to repeat until a false result is evaluated. If or once it is false then the statements within the code block will be skipped and control will be passed back to the method which called it.

If no curly braces are used to form a code block then only the first statement after the expression is treated as the statement block.

The do() loop

do

{

     //statements

}while(expression);

The do loop (or do..while loop as it’s sometimes known) is much the same as the while loop however in this loop the statement block is executed first before the expression is evaluated. Once again the expression must evaluate to a boolean true or false result. If it is true then the statements within the code block will be executed, this will continue to repeat until a false result is evaluated.

 

It is important to remember that within a loops statement block there is code that will affect the evaluation of the expression. Failure to do this will result in an infinite loop, which results in locking up the program.

 

The most complicated yet versatile loop construct is,

The for() loop

for(initialisation; expression; increment)

{

     //statements

} //end of for statement

 

Part

Description

initialisation

Also referred to as the start condition. It is used to assign an initial value to an identifier normally called the counter in order to start the loop.

The loop can start at any value.

expression

The expression normally consists of a relational test between the counter and a maximum or minimum value that related to the number of iterations the loop needs to perform. This is often the terminating condition of the loop.

The expression needs to evaluate to a Boolean true or false, and does not necessarily need to relate to the counter.

The first time the loop is entered the condition is tested after the initialisation part but before the statement block is entered. If this initial test evaluates to false then the statement block will not be executed.

increment

The increment part is executed after each iteration of the statement block, but before the condition is re-tested.

The increment part can increase or decrease the counter by a set amount.

 

All three parts of the for() construction are optional. If the test is missing, it is treated as perpetually true. If no curly braces are used to form a code block then only the first statement after the expression is treated as the statement block.

 

Break and continue

The break statement abandons the loop altogether; the test is not performed on the way out.

The continue statement causes the current iteration of the loop to be abandoned. Flow restarts at the bottom of the loop. For while() and do, this means the test is executed next. For the for() loop, the third statement in the parenthesis is executed, followed by the test.

Both break and continue can take a label that causes them to skip out of multiple levels of nested loop. The matching label must be placed at the head of a loop and is indicated by using an identifier followed by a colon (:). For example

public class test

{

     public static void main(String[] args)

     {

          outer: for(int i=0; i<2; i++)

              {

                   for(int j=0; j<3; j++)

                   {

                        if(i==j)

                        {

                             continue outer;

                        }

 

                        System.out.println("i = " + i + " j = " + j );

                   }

              }

     }   

} //end of test class

 

The above code produces the following output.

When i and j have the same value, the continue keyword sends the runtime back to the outer loop as specified, before the output is generated. Because the outer loop is the target of the continue statement, the whole of the inner loop is abandoned. So, for the value pairs, this table shows what happens:

i

j

Effect

0

0

continues to outer loop

1

0

prints output

1

1

continues to outer loop

2

1

exits loops (as this is the point where the expression in the for loop returns false)

 

 

Selection Statements

The if statement

The if statement is used to make decisions.

if( expression )

{

     //statements

} //end of if statement

Where expression refers to any expression that returns a boolean true or false value. The statement will only be executed if the expression evaluates to true. If no curly braces are used to form a code block then only the first statement after the expression is treated as the statement block.

 

The if…else statement

The basic if statement can be extended by adding the else clause.

if( expression )

{

     //statements_1

}

else

{

     //statements_2

} //end of if…else statement

 

The multiple if…else statement

if( expression )

{

     //statements_1

}

else if( expression )

{

     //statements_2

}

else

{

     //statements_3

} //end of multiple if statement

 

Nested if statements

if( expression )

{

     if( expression )

          statement;

} //end of nested if statement

 

The switch statement

Java™ provides us with another selection statement. The switch statement evaluates the expression and compares it against each of the case constants in turn. Unlike the if statement, the switch statement does not need to use statement blocks for each case. Execution begins at the appropriate label and continues until the break statement.

switch( expression )

{

     case constant1:    statement1;

                        ….

                        statementn;

                        break;

 

     case constant1:    statement1;

                        ….

                        statementn;

                        break;

 

     case constant1:    statement1;

                        ….

                        statementn;

                        break;

 

     default:           statement1;

                        ….

                        statementn;

                        break;

 

} //end of switch statement

 

The expression used in a switch statement must be of an integral type or one whose value can be implicitly cast into an int type such as byte, short, long or char.

The break statement identifies the end of a particular case and causes immediate exit from the switch. It prevents execution from dropping through to the next case statement.

The default statement is a catch-all statement in that if no constants match the expression then the statement list associated with the default statement is executed. It is important to remember that the default keyword is optional, it is not a requirement of the switch statement. If used, convention dictates that it usually appears at the end of a switch statement, but it is equally valid to put it at the beginning.

 

Assertions

Since Java™ 1.4 there has been an assertions facility.

Assertions provide a convenient mechanism for verifying that a class’s methods are called correctly. This mechanism can be enabled or disabled at runtime. The assert keyword has the following syntax:

assert expression1;

assert expression1: expression2;

expression1 must have a Boolean type. expression2 may have any type. If assertions are disabled at runtime (the default state), the assert statement does nothing. If it’s enabled at runtime via command line argument) then expression1 is evaluated.

If its value is true, no further action is taken. If it’s false then an AssertionError is thrown. If expression2 is present, it is passed into the constructor of the AssertionError, where it is converted to a String and used as the error’s message.

Compiling with assertions

To compile a program with assertions enabled compile with –source 1.4. For example if we had a class called Test and we wanted to compile with assertions enabled we would use the following command:

javac –source 1.4 Test.java

If the flag is omitted, the 1.4 compiler treats source code as if the assert keyword did not exist.

Runtime enabling of Assertions

Assertions are disabled by default. If we want to use the assertions coded and compiled into our Test class at runtime then we use the enableassertions or –ea flag on the java command line, for example:

java –ea Test

The following is a Test class

public class test

{

     public static void main(String[] args)

     {

          int age = 0;

 

          assert(age>0):"Age was not greater than zero. End";

 

System.out.println(“End of test class”):

     }

} //end of test class

If we compile and run with the assertions enabled we get the following:

If we change the age to 5, compile and run again, we get the following result:

No problems, the result of expression1 returned true so the code continued to run without interruption.

 

 

Exception Handling

An exception is an object that is created when something unexpected happens. For example:

·        Trying to access an element in an array that does not exist.

·        Illegal arithmetic operations (e.g. a division by zero).

·        Invalid data received as input.

·        Trying to open a file that does not exist.

·        Non-existent network connections.

 

Class hierarchy for the Exception class and some other classes of interest are shown below. It does not include all of the exception classes – there are many more.

 

Using try() catch(){}

A try block is a code block that is preceded with the keyword try followed by a pair of braces, for example:

try

{

     // code which might throw an exception

}catch(exception e)

{

     // handle the exception here

}// end of try catch block

The above try..catch block can be used to catch any type of exception thrown in a program.

Multiple catch blocks

 

 

Finally

The finally statement can be added to the end of a try..catch block to ensure that a block of code is executed, regardless of whether an exception was caught (or not caught) or thrown.

try

{

     // code which might throw an exception

}catch(exception e)

{

     // exception caught here

}finally

{

     // finally block executed

}// end of try catch block

 

 

Throwing exceptions

The throw Statement

Most exceptions are thrown by the standard java.lang classes, but any programs can be made to throw there own exceptions. The throw statement causes an exception to be thrown.  You can create a throw statement two ways, either by creating an exception and then throwing it at once or in two separate statements. See example.

throw new ioexception(“file does not exist”); // creates an ioexception and throws it in one statement

ioexception e = new ioexception(“file does not exist”);   //creates an ioexception

throw e;                                                  //the exception is then thrown

 

The program below creates a new exception that is thrown when the user runs the program and enters a negative number into the command line arguments, for instance, -1.

The exception is caught by a catch block containing a statement that uses the exception’s getMessage() method to display the exception message.

public class test

{

     public static void main(String[] args)

     {

          try

          {

              float num = Float.parseFloat(args[0]);

              if( num < 0 ) throw new IllegalArgumentException("Positive numbers only");

          }catch( IllegalArgumentException e )

          {

              System.out.println(e.getMessage());

          }

     }

} //end of test class

 

If I enter a positive number of 10 it runs fine, however if I enter -10, our exception is thrown and the catch block picks it up.

 

As a general rule, Java™ requires that any method that might throw an exception must declare the fact so that responsibility for handling exceptions can be passed, from the method containing the exception, to the method that is calling it.

To pass this responsibility the throws keyword is added after the method declaration, followed by the name of the predicted exception to be handled.

In the program below, if the user enters “10” the program works fine, however if the user enters “ten” an exception occurs in the calc() method but is handled by the catch statement in the main method.

public class test

{

     public static void main(String[] args)

     {

          try

          {

              System.out.println("Number is " + calc(args[0]) );

          }

          catch( NumberFormatException e )

          {

              System.out.println("Wrong format: " + e.getMessage());

          }

     }

 

     public static int calc(String num) throws NumberFormatException

     {

          int number = Integer.parseInt(num);

          return number;

     }   

} //end of test class

 

User defined exceptions

Creating and using your own exceptions brings convenience and power to Java™. The common practice is to extend the exceptions class so that the new class will have access to all of the methods which are available to the Exceptions class. In the following example I create my own exception called TestException. The code below is in one file.

public class test

{

     public static void main(String[] args)

     {

          int i = Integer.parseInt(args[0]);

 

          try

          {

              testUserException(i);

          }catch(TestException e)

          {

              System.out.println(e.getMessage());

          }

     }

 

     public static void testUserException(int val) throws TestException

     {

          if( val < 5 )

              throw new TestException("Number is less than five - EXCEPTION thrown");

          else

              System.out.println("Number greater than 5. Good.");

     }   

} //end of test class

 

 

class TestException extends Exception

{

     TestException(String message)

     {

          super(message);

     }

 

     TestException()

     {

          super();

     }

} //end of user defined exception

If we run the program with i at a value of 6 the program runs fine. If we change it to 3 then the method picks up the TestException and throws it back to the calling method (in this case the main method) to deal with. This is shown by the command window displaying the exception message. Methods can also be added to the TestException class if required.

 

 

Checked and unchecked exceptions

 

 

 

back