You are on page 1of 17

8966472.

doc FBE – Computer Science Dept

Mekelle University Faculty of Business & Economics

Computer Science Department

Comp 262: Internet Programming with Java

Handout 4 – Expressions, Statements, Control of Flow

Reference:
You may find it useful to look at the Java tutorial, taken from the Sun Java website, on
the intranet – browse to Computers, Course Materials and look under the heading for
this course.

1 Overview
This handout revises the concepts of expressions and statements. It also covers the
precedence of operators and control of flow in the Java language. Many of these will
be familiar to you if you have already taken the C++ course.

2 Expressions & Operator Precedence


Variables and operators are the basic building blocks of programs. Literals, variables
and operators are combined to form expressions. Expressions perform computations
and return values.
The data type of the return value of an expression depends on the elements used in the
expression. An operator returns a value, so the use of an operator is an expression.
Some examples of expressions are shown in bold in the code snippets below:

int i = 10;
char aChar = 's';

System.out.println ("The value is " + i);

If (Character.isUpperCase (aChar)) {
…………
}

As in other programming languages, there is an order of precedence for the Java


operators. The order is shown in the table below – the operators are listed with highest
precedence at the top of the table and the lowest at the bottom.

Description Operators
Postfix operators – array element reference,
object member access, function call, post- [] . (params) expr++ expr--
increment, post-decrement
Unary operators – pre-increment, pre-decrement, ++expr --expr +expr -expr ~ !
+, -, NOT; ~ is the bitwise complement operator
Creation or cast new (type)expr

Multiplicative * / %

Page 1 of 17
8966472.doc FBE – Computer Science Dept

Additive + -

Shift operators << >> >>>

Relational and instanceof < > <= >= instanceof

Equality (equals, not equals) == !=

Bitwise/boolean AND &

Bitwise exclusive OR ^

Bitwise/boolean inclusive OR |

Conditional AND &&

Conditional OR ||

Conditional (condition ? if_true : if_false) ? :


= += -= *= /= %= &= ^= |= <<= >>=
Assignment and shorthand assignments >>>=

Parentheses should be used to ensure that the order of evaluation of expressions are as
desired.

3 Statements
A statement is a complete unit of execution. Any expression that has a side-effect, i.e.
it changes the state of the program in some way, can be used as a statement simply by
putting a semi-colon after it.
These are assignments, increments and decrements, method calls and object creation.

For example:
i = 10; //assignment
i++; //increment
System.out.println ("Value of i is: + i); //method call
Integer integerObject = new Integer(4); //object creation

Variable declarations are also statements eg:


float f = 1.234;

Control flow statements regulate the order in which statements get executed. These
include if and for statements.

A block is a group of 0 or more statements between curly braces ({}) and can be used
anywhere that a single statement is allowed. Blocks are used to group statements
together e.g. the statements to execute when the condition for an if statement is true.

4 Control Of Flow Statements


4.1 Decision-making
4.1.1 If/else

The If/else statement is a fundamental control statement that is used to make decisions
i.e. to execute statements conditionally. The basic syntax for If in Java is as follows:
if ( expression )
{
statement(s)

Page 2 of 17
8966472.doc FBE – Computer Science Dept

The expression is any conditional expression that returns a boolean value (true or
false).
There must be brackets around the condition expression.
The statements to execute if the expression evaluates to true should be enclosed in a
block.
In this form, if the expression evaluates to false, execution simply moves to the next
line of code after the block.
This can be extended to include an else clause, which is the block of statements to
execute if the expression evaluates to false.

if ( expression )
{
//code to execute if expression is true
statement(s)
}
else
{
//code to execute if expression is false
statement(s)

If there are more than two possible blocks of code to execute, the else/if clause can be
used:
if ( expression1 ){
//code to execute if expression is true
statement(s)
}
else if ( expression2 ){
//code to execute if expression2 is true
statement(s)

}
else {
//code to execute if neither expression 1 nor expression2 is true
statement(s)
}

The if statement can have as many else/if clauses as required, but can have only one
else clause. Using else/if is equivalent to nesting if/else statements – but using else/if
makes the code clearer and easier to read. Nested if/else statements should be clearly
defined with parentheses to avoid confusion and unexpected results.

4.1.2 Switch

However, if there are multiple branching options, a better alternative to if/else is to


use a switch statement. Consider a case where the conditional expression is checking
the value of a particular variable e.g. using an if/else to allocate a grade based on an

Page 3 of 17
8966472.doc FBE – Computer Science Dept

exam mark. The same variable will be evaluated for each block of code – this is
inefficient.
A switch statement evaluates the value of the variable once and then decides which
branch to take based on the value.
The expression evaluated for the switch must return an integer value. Control jumps
to the entry point specified by that value – each entry point is marked with the case
keyword. The end of the block of code to execute for a given value must be marked
with the break keyword (otherwise the code will continue executing to the end of the
switch block).

switch ( integer_expression ) {
case int_value_1:
statements;
break;
case int_value_2:
statements;
break;
case int_value_3:
statements;
break;
default:
statements;
break;
}

The default case is optional, and is executed if the value of integer_expression does
not match any of the cases.
More than one case clause can label the same set of statements e.g. if, in the example
above, if the cases for int_value_1 and int_value_2 result in the same statements being
executed:
case int_value_1:
case int_value_2:
statements;
break;

The expression can be a char type – because a char is represented by the


corresponding Unicode value, which is an integer.
There are circumstances where an if/else must be used – because the switch can only
make decisions based on an integer value. The if/else is more flexible because the test
expression can be any expression that returns a boolean value.

4.1.3 Conditional Operator

Java provides a conditional operator that is similar to an if/else statement.


For example, consider the following if/else statement:

if ( i > j ) {
System.out.println ("max is i");
}
else {
System.out.println ("max is j");
}

Page 4 of 17
8966472.doc FBE – Computer Science Dept

Using the conditional operator, ?, this can also be written as:


(i > j ) ? System.out.println ("max is i") : System.out.println
("max is j")

Of it can be written like this:

System.out.println ("max is " + ( (i > j ) ? i : j));

The condition appears before the ?. The statement to execute if the condition is true
appears after the ? and before the :. The statement to execute if the condition is false
appears after the :.

4.2 Loops
4.2.1 For

The For statement allows a piece of code to be executed a specified number of times,
in an iterative loop.
The syntax is:

for ( initialisation ; termination ; update )


statement_block

The initialisation is executed at the beginning of the loop. It is usually used to set the
initial value of the counter used to control loop execution.
The termination is the test that determines when to exit the loop. It is an expression
that is evaluated at the beginning of each iteration. When it is true, the loop
terminates.
The update is an expression that is evaluated at the end of each iteration. It usually
increments or decrements the counter used to control loop execution.

For example:

System.out.println ("Countdown from 10…\n");


for (int i=10 ; i >= 0 10; i--)
{
System.out.println (i);
}

The for loop is frequently used to iterate through the values in an array.
The intialization expression can be used to declare a local variable – the scope of this
variable is the for statement and the block it controls – so it can be used in the
termination and update expressions as well as within the block.

String[] monthsArray = {"January",


"February","March","April","May","June","July","August","September",
"October","November","December"};
//display the months

for (int i=0 ; i < monthsArray.length ; i++ }


{
System.out.println (monthsArray[i] + "\n");

Page 5 of 17
8966472.doc FBE – Computer Science Dept

4.2.2 While and Do-while

The while statement is another looping mechanism, that allows a block of code to be
executed repetitively while a specified condition is true.
A for loop is used when the programmer knows how many times the code block is to
be executed. With a while loop, the number of times the loop is executed can vary
with each time the code is run.

while ( expression )
statement_block

The expression is evaluated at the beginning of each repetition of the loop.


Expression must return a boolean value. If it is true, the code in the statement_block is
executed. If it is false, execution moves to the next statement in the program, after the
statement_block.

A do-while loop is similar, except that the condition is evaluated at the end of each
repetition of the statement_block:

do {
statement_block
} while ( expression )

The difference between the while and the do-while loops is that the statement_block in
the do-while is guaranteed to be executed at least once – because the expression is not
evaluated at the end of the loop. The statement_block in a while loop may not execute
at all, if expression evaluates to false on the first loop.

For example:

//a simple while loop to count up to 10


int counter = 0;
while ( counter <= 10 ) {
System.out.println (counter);
counter++;
}

The same loop as a do-while:

//a simple while loop to count up to 10


int counter = 0;
do {
System.out.println (counter);
counter++;
}
while ( counter <= 10 );

Page 6 of 17
8966472.doc FBE – Computer Science Dept

This example shows a while loop where the number of times that the block of code is
executed is unknown – because it depends on user input (the full code needed to run
this example is in the Demos directory, named DemoWhile.java).

int input1;
//prompt the user to enter a number between 1 and 10, and set up a
//BufferedReader to read in the inputs
…………
//use a while loop to keep asking the user for another number if the
//entered value is not in the range 1 to 10.
while (input1 < 1 || input1 > 10 ) {

System.out.println ("number must be between 1 and 10 inclusive...try


again");
//don't forget to read in the new value
input1 = Integer.parseInt(in.readLine ());
}

4.3 Branching/Jump Statements


4.3.1 Break

The break statement causes the interpreter to skip immediately to the end of a
containing statement – the flow of control then transfers to the statement following
the end of the statement. The containing statement can be a switch, for, while or do-
while.
In a switch statement, the statements to execute for each case should be followed by a
break. If there is no break, the next case will also be executed. As seen in the example
for switch above:

switch ( integer_expression ) {
case int_value_1:
statements;
break;
case int_value_2:
statements;
break;
case int_value_3:
statements;
break;
default:
statements;
break;
}

The break can be used to exit out of a for, while or do-while loop also. This is
sometimes possible, for efficiency e.g. if the loop is searching for a particular value or
object then there is no need for it to continue after the value or object has been found.
For example – searching through an array to find a value:
//an array of integers

//an array of integers


int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076, 2000, 8, 622, 127 };
int searchfor = 12; //value to search for

Page 7 of 17
8966472.doc FBE – Computer Science Dept

int i = 0;
boolean foundIt = false; //flag to indicate if value is found

for ( ; i < arrayOfInts.length; i++) {


if (arrayOfInts[i] == searchfor) {
foundIt = true;
break; //exit the for loop when the value has been found
}
}

The break statement can also be followed by a label name. A label name can be placed
before any statement or statement block and is followed by a colon.
When a break is followed by a label name, the interpreter immediately exits the
named block. This means that a labelled break can be used to exit statements other
than switch, for, while and do-while.
If, for example, you have a for loop nested inside another one, you can use a label to
ensure that a break exits both loops rather than just the inner loop.

Taking the example above again – if the array is an array of arrays, then two for loops
are needed to search through all the arrays.

int[][] arrayOfInts = { { 32, 87, 3, 589 },


{ 12, 1076, 2000, 8 },
{ 622, 127, 77, 955 }
};
int searchfor = 12;

int i = 0;
int j = 0;
boolean foundIt = false;

//label the outer for loop


search:
for ( ; i < arrayOfInts.length; i++) {
for (j = 0; j < arrayOfInts[i].length; j++) {
if (arrayOfInts[i][j] == searchfor) {
foundIt = true;
break search; //exit both for loops
}
}
}

Class exercise: amend the while loop code in the DemoWhile class, so that the
program will ask the user for a value 5 times and then stop asking. If the user does not
supply the value in 5 attempts, the program gives up.

4.3.2 Continue

The continue statement causes the interpreter to quit the current iteration of a loop
and start the next one. It can only be used in a while, do or for loop.

Page 8 of 17
8966472.doc FBE – Computer Science Dept

Like the break statement, continue can also be labelled. When it is not labelled it quits
the current iteration of the innermost loop. If it is labelled, it quits the iteration of the
labelled loop or, if it is not a loop, just exits the statement.

This may be used where some condition indicates that it is not necessary to execute
all of the code in the loop. For example, if iterating through an array of objects to
carry out some form of processing one each one, if an array element is empty or has
no value, then the iteration can be exited.

for (int i = 0; i < dataArray.length; i++) {


if ( dataArray[i] = = -1 )
continue; //quit this iteration
process(dataArray[i])'
}

Note that the way in which a new iteration is started differs slightly for for, while and
do-while loops:
• In a for loop, the interpreter jumps to the top of the loop – it evaluates the
update expression (here, an increment) and then evaluates the termination
expression.
• In a while loop, the interpreter returns to the top of the loop and evaluates the
loop condition expression again.
• In a do-while loop, the interpreter jumps to the bottom of the loop, to evaluate
the condition expression again.

4.3.3 Return

The return statement exits from the current method. If the method is declared to return
a value, the return must be followed by an expression to be returned. The data type of
the expression must be the same as the declared return type of the method.

If a method is declared to return void, a return statement is not required – the


interpreter will execute the statements until it reaches the end of the method.
However, if it is necessary to return from the method before the last statement, a
return statement can be used.

4.4 Exception Handling


Runtime errors that occur in Java are called 'exceptions'. These are distinct from
errors that are found at the time of compiling.
Errors that are detected by the compiler are generally syntax errors. These include
errors such as:
• Missing semi-colons at the end of statements
• Missing or extra brackets or curly braces in classes and methods
• Misspelling of identifiers and keywords
• Use of undeclared variables
• Incompatible types in assignments and initialisations
• References to non-existent objects
• Use of = instead of the = = operator

Page 9 of 17
8966472.doc FBE – Computer Science Dept

However, even if a program is syntactically correct and compiles, it can still produce
errors at runtime. These types of errors include the following:
• Dividing an integer by 0
• Accessing an element that is out of bounds in an array
• Trying to store a value into an array of an incompatible class of type
• Passing a parameter that is not in a valid range or value for a method
• Using a null object reference to access a method or a variable
• Converting an invalid string to a number
• Accessing a character that is out of bounds in a string

There are many other possible runtime errors.


When the interpreter encounters such an error, it generates an error message and
aborts the program. For example, the class below will compile because it is
syntactically correct.

public class DemoError1 {

public static void main (String[] args)


{
int a = 10;
int b = 5;
int c = 5;

int x = a/(b-c); //division by zero


System.out.println ("x = " + x);
}

}
Figure 1 – class DemoError1 - code that compiles but will produce a runtime error
But when this class is run, it produces a runtime error because there is a division by
zero. The error message reads like this:

Exception in thread "main" java.lang.ArithmeticException: / by zero


at DemoError1.main(DemoError1.java:9)

The text in bold is a Java exception object. A Java exception is a condition that is
caused by a runtime error in a program. The interpreter creates the exception object
and throws it i.e. informs the program caller that an error has occurred.
If the exception is not caught and handled properly in the program code, the
interpreter displays a message like the one shown above and halts execution of the
program.
In order to have the program continue executing, the code has to catch the exception
object thrown by the error condition and then take some corrective action. This is
known as exception handling.
Some common exceptions are listed in the table below.

Exception Type Caused by


ArithmeticException Math errors e.g. division by zero

Page 10 of 17
8966472.doc FBE – Computer Science Dept

ArrayIndexOutOfBoundsException Trying to access an array element beyond the


length of the array e.g. myArray[10] when the
array length is 10.
ArrayStoreException Trying to store the wrong type of data in an array
e.g. trying to put a String object into an array of
Integers.
FileNotFoundException Trying to access a file that does not exist
IOException General I/O (input/output) failures e.g. cannot
read from a file or from standard input
NullPointerException Referencing a null (non-existent) object
NumberFormatExcetion A conversion between string and number types
fails e.g. reading input from args paremeter to a
main method – if a number is expected but a
string is supplied, will get a
NumberFormatException
StringIndexOutOfBoundsException Attempting to access a character position that
does not exist in a string e.g. trying to access
character number 5 in the string "Java".

There are many other exceptions, but the above are common types of exception that
you are likely to come across.

4.4.1 Try/catch

The syntax for catching exceptions and handling them is as follows. It consists of a
try block, which throws the exception object, followed by a catch block, which
catches and handles the exception.

try {
Statement that may cause the exception
}

catch ( Exception_type parameter_name) {


Statement that handles the exception
}

The try block can have one or more statements that could generate an exception. If
any one of the statements causes an exception, execution of the remaining statements
in the block is skipped and execution jumps to the catch block.
The catch block contains one or more statements to handle the exception. The catch
statement takes one parameter – a reference to the exception object that was thrown
by the try block. If the type of the thrown exception matches the type of the
parameter, then the exception will be caught and the statements in the catch block will
be executed. The parameter_name can be used to refer to the exception object within
the catch block.
Any statements following the catch block are then executed – i.e. execution of the
program does not stop when an exception is handled.
For example, to catch the ArithmeticException that is thrown by the example given
above:

public class DemoError1 {

public static void main (String[] args)


{

Page 11 of 17
8966472.doc FBE – Computer Science Dept

int a = 10;
int b = 5;
int c = 5;
int x;

try {
x = a/(b-c); //division by zero
System.out.println ("x = " + x);
}

catch (ArithmeticException e) {
System.out.println ("Error: division by zero");
}

}
Figure 2 – class DemoError1 – amended to catch and handle the runtime exception

If a block of statements could potentially generate multiple different types of


exception, different catch blocks can be written to catch each type.
When an exception is generated in the try block, the interpreter treats the multiple
catch statements like cases in a switch – it finds the catch statement whose parameter
matches the type of the thrown exception object.
If you are unsure what exception is being thrown by a block of code, put a catch block
for exceptions of type Exception – as all exceptions are sub-classes of this, this block
will catch any exception. However, this should only be used as a failsafe, after
catching other, known exception types, or to debug the program.

try {
statement;
}

catch (Exception_type1 e) {
statement;
}
catch (Exception_type2 e) {
statement;
}
catch (Exception_type3 e) {
statement;
}
//the last catch block should catch all other types of exception
catch (Exception e) {
statement;
}

The statements in a catch block should be designed to cope with the type of exception
that occurred, and to recover from the exception if possible. In some cases, this may
only be to inform the user, if the program is interactive. In other cases, it may require
logging the error to an error log (i.e. writing to a file) and/or taking some corrective
action.

Page 12 of 17
8966472.doc FBE – Computer Science Dept

Note that it is not necessary to put any processing statements in the block – it can be
empty. In that case, the catch block is there simply to avoid the program execution
being stopped. An empty block is created by putting a semi-colon after the catch
statement. For example:

catch (Exception e);

It is not necessary to have a catch block for every possible exception. If an exception
is thrown by a method and not caught in that method, it propagates up and is caught
by the method that invoked that method. It may be better sometimes to allow the
invoking method to catch the exception and handle it.

The Throwable superclass has some useful methods that can be used to get more
information about an exception.
The getMessage() method returns any error message associated with the exception.
The toString() method returns a string representation of the exception, including the
full name of the exception class (e.g. java.lang.ArithmeticException) and the error
message.
These can be used for debugging purposes or to display more information to the user
of the program.
For example:

try {
statement;
}

catch (Exception e) {
System.out.println ("Error message:\n" + e.getMessage()
+ "\n" + e.toString());
}

4.4.2 Finally

The finally statement can be used after a try block or after a try/catch block.
Generally, the code in the finally block is used to clean up after the code in the try
block e.g. close any open files, release system resources, display some output to the
user.
The finally block is guaranteed to be executed if any part of the try block is executed,
if the try block executes with no exceptions or with exceptions. Even if an exception
is thrown and there is no catch statement for it, the finally block will execute before
program execution ends.

Using the finally block means that the programmer does not have to put the same
clean-up code in both the try and catch blocks. Even if there are multiple catch blocks,
there is only one finally block.

A finally block can be added after a try block, if there are no catch blocks. Or it can be
added after the catch block(s).

Page 13 of 17
8966472.doc FBE – Computer Science Dept

try {
statement;
}

catch (Exception_type e) {
statement;
}
finally {
statement; //clean up
}

4.4.3 Throwing Exceptions

The classes of exception described above are all runtime exceptions. Because these
can happen often, they are automatically thrown by methods. These are also called
'unchecked exceptions'.
There are some types of exception that need to be explicitly thrown by methods.
These are called 'checked exceptions'. They are checked because the compiler checks
to make sure they have been declared or handled.
Unchecked exceptions, on the other hand, do not have to be declared or handled. For
example, in the class DemoError1, shown in Figure 1 above, there is no try/catch
statement. The class does compile but when it is run, it generates an
ArithmeticException. This exception type is unchecked – the compiler does not check
that it has been declared or handled.

An example of a checked exception is IOException. This occurs when there are


problems with reading or writing to files or standard input/output. If a method
contains code that could generated an IOException, the compiler will produce an
error. Consider the class, DemoError2, shown in the figure below.

import java.io.*;

public class DemoError2 {

public void getInput ()


{
BufferedReader in = new BufferedReader (new
InputStreamReader(System.in));
System.out.println ("Enter a value\n");
String input1 = in.readLine();
System.out.println ("You entered: " + input1);
}

}
Figure 3 – class DemoError2 – does not compile because IOException is not declared
When this class is compiled, the following error is reported by the compiler:

java:13: unreported exception java.io.IOException; must be caught or


declared to be thrown
String input1 = in.readLine();

Page 14 of 17
8966472.doc FBE – Computer Science Dept

This is because the attempt to read the input could generate an exception of type
IOException, which is a checked exception. In order to compile the class, it must
explicitly declare that it throws the exception, or handle the exception.
To throw the exception, the method signature must include the keyword throws and
the exception type. The exception is then thrown 'up' to whatever method invokes the
getInput() method.

import java.io.*;

public class DemoError2 {

public void getInput () throws IOException


{

BufferedReader in = new BufferedReader (new


InputStreamReader(System.in));
System.out.println ("Enter a value\n");
String input1 = in.readLine();
System.out.println ("You entered: " + input1);
}

}
Figure 4 – class DemoError2, amended to throw the IOException
Alternatively, the method getInput() needs to catch and handle the exception itself.

import java.io.*;

public class DemoError2 {

public void getInput ()


{

BufferedReader in = new BufferedReader (new


InputStreamReader(System.in));
System.out.println ("Enter a value\n");
try {
String input1 = in.readLine();
System.out.println ("You entered: " + input1);
}

catch (IOException e) {
System.out.println ("Could not read input:\n" +
e.toString());
}
}
}

All exception types are sub-classes of the Exception class, which is in turn a sub-class
of the Throwable class. Unchecked exception types inherit from a sub-class of
Exception, called RuntimeException. The class hierarchy for the exception types we
have seen here are shown in Figure 5 below.

Page 15 of 17
8966472.doc FBE – Computer Science Dept

This does not include all the exception classes, but it does show some of those that
you are likely to encounter at this stage.

Object

Throwable

Exception

Checked exceptions

Unchecked exceptions (subclasses of


IOException RuntimeException RuntimeException)

FileNotFoundException ArithmeticException IndexOutOfBoundsException ArrayStoreException

NullPointerException

ArrayIndexOutOfBoundsException StringIndexOutOfBoundsException

Figure 5 – part of the class hierarchy for Exception objects

If an exception is thrown by method A, the method that invoked method A must then
catch the exception, or, in turn, throw it itself.
In this way, exceptions can be propagated up the chain of methods. If the exception is
never caught (by a catch block), it propagates all the way up to the main method of
the program – i.e. the point where the interpreter started running the program.
If the main method does not handle the exception, the interpreter prints out an error
message, including a stack trace that shows where the error occurred. The stack trace
shows the chain of method calls that resulted in the exception occurring.

Exceptions can also be explicitly thrown within the body of a method. Each exception
class also has a constructor that takes one string parameter, which can be used to pass
a description of the error to the exception object. For example:

public static double factorial (int x) {


if (x<0)
throw new IllegalArgumentException ("x must be >= 0");
double fact;
for (fact=1.0; x > 1; fact*=x, x--)
;
return fact;
}

Page 16 of 17
8966472.doc FBE – Computer Science Dept

When the IllegalArgumentException above is caught, the message displayed by the


interpreter will include the text 'x must be >= 0', as this is passed to the constructor of
the exception object.

It is also possible to define your own exception sub-classes, to throw when particular
error conditions occur. A new exception sub-class must inherit from (extend) the
Exception class.
However, this should only be done if none of the built-in exception classes provide
enough information to diagnose the cause of an error.

Notes prepared by: FBE Computer Science Department.

Page 17 of 17

You might also like