int x, y, z;
x < y
x > y
x <= y
x >= y
x == y
x != y
WARNING: Don't confuse x = y and x == y!!!!!
double x, y, z;
x < y
x > y
x <= y
x >= y
x == y
x != y
Beware of x == y:
x == Math.sqrt(x * x); // returns false!
Use this instead:
class MyUtils {
private static final double DELTA =
1e-10;
public static boolean close(double x,
double y) {
return Math.abs(x – y) <= DELTA;
}
// etc.
}
Use == for literal equality and equals for logical equality.
String s1 = "Hello", s2 = "Hello", s3 = s1;
s1 == s2; // = false
s1 == s3; // = true
s1.equals(s2); // = true
s2.equals(s3); // = true
String s4 = "bye";
s1.compareTo(s4) < 0 // = false
Rectangle r1(2, 3, 5, 6), r2(2, 3, 5, 6), r3 = r1, r4
r1 == r2 // = false
r1 == r3 // = true
r1.equals(r2) // = true
r4 == null // = true
boolean a = true, b = false, c = true, d;
a && b && c // = false
a || b || c // = true
!(a && b) // = true
!(a && b) = !a || !b // DeMorgan's Law
Selections, also called conditionals, allow programmers to specify that a command should be executed only if a certain condition is true. Of course the truth of the condition generally won't be known until runtime. Selections are classified as one-way, two-way, and multi-way.
The form of a one-way selection is:
if (EXPRESSION) COMMAND;
Semantically, the expression, called the condition, is evaluated. If the value of this expression is true, then the command is executed, otherwise, control falls through to the next command. We often use fragments of flowcharts to describe the semantics of control commands:
One-way selections are typically used to terminate programs and functions when error conditions arise. For example, the following command might be used early in main to terminate the program if the value of x isn't positive:
if (x <= 0) return 1; // STOP, x must be positive!
// control only reaches this point if 0 < x
The syntax of a two-way selection is
if (EXPRESSION) COMMAND; else COMMAND;
Once again, the expression is called the condition. The first command is called the consequence, and the second command is called the alternative:
if (CONDITION) CONSEQUENCE; else ALTERNATIVE;
Semantically, the condition is evaluated. If its value is true, then the consequence is evaluated and the alternative is ignored. Otherwise, the alternative is evaluated and the consequence is ignored. Here's the flowchart representation:
In the following example, a two-way selection prevents the user from dividing by zero:
if (den) {
result = 1/den;
} else {
System.err.println("can't divide
by 0");
}
Multi-way selections can be achieved by nesting two-way selections:
if (income < 0)
System.err.println("income must be non-negative");
else if (income < 10000)
tax = 0;
else if (income < 20000)
tax = .2 * income;
else if (income < 35000)
tax = .3 * income;
else if (income < 50000)
tax = .5 * income;
else
tax = .75 * income;
Question: What would a flow chart for this command look like?
Question: Why don't we need to check that income is also greater than or equal to the lower limit:
if (income < 0)
System.err.println("income must be non-negative");
else if (0 <= income && income < 10000)
tax = 0;
else if (10000 <= income && income < 20000)
tax = .2 * income;
// etc.
Beware of the dangling else.
Question: How much tax does a person making $15,000 pay? (Answer = unknown.) $8000? (Answer = $800.)
if (income < 10000)
if (5000 < income)
tax = .1 * income;
else tax = .2 * income;
Both Java and C++ inherit the bizarre switch command from C. The syntax and semantics of the switch command are so awkward that they almost render the command unusable. Here is the syntax:
switch(EXPRESSION)
{
case EXPRESSION: COMMANDS
case EXPRESSION: COMMANDS
case EXPRESSION: COMMANDS
// etc.
default: COMMANDS
}
The expression in parenthesis, called the key, must produce an integer or integer subtype value when executed. The switch command contains one or more case clauses. Each case clause begins with an expression called a guard, followed by zero or more commands, called consequences. The last case clause traditionally begins with the reserved word "default". The list of commands following it are called alternatives:
switch(KEY)
{
case GUARD: CONSEQUENCES
case GUARD: CONSEQUENCES
case GUARD: CONSEQUENCES
// etc.
default: ALTERNATIVES
}
Semantically, the key is evaluated. The value of the key is compared to the value of each guard, starting with the topmost guard. When a match is found, all commands following the guard, including commands that follow subsequent guards, are executed. The defaule guard matches all keys. For example, here is a flowchart describing the semantics of a switch command with three case clauses guarded by expressions called GUARD1, GUARD2, and GUARD3, respectively:
Notice that if KEY == GUARD1 is false, but KEY == GUARD2 is true (i.e., not 0 or false), then CONSEQUENCES1 will be ignored, but CONSEQUENCES2 and CONSEQUENCES3 will be executed. This happens even if KEY == GUARD3 is false!
To prevent the consequences of subsequent case clauses from being executed, programmers often end each sequence of consequences with a break command. Break commands will be discussed later. Essentially, a break command causes control to exit the current control command and pass to the next command.
Here's an example of a switch command:
switch(op)
{
case '+': result = arg1 + arg2; break;
case '*': result = arg1 * arg2; break;
case '-': result = arg1 - arg2; break;
case '%': result = arg1 % arg2; break;
case '/':
if (arg2) result = arg1 / arg2;
else System.err.println("can't divide by
0");
break;
default: System.err.println("unrecognized operator " +
op);
}
We can only use this switch command if op happens to be declared as a character, since char is a subtype of int:
double arg1, arg2, result;
char op; // = operator used to combine arg1 & arg2
If we declare op as a string:
string op;
then we must use nested if commands.
What happens if several commands must be executed when a condition is true:
if (CONDITION)
COMMAND1;
COMMAND2;
COMMAND3;
Unfortunately, the compiler ignores indentation. Commands 2 and 3 will be executed if CONDITION is true or false.
However, most languages allow programmers to group a sequence of commands into a single command called a sequence. Syntactically, a sequence is just a list of commands, each terminated by a semi-colon, delimited by curly braces:
{ COMMAND; COMMAND; COMMAND; etc. }
Semantically, each command in a sequence is executed in order of appearance:
The following example shows how several commands can be grouped into a single command serving as the consequence of a conditional. Note that this example also shows that commands can be nested inside of commands. It also shows that sequences may contain declarations. A sequence that contains declarations is called a block. These will be discussed in the next chapter:
if (rad > 0)
{
int min = center + rad;
int max = center + rad;
if (min < result && result < max)
{
double error = fabs(result - center);
System.out.println("you only missed by
" +
error + " inches");
}
}
import java.util.Scanner;
public class Calculator {
public static void main(String[] args)
{
Scanner kbd = new
Scanner(System.in);
System.out.print("enter an
arithmetic expression: ");
if (!kbd.hasNextDouble()) {
System.err.println("First
argument must be a double");
return;
}
double arg1 = kbd.nextDouble();
String op = kbd.next();
if (!kbd.hasNextDouble()) {
System.err.println("Second
argument must be a double");
return;
}
double arg2 = kbd.nextDouble();
if (op.equals("+")) {
System.out.println("result =
" + (arg1 + arg2));
} else if (op.equals("*"))
{
System.out.println("result =
" + (arg1 * arg2));
} } else if
(op.equals("-")) {
System.out.println("result =
" + (arg1 - arg2));
}} else if
(op.equals("/")) {
System.out.println("result =
" + (arg1 / arg2));
}
else {
System.err.println("Unrecognized
operator: " + op);
}
}
}
public class BankAccount {
private double balance;
private String password;
public BankAccount(String pswd) {
password = pswd;
balance = 0;
}
private boolean isAuthorized(String
pswd) {
return password.equals(pswd);
}
public double getBalance(String pswd) {
if (isAuthorized(pswd)) {
return balance;
} else {
System.err.println("password
error");
return 0;
}
}
public void deposit(double amt, String
pswd) {
if (isAuthorized(pswd)) {
balance = balance + amt;
} else {
System.err.println("password
error");
}
}
public void withdraw(double amt, String
pswd) {
if (isAuthorized(pswd) &&
amt <= balance) {
balance = balance - amt;
} else {
if (amt <= balance) {
System.err.println("password
error");
} else {
System.err.println("insufficient
funds");
}
}
}
}