Chapter 4: Control Structures 1: Selection The order in which program statements are executed is called the “flow of Control” within a program. The default “flow” of control is sequential; statements are executed one after the other in the order in which they occur in the file. This sequential execution represents the most basic organization of statements and is called sequential composition. Statement 1 Statement 2 Statement 3 Statement 4 It is the simplest form of composition with commands being executed strictly in the order that they are encountered and with no commands being excluded from execution and no commands being executed more than once. While useful is insufficient for the creation of large complex program. Example 1: Hello World public class Hello{ public static void main (String args[]) { System.out.println(“Hello World “); System.out.println(“This is Camille”); } } To make programs more flexible and powerful, three other language constructs are needed: o A means of selecting between to or more alternative control flow paths (Selection), based on the evaluation of a Boolean expression. If the expression evaluates to true, one set of statements are performed, if false a different set of statements. Execution then continues with the first statement following the selection construct. F T E Statement 2 Statement 1 o Some means of causing the repeated execution of collections of statements. (Iteration). Here, a set of statements is executed based on the evaluation of a Boolean expression. If the expression is true the statements are executed, then control returns back to the beginning of the loop, and as along as the expression is true the statements are executed. Once false, control goes to the first statement following the loop body. True E False Statements Selection Statements Selection permits the specification of alternate sequences of actions (commands), where the selection of a particular sequence to execute is based on the value of a logical expression. Examples of selection statements are the if & switch statements. Logical expressions A logical expression (Boolean expression) consists of a series of one or more conditional expressions, whose result is either “true” or “false”. A conditional expression has the form: Value1 relational-operator Value2 Where value1 & value2 can be a variable name, a literal value, an arithmetic expression, or the value returned from a method. A Relational operator compare the values of its operands, and returns “true” if the relationship holds, and “false” otherwise. Relational operators, complement the arithmetic operators since they usually appear together in a logical expression. In Java the relational operators are: <, >, <=, >=, = = , != They are left to right associative, but == and != have a lower precedence than the other operators. Relational Operators Operator Use Description > op1 > op2 Returns true if op1 is greater than op2 >= op1 >= op2 Returns true if op1 is greater than or equal to op2 < op1 < op2 Returns true if op1 is less than op2 <= op1 <= op2 Returns true if op1 is less than or equal to op2 == op1 == op2 Returns true if op1 and op2 are equal != op1 != op2 Returns true if op1 and op2 are not equal Example Program #1: public class Rel{ public static void main (String args[]) { int x = 3, y = 3, m = 6, n = 10; String name1 = "Camille"; String name2 = "Camille"; String name3 = new String("Tom"); String name4 = new String("Tom"); System.out.println("The value of x is : " + x + " y is " + y + " m is " + m + " n is " + n); System.out.println("The value of x == y is: " + (x == y)); System.out.println("The value of m >= y is: " + (m >= y)); System.out.println("The value of x <= n is: " + (x <= n)); System.out.println("The value of m < n is: " + (m < n)); System.out.println("The value of n != m is: " + (m != n)); System.out.println("The value of x != y is: " + (x != y)); System.out.println("The value of name1 == name2 is: " + (name1 == name2)); System.out.println("The value of name3 == name4 is: " + (name3 == name4)); } } The results are: /home/hayhurst/java/ch6examples- java Rel The value of x is : 3 y is 3 m is 6 n is 10 The value of x == y is: true The value of m >= y is: true The value of x <= n is: true The value of m < n is: true The value of n != m is: true The value of x != y is: false The value of name1 == name2 is: true The value of name3 == name4 is: false Comparing Strings: The question of comparing strings is somewhat deceiving. Strings are objects and a variable representing a string points to the object and not the value of that string object. If we have two string variables: String str1 = new String(“joe”), str2 = new String(“joe”); If (str1 == str2) is false!!!! This is because each call to NEW allocates new storage, puts the address into the string variable, and stores the value joe into that storage 2500 str1 2500 str2 JOE 23412 23412 JOE To compare the contents of two strings we must use methods in the class String. Some of the methods that do comparison are: 1. . equals(String)… tests to determine if the string values of the two objects are the same value: if (str1.equals(str2)) is TRUE if (str1.equals(“joe”)) is true if (“joe”.equals(str1)) is TRUE if (“Joe.equals(str1)) is FALSE 2. .equalsIgnoreCase(string) -- returns boolean, compares two strings and ignores case. if (“Joe”.equalsIgnoreCase(str1)) is true 3. .compareTo(String) -- returns integer, compares the two strings character by character until two characters at the same index position differ. To use this method we need to understand the relative ASCII values of characters… All character digits < all CAPITAL LETTERS < all lower case letters For example: Adam < adam biLL < bill Suppose str1 < str2 Then: str1.compare(str2) returns a negative value str2.compare(str1) returns a positive value This function returns zero if the two are equal.. Suppose String str1 = new String(“Joe”); String str2 = new String(“Joe Brown”); Then str1 < str2 and str1.compareTo(str2) returns a negative number. 4. The method .compareToIgnoreCase(string) is the same as the .compareTo method but does not take case into account. Logical operators Compound logical expressions contain a series of 2 or more conditional expressions, joined with the logical operators and (&&), or or (||) operators. These are used to construct more complex decision making statements. An additional logical operator not (!) can also be used to negate (reverses) the initial value of an logical expression. The relative precedence of the logical operators is: NOT has the highest precedence of the three, followed by AND and finally OR. Truth table: If P and Q are logical expressions P Q P AND Q P OR Q True True True True True False False True False True False True False False False False !(p) False False True True Example #2: public class Rel2{ public static void main (String args[]) { int x = 3, y = 3, m = 6, n = 10; System.out.println("The value of x is : " + x + " y is " + y + " m is " + m + " n is " + n); System.out.println("The value of (x<m && y<n) is: " + ((x < m) && (y < n))); System.out.println("The value of (x>m && y<n) is: " + ((x > m) && (y < n))); System.out.println("The value of (x<m || y<n) is: " + ((x < m) || (y < n))); System.out.println("The value of (x>m || y<n) is: " + ((x > m) || (y < n))); System.out.println("The value of !(x < m) is : " + !(x<m)); } } The results are: /home/hayhurst/java/ch6examples- java Rel2 The value of x is : 3 y is 3 m is 6 n is 10 The value of (x<m && y<n) is: true The value of (x>m && y<n) is: false The value of (x<m || y<n) is: true The value of (x>m || y<n) is: true The value of !(x < m) is : false Short circuit evaluation; Java provides for short circuit evaluation of multiple logical expressions ( with the && and ||). In this method evaluation stops as soon as the truth of the expression is known: P && Q if P is true then Q is evaluated. If P is false there is no need to evaluate Q. P || Q if P is false then Q is evaluated. If P is true then there is no need to evaluate Q. The purpose of short-circuiting these operations is not just a time-saver, but to avoid the following problem. Consider the following int a=0, b=3; The following logical expression would cause an error: (a != 0) AND (b/(2*a)>0) If a=0, the first part of the expression false and the entire expression is false and evaluation halts. But if short circuit evaluation is not used, when the second condition is evaluated , a division by zero exception is raised, and the program will be terminated – needlessly. Java also additional operators that performs “full evaluation “ of logical expressions: These are & and | . With these operators all sub expressions of a compound expression are evaluated even if the value of the logical expression is known. The IF selection construct. There are several classic forms of the IF selection statement. In the following examples E represents a logical expression which can be evaluated to true or false, and S, S1 & S2 represent sets of one or more executable statements. The one way selection statement If E S1; If the logical expression E is true, then execute step S1, other wise continue with the next executable statement Decision Tree for simple If construct true E S1 In Java, the syntax of this simple if statement is: if (Boolean expression) statement; Sample 1-, simple if with one executable statement. following the condition import java.util.*; public class If1{ public static void main (String args[]) { Scanner instream = new Scanner(System.in); int num; System.out.println("Please enter an integer number and press return."); num = instream.nextInt(); if (num > 0) System.out.println("The number is positive"); System.out.println("All Done"); } } The output is : /home/hayhurst/java/ch6examples- java If1 Please enter an integer number and press return. 34 The number is positive All Done /home/hayhurst/java/ch6examples- java If1 Please enter an integer number and press return. -24 All Done Two way selection The second general from of the IF statements is the “if else” construct. Which specifies a series of actions to perform if the expression is true, and an alternate group of statements if the expression is false. If E Then S1 Else S2; False true E S1 S2 In Java, the syntax of the IF ELSE construct is: if (Boolean expression) statement 1; else statement 2; If Else example import java.util.*; public class If2 { public static void main (String args[]) { Scanner instream = new Scanner(System.in); int magic; int guess; int i; magic = 1325; System.out.print("Enter your guess: "); guess = instream.nextInt(); if (guess == magic) System.out.println (" You are RIGHT!!!"); else System.out.println ("... Sorry you are wrong.."); System.out.println("All Done!!! "); } } Results: /home/hayhurst/java/ch6examples- java If2 Enter your guess: 345 ... Sorry you are wrong.. All Done!!! /home/hayhurst/java/ch6examples- java If2 Enter your guess: 1325 You are RIGHT!!! All Done!!! A language must also allow for the selection construct to allow multiple executable statements in an “if” clause. This creates a BLOCK of statements that will be executed whenever the statement is true or false. import java.util.*; public class If3 { public static void main(String args[]){ Scanner instream = new Scanner(System.in); int magic; int guess; int i; magic = 1325; System.out.print ("Enter your guess: "); guess = instream.nextInt(); if (guess == magic) { /*in java this is resolved via a block */ System.out.println (" You are RIGHT!!!"); System.out.println ( " The number was: " + magic); } else System.out.println ("... Sorry you are wrong.."); System.out.println("All Done !!!!"); } } The results are: /home/hayhurst/java/ch6examples- java If3 Enter your guess: 1234 ... Sorry you are wrong.. All Done !!!! /home/hayhurst/java/ch6examples- java If3 Enter your guess: 1325 You are RIGHT!!! The number was: 1325 All Done !!!! This is a block of statements Nesting of If statements: It is possible to include additional if-else constructs inside the set of executable statements for an “if” statement. When this occurs this is called “nesting”, because one the body of one if statement in contained inside another. A “nested if” can have many different forms including: if (E1) { if (E2) statement; } else statement; OR if (E1) statement; else { if (E2) statement; } Nested if Example import java.util.*; public class nestedIf { public static void main(String args[]) { Scanner in = new Scanner(System.in); int a,b; char ch; String input; System.out.println ("Do you want to Add, Subtract, Multiply or " + "Divide?"); System.out.print ("Please enter the first letter of what you would" + " like to do?"); ch= (in.next().toUpperCase()).charAt(0); System.out.println ("Enter first number: "); a = in.nextInt(); System.out.println ("Enter second number: "); b = in.nextInt(); System.out.println("ch, a, b " + ch + " " + a + " " + b); if (ch == 'A') System.out.println ("Answer is "+ (a+b)); else { // else not A if (ch == 'S') System.out.println ("Answer is "+ (a-b)); else { // else not S if (ch == 'M') System.out.println ("Answer is "+ (a*b)); else { // else not M if (ch == 'D' && b!=0) System.out.println ("Answer is "+ (a/b)); else System.out.println("Division by zero"); } // ends not multiplication } // ends not subtraction } // ends not addition } } Of particular interest when writing nested ifs is how a language deals with nested if statements that have fewer else clauses than if clauses. Consider if (E1) if (E2) s1; else s2; To which “if” does the lone else belong? In general an else clause is paired with the nearest unpaired if clause. So in the above example: if (E2) s1; else s2; is considered a complete statement and executed when the condition E1 is true. When E1 is false the above statement does nothing. To force the alternative meaning in this example we must use {}. if (E1) { if (E2) s1; } else s2; In this case if (E2) s1; is executed when E1 is true and S2 is executed when E1 is false. When nesting if statements, braces can always be used to identify to which if an else clause belongs. The nested example in the previous statement could also be rewritten without the use of “else” clauses, as: import java.util.*; public class nestedIf2 { public static void main(String args[]) { Scanner in = new Scanner(System.in); int a,b; char ch; String input; System.out.println ("Do you want to Add, Subtract, Multiply or " + "Divide?"); System.out.print ("Please enter the first letter of what you would" + " like to do?"); ch= (in.next().toUpperCase()).charAt(0); System.out.println ("Enter first number: "); a = in.nextInt(); System.out.println ("Enter second number: "); b = in.nextInt(); System.out.println("ch, a, b " + ch + " " + a + " " + b); if (ch = = 'A') System.out.println ("Answer is "+ (a+b)); if (ch = = 'S') System.out.println ("Answer is "+ (a-b)); if (ch = = 'M') System.out.println ("Answer is "+ (a*b)); if (ch = = 'D' && b != 0) System.out.println ("Answer is "+ (a/b)); else if (b = =0) System.out.println("Division by zero"); } } Although easier to understand and read, this version is less efficient. In the first version, the evaluation of if statements STOPS as soon as a match is found. In this example, EVERY if statement is evaluated. So we sacrifice efficiency for clarity. Multiple selectors: o Multiple selection constructs or SWITCH statements can be used to simplify the logic of nested/multiple if statements when only ONE execution path will be executed between all of the alternatives. The switch statement allows the selection of one of any number of statements or statement groups and is an extension of the two-way selector. The format of the switch statement is: switch (expression) { case value1: action1; case value2: action2; case value3: action3; …. [default: action m; ] } In this statement, “expression” is a variable, or calculation that yields a value of a “discrete” type. ( A discrete type has a finite number of possible values and are enumeration, integers and character types ). Each “case” clause specifies one possible value of the expression. If the expressions value matches the case, that cases action is performed. Each action can consist of one or more statements. Evaluation stops once a valid case if found. This statement also contains an optional “default” clause. If no matching case is found, the action specified in the default clause is executed. Switch example 1. import java.util.*; public class caseEx1 { public static void main (String args[]) { Scanner in = new Scanner(System.in); int num; System.out.println("Please enter an integer “ + ” number between 1 & 3"); num = in.nextInt(); The output of this example is: Please enter an integer number between 1 & 3 1 The number entered was 1 The number entered was 2 The number entered was 3 Invalid number Good Bye switch (num) { case 1: System.out.println("The number entered was 1"); case 2: System.out.println("The number entered was 2"); case 3: System.out.println("The number entered was 3"); default : System.out.println("Invalid number entered" ); } // end of switch statement System.out.println(“Good Bye”); } } One problem with a switch statement is that once a “case” is selected, control flow returns to sequential, and all remaining cases are executed. To avoid this we place the “break” statement following the last executable statement in each case. This causes execution to jump out of the case statement and to continue with the next sequential statement following the case. To fix our problem: import java.util.*; public class caseEx1 { public static void main (String args[]) { Scanner in = new Scanner(System.in); int num; System.out.println("Please enter an integer “ + ” number between 1 & 3"); The output of this example is: Please enter an integer number between 1 & 3 1 The number entered was 1 Good Bye num = in.nextInt(); switch (num) { case 1: System.out.println("The number entered was 1"); break; case 2: System.out.println("The number entered was 2"); break; case 3: System.out.println("The number entered was 3"); break; default : System.out.println("Invalid number entered" ); } // end of switch statement System.out.println(“Good Bye”); } } Simple Calculator Example import java.util.*; public class switchEx2 { public static void main(String args[]) { Scanner in = new Scanner(System.in); int a,b; char ch; String input; System.out.println ("Do you want to Add, Subtract, Multiply or " + "Divide?"); System.out.print ("Please enter the first letter of what you would" + " like to do?"); ch= (in.next().toUpperCase()).charAt(0); System.out.println ("Enter first number: "); a = in.nextInt(); System.out.println ("Enter second number: "); b = in.nextInt(); switch (ch) { case 'A': System.out.println ("Answer is "+ (a+b)); break; case 'S': System.out.println ("Answer is "+ (a-b)); break; case 'M': System.out.println ("Answer is "+ (a*b)); break; case 'D': if (b != 0) System.out.println ("Answer is "+ (a/b)); else System.out.println("Division by zero"); break; default : System.out.println("Invalid Operation"); } //end of switch System.out.println("Good bye"); } } Sometimes the fact that a switch statement will “fall through” can be used to our advantage, if multiple cases must perform the same action. Lets consider the problem of printing the number of days in a particular month. Scanner in = new Scanner(System.in); int month; System.out.println(“Please enter the desired month as an integer in the range 1 – 12”); month = in.nextInt(); switch (month) { case 1: case 3: case 5: case 7 case 8: case 10: case 12: System.out.println(“The number of days is 31”); break; case 2: System.out.println(“The number of days is 28”); break; case 4: case 6: case 9: case 11: System.out.println(“The number of days is 30”); break; default : System.out.println(“The month entered is invalid”); } Enumeration Types In versions of Java prior to 5.0, we had to make many compromises. For example, suppose our application models traffic flow, and we needed to represent the states of a stop light which are “red”, “yellow” or “green”. Prior to 5.0 these was no easy way to do this.. we would need to do something like: int stopLightState; // 0=green, 1= yellow, and 2=red and rely upon our users correctly using the right values, but since stopLightState was an int, any valid integer could be assigned to it.. In terms of a switch statement to perform some action based on the state of a light: switch ( stopLightState) { case 0: System.out.println(“the light is green”); ……… // some other actions break; case 1: System.out.println(“The light is yellow”); ……. // some other actions break; case 2: System.out.println(“the light is read”); ……. // some other actions break; default: System.out.println(“Invalid state”); } This doesn’t lend itself to understandability. We could improve the situation by: final int RED = 2; final int GREEN = 0; final int YELLOW = 1; switch ( stopLightState) { case GREEN: System.out.println(“the light is green”); ……… // some other actions break; case YELLOW: System.out.println(“The light is yellow”); ……. // some other actions break; case RED: System.out.println(“the light is read”); ……. // some other actions break; default: System.out.println(“Invalid state”); } But it still doesn’t protect our lights from being set to an invalid state. Java 5.0 permits the definition of a USER DEFINED type with a fixed, finite number of values. This type is called an enumerated type. The syntax to define an enumerated type is : Access_specifier enum typename(list of values} In the previous example we could have declared: Public enum stopLightState{ GREEN, YELLOW, RED} We can now define our variable as being of type stopLightState rather than of type int. stopLightState aStopLight = stopLightState.RED; Now our stoplight variable can only take on three possible values..These values are represented as “symbolic” constants Automatic methods for enumeration types When an enumerated type is defined, a couple of useful methods are automatically created for that type. 1. .equals can be used to compare two enumerated variables for equality. if (alight.equals(stopLightState.RED)) 2. .toString can be used to convert an enumerated value to a string. alight.toString()