CHAPTER GOALS
To be able to implement decisions using if statements
To effectively group statements into blocks
To learn how to compare integers, floating-point numbers, strings, and objects
To correctly order decisions in multiple branches and nested branches
To program conditions using Boolean operators and variables
T To be able to design tests that cover all parts of a program
The programs we have seen so far were able to do fast computations and render graphs, but they were very inflexible. Except for variations in the input, they worked the same way with every program run. One of the essential features of nontrivial computer programs is their ability to make decisions and to carry out different actions, depending on the nature of the inputs. The goal of this chapter is to learn how to program simple and complex decisions.
Computer programs often need to make decisions, taking different actions depending on a condition.
Consider the bank account class of Chapter 3. The withdraw method allows you to withdraw as much money from the account as you like. The balance just moves ever further into the negatives. That is not a realistic model for a bank account. Let's implement the withdraw method so that you cannot withdraw more money than you have in the account. That is, the withdraw method must make a decision: whether to allow the withdrawal or not.
The if
statement is used to implement a decision. The if statement has two parts: a condition and a body. If the condition is true, the body of the statement is executed. The body of the if statement consists of a statement:
if (amount <= balance) // Condition balance = balance - amount; // Body
The if statement lets a program carry out different actions depending on a condition.
The assignment statement is carried out only when the amount to be withdrawn is less than or equal to the balance (see Figure 1).
Let us make the withdraw
method of the BankAccount
class even more realistic. Most banks not only disallow withdrawals that exceed your account balance; they also charge you a penalty for every attempt to do so.
This operation can't be programmed simply by providing two complementary if
statements, such as:
if (amount <= balance) balance = balance - amount; if (amount > balance) // Use if/else instead balance = balance - OVERDRAFT_PENALTY;
There are two problems with this approach. First, if you need to modify the condition amount <= balance
for some reason, you must remember to update the condition amount > balance
as well. If you do not, the logic of the program will no longer be correct. More importantly, if you modify the value of balance
in the body of the first if
statement (as in this example), then the second condition uses the new value.
To implement a choice between alternatives, use the if/else
statement:
if (amount <= balance) balance = balance - amount; else balance = balance - OVERDRAFT_PENALTY;
Now there is only one condition. If it is satisfied, the first statement is executed. Otherwise, the second is executed. The flowchart in Figure 2 gives a graphical representation of the branching behavior.
Quite often, however, the body of the if
statement consists of multiple statements that must be executed in sequence whenever the condition is true. These statements must be grouped together to form a blockstatement by enclosing them in braces { }
. Here is an example.
if (amount <= balance) { double newBalance = balance - amount; balance = newBalance; }
A block statement groups several statements together.
In general, the body of an if
statement must be a block statement, a simple statement, such as
balance = balance - amount;
or a compound statement (another if
statement or a loop—see Chapter 6). The else
alternative also must be a statement—that is, a simple statement, a compound statement, or a block statement.
2. What is logically wrong with the statement
if (amount <= balance) newBalance = balance - amount; balance = newBalance;
and how do you fix it?
A relational operator tests the relationship between two values. An example is the <=
operator that we used in the test
if (amount <= balance)
Java has six relational operators:
Java | Math Notation | |
---|---|---|
| > | Greater than |
| ≥ | Greater than or equal |
| < | Less than |
| ≤ | Less than or equal |
| = | Equal |
| ≠ | Not equal |
As you can see, only two relational operators (>
and <
) look as you would expect from the mathematical notation. Computer keyboards do not have keys for ≥, ≤, or ≠, but the >=, <=
, and !=
operators are easy to remember because they look similar.
The ==
operator is initially confusing to most newcomers to Java. In Java, the =
symbol already has a meaning, namely assignment. The ==
operator denotes equality testing:
a = 5; // Assign 5 to a if (a == 5) ... // Test whether a equals 5
You will have to remember to use ==
for equality testing, and to use =
for assignment.
The relational operators have a lower precedence than the arithmetic operators. That means, you can write arithmetic expressions on either side of the relational operator without using parentheses. For example, in the expression
amount + fee <= balance
both sides (amount + fee
and balance
) of the < operator are evaluated, and the results are compared. Appendix B shows a table of the Java operators and their precedence.
You have to be careful when comparing floating-point numbers, in order to cope with roundoff errors. For example, the following code multiplies the square root of 2 by itself and then subtracts 2.
double r = Math.sqrt(2); double d = r * r - 2; if (d == 0) System.out.println("sqrt(2) squared minus 2 is 0"); else System.out.println( "sqrt(2) squared minus 2 is not 0 but " + d);
Even though the laws of mathematics tell us that (√2)2 – 2 equals 0, this program fragment prints
sqrt(2) squared minus 2 is not 0 but 4.440892098500626E-16
Unfortunately, such roundoff errors are unavoidable. It plainly does not make sense in most circumstances to compare floating-point numbers exactly. Instead, test whether they are close enough.
To test whether a number xis close to zero, you can test whether the absolute value |x| (that is, the number with its sign removed) is less than a very small threshold number. That threshold value is often called ɛ (the Greek letter epsilon). It is common to set ɛ to 10–14 when testing double
numbers.
When comparing floating-point numbers, don't test for equality. Instead, check whether they are close enough.
Similarly, you can test whether two numbers are approximately equal by checking whether their difference is close to 0.
In Java, we program the test as follows:
final double EPSILON = 1E-14; if (Math.abs(x - y) <= EPSILON) // x is approximately equal to y
To test whether two strings are equal to each other, you must use the method called equals
:
if (string1.equals(string2)) ...
Do not use the ==
operator to compare strings. The expression
if (string1 == string2) // Not useful
has an unrelated meaning. It tests whether the two string variables refer to the identical string object. You can have strings with identical contents stored in different objects, so this test never makes sense in actual programming; see Common Error 5.2 on page 180.
Do not use the ==
operator to compare strings. Use the equals
method instead.
In Java, letter case matters. For example, "Harry"
and "HARRY"
are not the same string. To ignore the letter case, use the equalsIgnoreCase
method:
if (string1.equalsIgnoreCase(string2)) ...
If two strings are not identical to each other, you still may want to know the relationship between them. The compareTo
method compares strings in dictionary order. If
string1.compareTo(string2) < 0
then the string string1
comes before the string string2
in the dictionary. For example, this is the case if string1
is "Harry"
, and string2
is "Hello"
. If
string1.compareTo(string2) > 0
then string1
comes after string2
in dictionary order. Finally, if
string1.compareTo(string2) == 0
then string1
and string2
are equal.
The compareTo
method compares strings in dictionary order.
Actually, the "dictionary" ordering used by Java is slightly different from that of a normal dictionary. Java is case sensitive and sorts characters by putting numbers first, then uppercase characters, then lowercase characters. For example, 1
comes before B
, which comes before a
. The space character comes before all other characters.
Let us investigate the comparison process closely. When Java compares two strings, corresponding letters are compared until one of the strings ends or the first difference is encountered. If one of the strings ends, the longer string is considered the later one. If a character mismatch is found, the characters are compared to determine which string comes later in the dictionary sequence. This process is called lexicographic comparison. For example, let's compare "car"
with "cargo"
. The first three letters match, and we reach the end of the first string. Therefore "car"
comes before "cargo"
in the lexicographic ordering. Now compare "cathode"
with "cargo"
. The first two letters match. In the third character position, t
comes after r
, so the string "cathode"
comes after "cargo"
in lexicographic ordering. (See Figure 3.)
Table 5.1. Relational Operator Examples
Value | Comment | |
---|---|---|
|
| 3 is less than 4; |
Error | The "less than or equal" operator is | |
|
|
|
|
| The left-hand side must be strictly smaller than the right-hand side. |
|
| Both sides are equal; |
|
|
|
|
|
|
Error | Use | |
|
| Although the values are very close to one another, they are not exactly equal. See Common Error 4.3. |
Error | You cannot compare a string to a number. | |
|
| Always use the |
|
| Never use |
|
| Use the |
If you compare two object references with the ==
operator, you test whether the references refer to the same object. Here is an example:
Rectangle box1 = new Rectangle(5, 10, 20, 30); Rectangle box2 = box1; Rectangle box3 = new Rectangle(5, 10, 20, 30);
The comparison
box1 == box2
is true
. Both object variables refer to the same object. But the comparison
box1 == box3
is false
. The two object variables refer to different objects (see Figure 4). It does not matter that the objects have identical contents.
You can use the equals
method to test whether two rectangles have the same contents, that is, whether they have the same upper-left corner and the same width and height. For example, the test
box1.equals(box3)
is true.
The ==
operator tests whether two object references are identical. To compare the contents of objects, you need to use the equals
method.
However, you must be careful when using the equals
method. It works correctly only if the implementors of the class have supplied it. The Rectangle
class has an equals
method that is suitable for comparing rectangles.
For your own classes, you need to supply an appropriate equals
method. You will learn how to do that in Chapter 10. Until that point, you should not use the equals
method to compare objects of your own classes.
An object reference can have the special value null
if it refers to no object at all. It is common to use the null
value to indicate that a value has never been set. For example,
String middleInitial = null; // Not set if ( ... ) middleInitial = middleName.substring(0, 1);
The null
reference refers to no object.
You use the ==
operator (and not equals
) to test whether an object reference is a null
reference:
if (middleInitial == null) System.out.println(firstName + " " + lastName); else System.out.println(firstName + " " + middleInitial + ". " + lastName);
Note that the null
reference is not the same as the empty string ""
. The empty string is a valid string of length 0, whereas a null
indicates that a string variable refers to no string at all.
the empty string ""
?
the string " "
containing a space?
null
?
4. Which of the following comparisons are syntactically incorrect? Which of them are syntactically correct, but logically questionable?
String a = "1"; String b = "one"; double x = 1; double y = 3 * (1.0 / 3);
a == "1"
a == null
a.equals("")
a == b
a == x
x == y
x - y == null
x.equals(y)
Many computations require more than a single if/else
decision. Sometimes, you need to make a series of related comparisons.
The following program asks for a value describing the magnitude of an earthquake on the Richter scale and prints a description of the likely impact of the quake. The Richter scale is a measurement for the strength of an earthquake. Every step in the scale, for example from 6.0 to 7.0, signifies a tenfold increase in the strength of the quake. The 1989 Loma Prieta earthquake that damaged the Bay Bridge in San Francisco and destroyed many buildings in several Bay area cities registered 7.1 on the Richter scale.
Multiple conditions can be combined to evaluate complex decisions. The correct arrangement depends on the logic of the problem to be solved.
ch05/quake/Earthquake.java
1
/**2
A class that describes the effects of an earthquake.3
*/4
public class Earthquake5
{6
private double richter;7
8
/**9
Constructs an Earthquake object.10
@param magnitude the magnitude on the Richter scale11
*/12
public Earthquake(double magnitude)13
{14
richter = magnitude;15
}16
17
/**18
Gets a description of the effect of the earthquake.19
@return the description of the effect20
*/21
public String getDescription()22
{
23
String r;24
if (richter >= 8.0)25
r = "Most structures fall";26
else if (richter >= 7.0)27
r = "Many buildings destroyed";28
else if (richter >= 6.0)29
r = "Many buildings considerably damaged, some collapse";30
else if (richter >= 4.5)31
r = "Damage to poorly constructed buildings";32
else if (richter >= 3.5)33
r = "Felt by many people, no destruction";34
else if (richter >= 0)35
r = "Generally not felt by people";36
else37
r = "Negative numbers are not valid";38
return r;39
}40
}
ch05/quake/EarthquakeRunner.java
1
import java.util.Scanner;2
3
/**4
This program prints a description of an earthquake of a given magnitude5
*/6
public class EarthquakeRunner7
{8
public static void main(String[] args)9
{10
Scanner in = new Scanner(System.in);11
12
System.out.print("Enter a magnitude on the Richter scale: ");13
double magnitude = in.nextDouble();14
Earthquake quake = new Earthquake(magnitude);15
System.out.println(quake.getDescription());16
}17
}
Program Run
Enter a magnitude on the Richter scale: 7.1 Many buildings destroyed
Here we must sort the conditions and test against the largest cutoff first. Suppose we reverse the order of tests:
if (richter >= 0) // Tests in wrong order r = "Generally not felt by people"; else if (richter >= 3.5) r = "Felt by many people, no destruction"; else if (richter >= 4.5) r = "Damage to poorly constructed buildings"; else if (richter >= 6.0) r = "Many buildings considerably damaged, some collapse"; else if (richter >= 7.0) r = "Many buildings destroyed"; else if (richter >= 8.0) r = "Most structures fall";
This does not work. All nonnegative values of richter
fall into the first case, and the other tests will never be attempted.
In this example, it is also important that we use an if
/else if
/else
test, not just multiple independent if
statements. Consider this sequence of independent tests:
if (richter >= 8.0) // Didn't use else r = "Most structures fall"; if (richter >= 7.0) r = "Many buildings destroyed"; if (richter >= 6.0) r = "Many buildings considerably damaged, some collapse"; if (richter >= 4.5) r = "Damage to poorly constructed buildings"; if (richter >= 3.5) r = "Felt by many people, no destruction"; if (richter >= 0) r = "Generally not felt by people";
Now the alternatives are no longer exclusive. If richter
is 6.0, then the last four tests all match, and r
is set four times.
Some computations have multiple levels of decision making. You first make one decision, and each of the outcomes leads to another decision. Here is a typical example.
In the United States, taxpayers pay federal income tax at different rates depending on their incomes and marital status. There are two main tax schedules: one for single taxpayers and one for married taxpayers "filing jointly", meaning that the married taxpayers add their incomes together and pay taxes on the total. Table 2 gives the tax rate computations for each of the filing categories, using a simplified version of the values for the 2008 federal tax return.
Table 5.2. Federal Tax Rate Schedule (2008, simplified)
If your filing status is Single: | If your filing status is Married: | ||
---|---|---|---|
Tax Bracket | Percentage | Tax Bracket | Percentage |
$0 . . . $32,000 | 10% | $0 . . . $64,000 | 10% |
Amount over $32,000 | 25% | Amount over $64,000 | 25% |
Now let us compute the taxes due, given a filing status and an income figure. First, we must branch on the filing status. Then, for each filing status, we must have another branch on income level.
The two-level decision process is reflected in two levels of if
statements. We say that the income test is nested inside the test for filing status. (See Figure 5 for a flowchart.)
ch05/tax/TaxReturn.java
1
/**2
A tax return of a taxpayer in 2008.3
*/4
public class TaxReturn5
{6
public static final int SINGLE = 1;7
public static final int MARRIED = 2;8
9
private static final double RATE1 = 0.10;10
private static final double RATE2 = 0.25;11
private static final double RATE1_SINGLE_LIMIT = 32000;12
private static final double RATE1_MARRIED_LIMIT = 64000;13
14
private double income;15
private int status;16
17
/**18
Constructs a TaxReturn object for a given income and19
marital status.20
@param anIncome the taxpayer income21
@param aStatus either SINGLE or MARRIED22
*/23
public TaxReturn(double anIncome, int aStatus)24
{25
income = anIncome;26
status = aStatus;27
}28
29
public double getTax()30
{31
double tax1 = 0;32
double tax2 = 0;33
34
if (status == SINGLE)35
{36
if (income <= RATE1_SINGLE_LIMIT)37
{38
tax1 = RATE1 * income;39
}40
else41
{42
tax1 = RATE1 * RATE1_SINGLE_LIMIT;43
tax2 = RATE2 * (income - RATE1_SINGLE_LIMIT);44
}45
}46
else47
{48
if (income <= RATE1_MARRIED_LIMIT)49
{50
tax1 = RATE1 * income;51
}52
else53
{54
tax1 = RATE1 * RATE1_MARRIED_LIMIT;55
tax2 = RATE2 * (income - RATE1_MARRIED_LIMIT);56
}57
}58
59
return tax1 + tax2;60
}61
}
1
import java.util.Scanner;2
3
/**4
This program calculates a simple tax return.5
*/6
public class TaxCalculator7
{8
public static void main(String[] args)9
{10
Scanner in = new Scanner(System.in);11
12
System.out.print("Please enter your income: ");13
double income = in.nextDouble();14
15
System.out.print("Are you married? (Y/N) ");16
String input = in.next();17
int status;18
if (input.equalsIgnoreCase("Y"))19
status = TaxReturn.MARRIED;20
else21
status = TaxReturn.SINGLE;22
TaxReturn aTaxReturn = new TaxReturn(income, status);23
24
System.out.println("Tax: "25
+ aTaxReturn.getTax());26
}27
}
Please enter your income: 80000 Are you married? (Y/N) Y Tax: 10400.0
6. Some people object to higher tax rates for higher incomes, claiming that you might end up with less money after taxes when you get a raise for working hard. What is the flaw in this argument?
In Java, an expression such as amount < 1000
has a value, just as the expression amount + 1000
has a value. The value of a relational expression is either true
or false
. For example, if amount
is 500, then the value of amount < 1000
is true
. Try it out: The program fragment
double amount = 0; System.out.println(amount < 1000);
prints true
. The values true
and false
are not numbers, nor are they objects of a class. They belong to a separate type, called boolean
. The Boolean type is named after the mathematician George Boole (1815–1864), a pioneer in the study of logic.
The boolean
type has two values: true
and false
.
A predicate method is a method that returns a boolean
value. Here is an example of a predicate method:
public class BankAccount { public boolean isOverdrawn() { return balance < 0; // Returns true or false } }
A predicate method returns a boolean
value.
You can use the return value of the method as the condition of an if
statement:
if (harrysChecking.isOverdrawn()) ...
There are several useful static predicate methods in the Character
class:
isDigit isLetter isUpperCase isLowerCase
that let you test whether a character is a digit, a letter, an uppercase letter, or a lowercase letter:
if (Character.isUpperCase(ch)) . . .
It is a common convention to give the prefix "is
" or "has
" to the name of a predicate method.
The Scanner
class has useful predicate methods for testing whether the next input will succeed. The hasNextInt
method returns true
if the next character sequence denotes an integer. It is a good idea to call that method before calling nextInt
:
if (in.hasNextInt()) input = in.nextInt();
Similarly, the hasNextDouble
method tests whether a call to nextDouble
will succeed.
Suppose you want to find whether amount
is between 0 and 1000. Then two conditions have to be true: amount
must be greater than 0, and it must be less than 1000. In Java you use the &&
operator to represent the and when combining test conditions. That is, you can write the test as follows:
if (0 < amount && amount < 1000) . . .
The &&
(and) operator combines several tests into a new test that passes only when all conditions are true. An operator that combines Boolean values is called a Boolean operator.
You can form complex tests with the Boolean operators &&
(and), ||
(or), and !
(not).
The &&
operator has a lower precedence than the relational operators. For that reason, you can write relational expressions on either side of the &&
operator without using parentheses. For example, in the expression
0 < amount && amount < 1000
the expressions 0 < amount
and amount < 1000
are evaluated first. Then the &&
operator combines the results. Appendix B shows a table of the Java operators and their precedence.
The ||
(or) logical operator also combines two or more conditions. The resulting test succeeds if at least one of the conditions is true. For example, here is a test to check whether the string input
is an "S"
or "M"
:
if (input.equals("S") || input.equals("M")) ...
Figure 6 shows flowcharts for these examples.
Sometimes you need to invert a condition with the !
(not) logical operator. For example, we may want to carry out a certain action only if two strings are not equal:
if (!input.equals("S")) ...
The !
operator takes a single condition and evaluates to true
if that condition is false and to false
if the condition is true.
Table 5.3. Boolean Operators
Expression | Value | Comment |
---|---|---|
|
| Only the first condition is true. |
|
| The first condition is true. |
|
| The |
Syntax error | Error: The expression | |
| Error: This condition is always true. The programmer probably intended | |
|
| The |
|
|
|
|
| There is no need to compare a Boolean variable with |
|
| It is clearer to use |
Here is a summary of the three logical operations:
A | B | A | A | B | A | A | A |
---|---|---|---|---|---|---|---|
|
|
|
| Any |
|
|
|
|
|
|
|
|
|
|
|
| Any |
|
|
|
|
You can use a Boolean variable if you know that there are only two possible values. Have another look at the tax program in Section 5.3.2. The marital status is either single or married. Instead of using an integer, you can use a variable of type boolean
:
private boolean married;
The advantage is that you can't accidentally store a third value in the variable.
Then you can use the Boolean variable in a test:
if (married) ... else ...
You can store the outcome of a condition in a Boolean variable.
Sometimes Boolean variables are called flags because they can have only two states: "up" and "down".
It pays to think carefully about the naming of Boolean variables. In our example, it would not be a good idea to give the name maritalStatus
to the Boolean variable. What does it mean that the marital status is true
? With a name like married
there is no ambiguity; if married
is true
, the taxpayer is married.
By the way, it is considered gauche to write a test such as
if (married == true) . . . // Don't
Just use the simpler test
if (married) . . .
In Chapter 6 we will use Boolean variables to control complex loops.
System.out.println(x > 0 || x < 0); print false?
8. Rewrite the following expression, avoiding the comparison with false
:
if (Character.isDigit(ch) == false) ...
Testing the functionality of a program without consideration of its internal structure is called black-box testing. This is an important part of testing, because, after all, the users of a program do not know its internal structure. If a program works perfectly on all inputs, then it surely does its job.
Black-box testing describes a testing method that does not take the structure of the implementation into account.
However, it is impossible to ensure absolutely that a program will work correctly on all inputs just by supplying a finite number of test cases. As the famous computer scientist Edsger Dijkstra pointed out, testing can show only the presence of bugs—not their absence. To gain more confidence in the correctness of a program, it is useful to consider its internal structure. Testing strategies that look inside a program are called white-box testing. Performing unit tests of each method is a part of white-box testing.
White-box testing uses information about the structure of a program.
You want to make sure that each part of your program is exercised at least once by one of your test cases. This is called code coverage. If some code is never executed by any of your test cases, you have no way of knowing whether that code would perform correctly if it ever were executed by user input. That means that you need to look at every if
/else
branch to see that each of them is reached by some test case. Many conditional branches are in the code only to take care of strange and abnormal inputs, but they still do something. It is a common phenomenon that they end up doing something incorrectly, but those faults are never discovered during testing, because nobody supplied the strange and abnormal inputs. Of course, these flaws become immediately apparent when the program is released and the first user types in an unusual input and is incensed when the program misbehaves. The remedy is to ensure that each part of the code is covered by some test case.
Code coverage is a measure of how many parts of a program have been tested.
For example, in testing the getTax
method of the TaxReturn
class, you want to make sure that every if
statement is entered for at least one test case. You should test both single and married taxpayers, with incomes in each of the three tax brackets.
When you select test cases, you should make it a habit to include boundary test cases: legal values that lie at the boundary of the set of acceptable inputs.
For example, what happens when you compute the taxes for an income of 0 or if a bank account has an interest rate of 0 percent? Boundary cases are still legitimate inputs, and you expect that the program will handle them correctly—often in some trivial way or through special cases. Testing boundary cases is important, because programmers often make mistakes dealing with boundary conditions. Division by zero, extracting characters from empty strings, and accessing null references are common symptoms of boundary errors.
Boundary test cases are test cases that are at the boundary of acceptable inputs.
10. Give a boundary test case for the EarthquakeRunner
program. What output do you expect?
Use the if
statement to implement a decision.
The if
statement lets a program carry out different actions depending on a condition.
A block statement groups several statements together.
Implement comparisons of numbers and objects.
Relational operators compare values. The ==
operator tests for equality.
When comparing floating-point numbers, don't test for equality. Instead, check whether they are close enough.
Do not use the ==
operator to compare strings. Use the equals
method instead.
The compareTo
method compares strings in dictionary order.
The ==
operator tests whether two object references are identical. To compare the contents of objects, you need to use the equals
method.
The null
reference refers to no object.
Implement complex decisions that require multiple if statements.
Multiple conditions can be combined to evaluate complex decisions. The correct arrangement depends on the logic of the problem to be solved.
Use the Boolean data type to store and combine conditions that can be true or false.
The boolean
type has two values: true
and false
.
A predicate method returns a boolean
value.
You can form complex tests with the Boolean operators &&
(and), ||
(or), and !
(not).
De Morgan's law shows how to simplify expressions in which the not operator (!
) is applied to terms joined by the &&
or ||
operators.
You can store the outcome of a condition in a Boolean variable.
Design test cases that cover all parts of a program.
Black-box testing describes a testing method that does not take the structure of the implementation into account.
White-box testing uses information about the structure of a program.
Code coverage is a measure of how many parts of a program have been tested.
Boundary test cases are test cases that are at the boundary of acceptable inputs.
You should calculate test cases by hand to double-check that your application computes the correct answer.
Use the Java logging library for messages that can be easily turned on or off.
Logging messages can be deactivated when testing is complete.
java.lang.Character java.util.Scanner isDigit hasNextDouble isLetter hasNextInt isLowerCase java.util.logging.Level isUpperCase INFO java.lang.Object OFF equals java.util.logging.Logger java.lang.String getGlobal equals info equalsIgnoreCase setLevel compareTo
R5.1 What is the value of each variable after the if
statement?
int n = 1; int k = 2; int r = n; if (k < n) r = k;
int n = 1; int k = 2; int r; if (n < k) r = k; else r = k + n;
int n = 1; int k = 2; int r = k; if (r < k) n = r; else k = n;
int n = 1; int k = 2; int r = 3; if (r < n + k) r = 2 * n; else k = 2 * r;
R5.2 Find the errors in the following if
statements.
if (1 + x > Math.pow(x, Math.sqrt(2)) y = y + x;
if (x = 1) y++; else if (x = 2) y = y + 2;
int x = Integer.parseInt(input); if (x != null) y = y + x;
R5.3 Find the error in the following if
statement that is intended to select a language from a given country and state/province.
language = "English"; if (country.equals("Canada")) if (stateOrProvince.equals("Quebec")) language = "French"; else if (country.equals("China")) language = "Chinese";
R5.4 Find the errors in the following if
statements.
if (x && y == 0) { x = 1; y = 1; }
if (1 <= x <= 10) System.out.println(x);
if (!s.equals("nickels") || !s.equals("pennies") || !s.equals("dimes") || !s.equals("quarters")) System.out.print("Input error!");
if (input.equalsIgnoreCase("N") || "NO") return;
R5.5 Explain the following terms, and give an example for each construct:
Expression
Condition
Statement
Simple statement
Compound statement
Block
R5.6 Explain the difference between an if
statement with multiple else
branches and nested if
statements. Give an example for each.
R5.7 Give an example for an if/else if/else
statement where the order of the tests does not matter. Give an example where the order of the tests matters.
R5.8 Of the following pairs of strings, which comes first in lexicographic order?
"Tom", "Jerry"
"Tom", "Tomato"
"church", "Churchill"
"car manufacturer", "carburetor"
"Harry", "hairy"
"C++", " Car"
"Tom", "Tom"
"Car", "Carl"
"car", "bar"
"101", "11"
"1.01", "10.1"
R5.9 Complete the following truth table by finding the truth values of the Boolean expressions for all combinations of the Boolean inputs p, q
, and r
.
p | q | r |
|
|
---|---|---|---|---|
false | false | false | ||
false | false | false | ||
false | false | false | ||
. . . | . . . | . . . | ||
5 more combinations | ||||
. . . |
R5.10 Each square on a chess board can be described by a letter and number, such as g5
in this example:
The following pseudocode describes an algorithm that determines whether a square with a given letter and number is dark (black) or light (white).
If the letter is an a, c, e, or g If the number is odd color = "black" Else color = "white" Else If the number is even color = "black" Else color = "white"
Using the procedure in Productivity Hint 5.2 on page 192, trace this pseudocode with input g5
.
R5.11 Give a set of four test cases for the algorithm of Exercise R5.10 that covers all branches.
R5.12 In a scheduling program, we want to check whether two appointments overlap. For simplicity, appointments start at a full hour, and we use military time (with hours 0–24). The following pseudocode describes an algorithm that determines whether the appointment with start time start1
and end time end1
overlaps with the appointment with start time start2
and end time end2
.
If start1 > start2
s = start1
Else
s = start2
If end1 < end2
e = endl
Else
e = end2
If s < e
The appointments overlap.
Else
The appointments
Trace this algorithm with an appointment from 10–12 and one from 11–13, then with an appointment from 10–11 and one from 12–13.
R5.13 Write pseudocode for a program that prompts the user for a month and day and prints out whether it is one of the following four holidays:
New Year's Day (January 1)
Independence Day (July 4)
Veterans Day (November 11)
Christmas Day (December 25)
R5.14 True or false? A &&
B is the same as B &&
A for any Boolean conditions A and B.
R5.15 Explain the difference between
s = 0; if (x > 0) s++; if (y > 0) s++;
and
s = 0; if (x > 0) s++; else if (y > 0) s++;
R5.16 Use de Morgan's law to simplify the following Boolean expressions.
!(x > 0 && y > 0)
!(x != 0 || y != 0)
!(country.equals("US") && !state.equals("HI") && !state.equals("AK"))
!(x % 4 != 0 || !(x % 100 == 0 && x % 400 == 0))
R5.17 Make up another Java code example that shows the dangling else
problem, using the following statement: A student with a GPA of at least 1.5, but less than 2, is on probation; with less than 1.5, the student is failing.
R5.18 Explain the difference between the ==
operator and the equals
method when comparing strings.
R5.19 Explain the difference between the tests
r == s
and
r.equals(s)
where both r
and s
are of type Rectangle
.
R5.20 What is wrong with this test to see whether r
is null
? What happens when this code runs?
Rectangle r; ... if (r.equals(null)) r = new Rectangle(5, 10, 20, 30);
R5.21 Explain how the lexicographic ordering of strings differs from the ordering of words in a dictionary or telephone book. Hint: Consider strings, such as IBM
, wiley.com
, Century 21, While-U-Wait
, and 7-11
.
R5.22 Write Java code to test whether two objects of type Line2D.Double
represent the same line when displayed on the graphics screen. Do not use a.equals(b)
.
Line2D.Double a;
Line2D.Double b;
if (your condition goes here
)
g2.drawString("They look the same!", x, y);
Hint: If p
and q
are points, then Line2D.Double(p, q)
and Line2D.Double(q, p)
look the same.
R5.23 Explain why it is more difficult to compare floating-point numbers than integers. Write Java code to test whether an integer n
equals 10 and whether a floating-point number x
is approximately equal to 10.
R5.24 Consider the following test to see whether a point falls inside a rectangle.
Point2D.Double p = . . . Rectangle r = . . .
boolean xInside = false; if (r.getX() <= p.getX() && p.getX() <= r.getX() + r.getWidth()) xInside = true; boolean yInside = false; if (r.getY() <= p.getY() && p.getY() <= r.getY() + r.getHeight()) yInside = true; if (xInside && yInside) g2.drawString("p is inside the rectangle.", p.getX(), p.getY());
Rewrite this code to eliminate the explicit true
and false
values, by setting xInside
and yInside
to the values of Boolean expressions.
R5.25 Give a set of test cases for the earthquake program in Section 5.3.1. Ensure coverage of all branches.
R5.26 Give an example of a boundary test case for the earthquake program in Section 5.3.1. What result do you expect?
P5.1 Write a program that prints all real solutions to the quadratic equation ax2 + bx + c = 0. Read in a, b, c and use the quadratic formula. If the discriminant b2 – 4ac is negative, display a message stating that there are no real solutions. Implement a class QuadraticEquation
whose constructor receives the coefficients a, b, c
of the quadratic equation. Supply methods getSolution1
and getSolution2
that get the solutions, using the quadratic formula, or 0 if no solution exists. The getSolution1
method should return the smaller of the two solutions. Supply a method
boolean hasSolutions()
that returns false
if the discriminant is negative.
P5.2 Write a program that takes user input describing a playing card in the following shorthand notation:
Notation | Meaning |
---|---|
| Ace |
| Card values |
| Jack |
| Queen |
| King |
| Diamonds |
| Hearts |
| Spades |
| Clubs |
Your program should print the full description of the card. For example,
Enter the card notation: 4S Four of spades
Implement a class Card
whose constructor takes the card notation string and whose getDescription
method returns a description of the card. If the notation string is not in the correct format, the getDescription
method should return the string "Unknown"
.
P5.3 Write a program that reads in three floating-point numbers and prints the three inputs in sorted order. For example:
Please enter three numbers: 4 9 2.5 The inputs in sorted order are: 2.5 4 9
P5.4 Write a program that translates a letter grade into a number grade. Letter grades are A B C D F
, possibly followed by + or -. Their numeric values are 4, 3, 2, 1, and 0. There is no F+
or F-
. A + increases the numeric value by 0.3, a - decreases it by 0.3. However, an A+
has the value 4.0. All other inputs have value −1.
Enter a letter grade: B- Numeric value: 2.7.
Use a class Grade
with a method getNumericGrade
.
P5.5 Write a program that translates a number into the closest letter grade. For example, the number 2.8 (which might have been the average of several grades) would be converted to B-
. Break ties in favor of the better grade; for example, 2.85 should be a B
. Any value ≥ 4.15 should be an A+
.
Use a class Grade
with a method getLetterGrade
.
P5.6 Write a program that reads in three strings and prints them in lexicographically sorted order:
Please enter three strings: Tom Dick Harry The inputs in sorted order are: Dick Harry Tom
P5.7 Change the implementation of the getTax
method in the TaxReturn
class, by setting a variable rate1Limit
, depending on the marital status. Then have a single formula that computes the tax, depending on the income and the limit. Verify that your results are identical to that of the TaxReturn
class in this chapter.
P5.8 The original U.S. income tax of 1913 was quite simple. The tax was
1 percent on the first $50,000.
2 percent on the amount over $50,000 up to $75,000.
3 percent on the amount over $75,000 up to $100,000.
4 percent on the amount over $100,000 up to $250,000.
5 percent on the amount over $250,000 up to $500,000.
6 percent on the amount over $500,000.
There was no separate schedule for single or married taxpayers. Write a program that computes the income tax according to this schedule.
P5.9 Write a program that prompts for the day and month of the user's birthday and then prints a horoscope. Make up fortunes for programmers, like this:
Please enter your birthday (month and day): 6 16 Gemini are experts at figuring out the behavior of complicated programs. You feel where bugs are coming from and then stay one step ahead. Tonight, your style wins approval from a tough critic.
Each fortune should contain the name of the astrological sign. (You will find the names and date ranges of the signs at a distressingly large number of sites on the Internet.)
P5.10 When two points in time are compared, each given as hours (in military time, ranging from 0 and 23) and minutes, the following pseudocode determines which comes first.
If hour1 < hour2
time1 comes first.
Else if hour1 and hour2 are the same
If minute1 < minute2
time1 comes first.
Else if minute1 and minute2 are the same
time1 and time2 are the same.
Else
time2 comes first.
Else
time2 comes first.
Write a program that prompts the user for two points in time and prints the time that comes first, then the other time.
P5.11 The following algorithm yields the season (Spring, Summer, Fall, or Winter) for a given month and day.
If month is 1, 2, or 3, season = "Winter" Else if month is 4, 5, or 6, season = "Spring" Else if month is 7, 8, or 9, season = "Summer" Else if month is 10, 11, or 12, season = "Fall" If month is divisible by 3 and day >= 21 If season is "Winter", season = "Spring" Else if season is "Spring", season = "Summer" Else if season is "Summer", season = "Fall" Else season = "Winter"
Write a program that prompts the user for a month and day and then prints the season, as determined by this algorithm.
P5.12 A year with 366 days is called a leap year. A year is a leap year if it is divisible by 4 (for example, 1980). However, since the introduction of the Gregorian calendar on October 15, 1582, a year is not a leap year if it is divisible by 100 (for example, 1900); however, it is a leap year if it is divisible by 400 (for example, 2000). Write a program that asks the user for a year and computes whether that year is a leap year. Implement a class Year
with a predicate method boolean isLeapYear()
.
P5.13 Write a program that asks the user to enter a month (1 = January, 2 = February, and so on) and then prints the number of days of the month. For February, print "28 days".
Enter a month (1-12): 5 31 days
Implement a class Month
with a method int getDays()
. Do not use a separate if
or else
statement for each month. Use Boolean operators.
P5.14 Write a program that reads in two floating-point numbers and tests (a) whether they are the same when rounded to two decimal places and (b) whether they differ by less than 0.01. Here are two sample runs.
Enter two floating-point numbers: 2.0 1.99998 They are the same when rounded to two decimal places. They differ by less than 0.01. Enter two floating-point numbers: 0.999 0.991 They are different when rounded to two decimal places. They differ by less than 0.01.
P5.15 Enhance the BankAccount
class of Chapter 3 by
Rejecting negative amounts in the deposit
and withdraw
methods
Rejecting withdrawals that would result in a negative balance
P5.16 Write a- program that reads in the hourly wage of an employee. Then ask how many hours the employee worked in the past week. Be sure to accept fractional hours. Compute the pay. Any overtime work (over 40 hours per week) is paid at 150 percent of the regular wage. Solve this problem by implementing a class Paycheck
.
P5.17 Write a unit conversion program that asks users to identify the unit from which they want to convert and the unit to which they want to convert. Legal units are in, ft, mi, mm, cm, m, and km. Declare two objects of a class UnitConverter
that convert between meters and a given unit.
Convert from: in Convert to: mm Value: 10 10 in = 254 mm
P5.18 A line in the plane can be specified in various ways:
by giving a point (x, y) and a slope m
by giving two points (x1, y1), (x2, y2)
as an equation in slope-intercept form y = mx + b
as an equation x = a if the line is vertical
Implement a class Line
with four constructors, corresponding to the four cases above. Implement methods
boolean intersects(Line other) boolean equals(Line other) boolean isParallel(Line other)
P5.19 Write a program that draws a circle with radius 100 and center (200, 200). Ask the user to specify the x- and y-coordinates of a point. Draw the point as a small circle. If the point lies inside the circle, color the small circle green. Otherwise, color it red. In your exercise, declare a class Circle
and a method boolean isInside(Point2D.Double p)
.
P5.20 Write a graphics program that asks the user to specify the radii of two circles. The first circle has center (100, 200), and the second circle has center (200, 100). Draw the circles. If they intersect, then color both circles green. Otherwise, color them red. Hint: Compute the distance between the centers and compare it to the radii. Your program should draw nothing if the user enters a negative radius. In your exercise, declare a class Circle
and a method boolean intersects(Circle other)
.
Project 5.1 Implement a combination lock class. A combination lock has a dial with 26 positions labeled A . . . Z. The dial needs to be set three times. If it is set to the correct combination, the lock can be opened. When the lock is closed again, the combination can be entered again. If a user sets the dial more than three times, the last three settings determine whether the lock can be opened. An important part of this exercise is to implement a suitable interface for the CombinationLock
class.
Project 5.2 Get the instructions for last year's form 1040 from http://www.irs.ustreas.gov
. Find the tax brackets that were used last year for all categories of taxpayers (single, married filing jointly, married filing separately, and head of household). Write a program that computes taxes following that schedule. Ignore deductions, exemptions, and credits. Simply apply the tax rate to the income.
If the withdrawal amount equals the balance, the result should be a zero balance and no penalty.
Only the first assignment statement is part of the if
statement. Use braces to group both assignment statements into a block statement.
(a) 0; (b) 1; (c) An exception occurs.
Syntactically incorrect: e, g, h. Logically questionable: a, d, f
Yes, if you also reverse the comparisons:
if (richter < 3.5) r = "Generally not felt by people"; else if (richter < 4.5) r = "Felt by many people, no destruction"; else if (richter < 6.0) r = "Damage to poorly constructed buildings"; ...
The higher tax rate is only applied on the income in the higher bracket. Suppose you are single and make $31,900. Should you try to get a $200 raise? Absolutely: you get to keep 90 percent of the first $100 and 75 percent of the next $100.
When x
is zero.
if (!Character.isDigit(ch)) . . .
Seven
An input of 0 should yield an output of "Generally not felt by people"
. (If the output is "Negative numbers are not allowed"
, there is an error in the program.)
3.135.247.11