Handout 4 - Expressions, Statements, Control Of Flow

  • November 2019
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Handout 4 - Expressions, Statements, Control Of Flow as PDF for free.

More details

  • Words: 5,079
  • Pages: 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, postincrement, post-decrement

[] . (params) expr++ expr--

Unary operators – pre-increment, pre-decrement, +, -, NOT; ~ is the bitwise complement operator

++expr --expr +expr -expr ~ !

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 dowhile. 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 ArithmeticException

Caused by Math errors e.g. division by zero Page 10 of 17

8966472.doc

ArrayIndexOutOfBoundsException ArrayStoreException FileNotFoundException IOException NullPointerException NumberFormatExcetion

StringIndexOutOfBoundsException

FBE – Computer Science Dept

Trying to access an array element beyond the length of the array e.g. myArray[10] when the array length is 10. Trying to store the wrong type of data in an array e.g. trying to put a String object into an array of Integers. Trying to access a file that does not exist General I/O (input/output) failures e.g. cannot read from a file or from standard input Referencing a null (non-existent) object 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 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

int int int int

FBE – Computer Science Dept

a = 10; b = 5; c = 5; 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 statement; } catch (Exception_type2 statement; } catch (Exception_type3 statement; } //the last catch block catch (Exception e) { statement; }

e) { e) { e) { should catch all other types of exception

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

try { }

FBE – Computer Science Dept

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

IOException

FileNotFoundException

RuntimeException

ArithmeticException

Unchecked exceptions (subclasses of RuntimeException)

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

Related Documents