Start Lecture #6
We have seen how to use if-then-else to specify one of a number of different actions, with the chosen action determined by a series of Boolean expressions.
Often the Boolean expressions consist of different values for a single (normally arithmetic) expression.
switch(expression) { case value1: stmts1 case value2: stmts2 ... case valueN: stmtsN default: def-stmts }
For example we may want to do one action if i+j is 4, a different action if i+j is 8, a third action if i+j is 15, and a fourth action if i+j is any other value. In such cases the switch statement, shown on the right, is appropriate.
When a switch statement is executed the expression is evaluated and the result specifies, which case is executed.
The semantics of switch are somewhat funny. Specifically, given the similarity with if-then-else, one might assume that after stmts1 is executed, control transfers to the end of the switch. However, this is wrong: Unless explicitly directed, control flows from one case to another.
computed gotoof Fortran.
switch (expression) { case value1: stmts1 break; case value2: stmts2 break; ... case valueN: stmtsN break; default: def-stmts }
It is quite easy to explicitly transfer control from the end of one case to the end of the entire switch. Java, again borrowing from C, has a break statement that serves this purpose.
We see on the right the common form of a switch in which the last statement of stmts1...stmtsN is a break.
When a break is executed within a switch, control
breaks out of
the switch.
That is, execution proceeds directly to the end of
the switch.
In particular, the code on the right will execute exactly one
case or the default.
Homework: 3.11, 2.25, Handout for those w/o 8e.
bool-expr ? expr1 : expr2
if (x==5) y = 2; else y = 3;
y = x==5 ? 2 : 3;
Recall that Java has += that shortens x=x+5 to x+=5. Java has another shortcut, the tertiary operator ?...: that can be used to shorten an if-then-else.
The general form of the so-called conditional expression
is
shown on the top right.
The value of the entire expression is either expr1 or
expr2, depending on the value of the Boolean expression
bool-expr.
For example, the middle right if-then-else can be replaced by the bottom right assignment statement containing the equivalent conditional expression.
Note that this is not limited to arithmetic and can often be used to produce grammatically correct output.
System.out.println ("Please input " + N + "number" + N ? "." : "s.");
I realize this looks weird; be sure you see how it works.
Homework: Redo 3.7, this time using a switch.
A comparatively recent addition to Java is the C-like printf method. (It was added in Java 2 Standard Edition 5; we are using J2SE 6).
System.out.printf(format, item1, item2, ..., item n);
The first point to make is that printf() takes a variable number of arguments as indicated on the right. The required first argument, which must be a string, indicates how many additional arguments are needed and how those arguments are to be printed.
Wherever the first argument contains a %
, the value
of the next argument is inserted (a double %%
is
printed as a single %
).
System.out.printf("i = %d and j = %d", i, j); System.out.printf("x = %f and y = %e", x, y);
The first line on the right prints the integer values of x and
y.
The second line prints two real values, the second using scientific
notation.
Specifier | Output |
---|---|
%b | Boolean |
%c | Character |
%d | Integer |
%f | Floating Point |
%e | Scientific Notation |
%s | String |
The table on the right gives the most common specifiers. Although Java will perform a few conversions automatically (e.g., an integer value will be converted to a string if the corresponding specifier is %s), most conversions are illegal. For example
int i; double x; int one=1, two=2; System.out.printf("Both %f and %d are bad\n", i, x); System.out.printf("%d plus %d is %d\n", one, two, one+two);
You could try to find which conversions are OK, but I very much suggest that instead you do not use any. That is use %f and %e only for floats and doubles; use %d only for the four integer types; use %s only for Strings, etc.
System.out.printf("%d\n%d\n",45,7);
45 7
45 7
System.out.printf("%2d\n%2d\n",45,7);
System.out.printf("%2d\n%2d\n",45,789);
45 789
Note that %d uses just enough space to print the actual number; it does not pad with blanks. If you print several integers one per line using %d they won't line up properly. For example, the printf() on the right will produce the first output, not the second.
To remedy this problem you can specify a minimum width between the
% and the key-letter
.
For example the second printf() does produce the second
output.
But what would happen if we tried to print 543 using %2d? There are two reasonable choices.
Java chooses the second option. So the bottom printf() produces the bottom output.
These same considerations apply to the other 5 specifiers in the table: if the value is not as wide as the specified width, the value is right justified and padded on the left with blanks.
For the real number specifiers %f and %e one can specify the precision in addition to the (minimum) width. This is done by writing the width, then a period, and then the precision between the % and the letter.
For example %6.2 means that the floating-point value will be written with exactly 2 digits after the decimal point and if the result (including a minus sign if needed) is less than 6 characters, the value will be padded with blanks on the left.
As we have seen, when the width is specified (with or without precision), the value is right justified if needed and padded on the left with blanks. This is normally just what you want for numbers, but not for strings.
For all specifiers (numbers, strings, etc) Java supports left justification (padding on the right with blanks) as well: Simply put a minus sign right before the width as in %-9f, %-10.2e, or %-7s.
Operator | Associativity |
---|---|
var++, var-- | Left-to-right |
+,- (unary), ++var, --var | Right-to-left |
(type) | Right-to-left |
! | Left-to-right |
*,/,% | Left-to-right |
+,- (binary) | Left-to-right |
<,<=,>,>= | Left-to-right |
==,!= | Left-to-right |
^ | Left-to-right |
&& | Left-to-right |
|| | Left-to-right |
?: (tertiary) | Right-to-left |
=,+=,-=,*=,/=,%= | Right-to-left |
The table on the right lists the operators we have seen in decreasing order of precedence. That mean that, in the absence of parentheses, if an expression contains two operators from different rows of the table, the operator in the higher row is done first.
The second column gives the associativity of the operators. If an expression contains two operators from the same row and that row has left-to-right associativity, the left operator is done first. Similarly if the row has right-to-left associativity, the right operator is done first. As with precedence, parentheses can be used to override this default ordering.
Not many programmers have the entire table memorized (not to mention the fact that there are other operators we have not yet encountered). Instead, they use parenthesis even when their use might not be necessary due to precedence and associativity.
However, it is wise to remember the precedence and associativity of
some of the frequently used operators.
For example, one should remember that *,/,% are executed before
(binary +,-) and that both groups have left-to-right associativity.
It would clutter up a program to see an expression like
((x*y)/z)/(((-x)+z)-y) rather than the equivalent
(x*y/z)/(-x+z-y)
As you know from Python, loops are used to execute the same block
of code multiple times.
There are several kinds of loops:
The while (and do-while) are fairly general;
the for is most convenient when the loops are
counting
, but can be used (abused?) in quite general ways.
while (BE) { stmts }
Some early languages (notable FORTRAN) did not have a while loop, but essentially all modern languages (including Fortran) do.
The semantics are fairly simple:
The idea of a while loop is that the body is executed while (i.e, as long as) the Boolean expression is true.
The flow chart on the right illustrates these simple semantics.
Note that if the Boolean expression is false initially, the loop body (the statements in the diagram) are not executed at all. We shall see in the next section a loop in which the body is executed at least once.
Note that when right after the while loop is executed, the
BE is FALSE.
Please don't get this wrong.
while ((i=getInput.nextInt) >= 0) { // process the non-negative i }
For example, when the loop on the right ends (assuming no EOF), the value of i is negative!
Lets write a program that adds two positive numbers just using ++ and --. One solution is here.
This is actually how one defines addition starting with Peano's postulates
The program picks a random number between 0 and 100 inclusive (101
possibilities).
The users repeatedly guess until they are correct.
For each guess, the program states higher
, lower
,
or correct
.
Let's do in class; one solution is in the book.