Lecture5

advertisement
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()
Download