Plans for the Week and Assignments: 1. MONDAY(10/01): Finish Programming Round 2, and Start Random NumberGenerator Presentations. HW: Read p.190-192, "Programming Tips" and "Chapter Summary", then solve prob.2, 4, and 6 on pages 192-193. 2. TUESDAY(10/02): Continue with Random Number Generator Presentations. HW: Solve prob.8, 12, and 14 on page 193. 3. WEDNESDAY(10/03): Check all homework assignments from page 178 to current. HW: Read p.195-200, then solve prob.1 and 2 on page 209. 4. THURSDAY(10/04): Operands and Relational Operators. The char Type. HW: Read p.200-205, then solve prob.3 and 4 on page 209. 5. FRIDAY(10/05): Compound Statements and the else Clause. HW: Read p.205-208, then solve prob.5 and 6 on page 209. 6. MONDAY(10/08): Collect all homework assignments from page 178 to current. Computer lab time for Prog 4_1 Euclid's GCD, using the Keyboard class. HW: Solve prob.7 and 8 on page 210. 7. TUESDAY(10/09): Computer lab time for Prog 4_2 Fraction Reducer, using the Keyboard class. HW: Solve prob.9 and 10 on page 210. 8. WEDNESDAY(10/10): Computer lab time for Prog 4_3 Distance Between Points (Page 193, #8), using the Keyboard class. HW: Solve prob.11 and 12 on pages 210-11. 9. THURSDAY(10/11): Computer lab time for Prog 4_4 Body Mass Index (Page 193, #14), using the Keyboard class. HW: Solve prob.13, 14, and 15 on page 211. 10. FRIDAY(10/12): Computer lab time for Prog 4_5 Area of Triangle with Hero's Formula, using the Keyboard class. HW: Read p.212-222, then solve prob.1 and 2 on page 245. 11. MONDAY(10/15): Computer lab time for Prog 4_6 Zeller's Conjecture,using the Keyboard class. HW: Read p.229-235, then solve prob.3 and 5 on pages 245-246. 12. TUESDAY(10/16): Computer lab time for Prog 4_7 Guess My Number, using the Keyboard class. HW: Read p.236-244, then solve prob.6, 7, and 8 on page 246. 13. WEDNESDAY(10/17): Computer lab time for Prog 4_8 Finding Prime Numbers. HW: Solve prob.9, 10, and 11 on pages 246-247. 14. THURSDAY(10/18): Computer lab time for Prog 4_9 ASCII Code to Encrypt a Statement. HW: Solve prob.15 and 16 on page 248. 15. FRIDAY(10/19): Computer lab time for Prog 4_10 ASCII Code to Decode a Statement. HW: Solve prob.19 and 20 on pages 249-250. 18. MONDAY(10/22): Computer lab time for Prog 4_11 Finding Pythagorean Triples Using Liberi's Method of 1/m + 1/(m+2) = a/b, with natural number m>1, and a2 + b2 = c2. HW: Read pages 251-55 and solve prob. 1, 2, 3, and 4 on page 255. 19. TUESDAY(10/23): Computer lab time for Prog 4_12 Finding Pythagorean Triples Using m2 – n2 , 2mn , m2 + n2. HW: Solve prob. 5, 6, and 7 on pages 255-56. 20. WEDNESDAY(10/24): Chapter 4 Review. HW: Finish all review handouts. 21. THURSDAY(10/25): TEST on Ch.4 - Conditionals, Char, Classes, and Loop Control. HW: Go to Website for notes on Ch.5 - Additional Features of Loop-Control Statements. 22. FRIDAY(10/26): Computer lab time for Prog 4_13 Finding Pythagorean Triples Using Nested Loops. HW: Read pages 278-87 and solve prob. 1 through 8 on page 288.
Very Important: If you have any questions or were absent from class, see me before school (8:00 - 8:30 AM), during Lunch, 7th hour, or after school. Best to send an email to rpersin@fau.edu.
Storing CharactersVariables of the type char store a single character. They each occupy 16 bits, two bytes, in memory because all characters in Java are stored as Unicode. To declare and initialize a character variable myCharacter you would use the statement: char myCharacter = 'X';
This initializes the variable with the Unicode character representation of the letter 'X'. You must put single quotes around a character in a statement – 'X'. This is necessary to enable the compiler to distinguish between the character 'X' and a variable with the name X. Note that you can't use double quotes here as they are used to delimit a character string. A character string such as "X" is quite different from the literal of type char, 'X'. Character Escape SequencesIf you are using an ASCII text editor you will only be able to enter characters directly that are defined within ASCII. You can define Unicode characters by specifying the hexadecimal representation of the character codes in an escape sequence. An escape sequence is simply an alternative means of specifying a character, often by its code. A backslash indicates the start of an escape sequence, and you create an escape sequence for a Unicode character by preceding the four hexadecimal digits of the character by \u. Since the Unicode coding for the letter X is 0x0058 (the low order byte is the same as the ASCII code), you could also declare and define myCharacter with the statement: char myCharacter = '\u0058';
You can enter any Unicode character in this way, although it is not exactly user-friendly for entering a lot of characters. You can get more information on the full Unicode character set visiting http://www.unicode.org/. As you have seen, we can write a character string (a String literal) enclosed between double quotes. Because the backslash indicates the beginning of an escape sequence in a character string, you must use an escape sequence to specify a backslash character itself in text strings, \\. Since a single quote is used to delimit characters, and we use a double quote to delimit a text string, we also need escape sequences for these. You can define a single quote with the escape sequence \', and a double quote with \". For example, to produce the output: "It's freezing in here", he said coldly. you could write: System.out.println("\"It\'s freezing in here\", he said coldly.");
In fact, it's not strictly necessary to use an escape sequence to specify a single quote within a string, but obviously it will be when you want to specify it as a single character. Of course, it is always necessary to specify a double quote within a string using an escape sequence otherwise it would be interpreted as the end of the string. There are other escape characters you can use to define control characters:
Character ArithmeticYou can perform arithmetic on char variables. With myCharacter containing the character 'X', the statement: myCharacter += 1; // Increment to next character
will result in the value of myCharacter being changed to 'Y'. This is because the Unicode code for 'Y' is one more than the code for 'X'. You could use the increment operator ++ to increase the code stored in myCharacter by just writing: ++myCharacter; // Increment to next character
You can use variables of type char in an arithmetic expression, and their values will be converted to type int to carry out the calculation. It doesn't necessarily make a whole lot of sense, but you could write, char aChar = 0; char bChar = '\u0025'; aChar = (char)(2*bChar + 8); which will leave aChar holding the code for X – which is 0x0058. Making ComparisonsJava provides you with six relational operators for comparing two data values. Either of the data values you are comparing can be variables, constants or expressions drawn from Java's primitive data types – byte, short, int, long, char, float or double.
As you see, each operator produces either the value true, or the value false, and so is eminently suited to the business of making decisions. If you wish to store the result of a comparison, you use a boolean variable. We saw how to declare these in the last set of notes. For example you can define a boolean variable state and you can set its value in an assignment as follows: boolean state = false; state = x - y < a + b; The value of the variable state will be set to true in the assignment if x-y is less than a+b, and to false otherwise. To understand how the expression above is evaluated, take a look back at the precedence table for operators that we saw in the last set of notes. You will see that the comparison operators are all of lower precedence than the arithmetic operators, so arithmetic operations will always be completed before any comparisons are made, unless of course there are parentheses saying otherwise. The expression, x - y == a + b
will produce the result true if x-y is equal to a+b, since these arithmetic sub-expressions will be evaluated first, and the values that result will be the operands for the == operator. Of course, it is helpful to put the parentheses in, even though they are not strictly necessary. It leaves no doubt as to what is happening if you write: (x – y) == (a + b)
Note that if the left and right operands of a relational operator are of differing types, values will be promoted in the same way as we saw in the last set of notes for mixed arithmetic expressions. So if aDouble is of type double, and number is of type int, in the following expression: aDouble < number + 1
the value produced by number + 1 will be calculated as type int, and this value will be promoted to type double before comparing it with the value of aDouble. The if StatementThe first statement we will look at that can make use of the result of a comparison is the if statement. The if statement, in its simplest usage, is of the form: if(expression)
statement;
where expression can be any expression that produces a value true or false. You can see a graphical representation of this logic in the following diagram: ![]() If the value of expression is true, the statement that follows the if is executed, otherwise it isn't. A practical example of this is as follows: if(number%2 != 0) // Test if number is odd ++number; // If so make it even The if tests whether the value of number is odd by comparing the remainder, after dividing by 2, with 0. If the remainder isn't equal to 0, the value of number is odd, so we add 1 to make it even. If the value of number is even, the statement incrementing number will not be executed. Note how the statement is indented. This is to show that it is subject to the if condition. You should always indent statements in your Java programs as cues to the program structure. We will gather more guidelines on the use of statement indenting as we work with more complicated examples. You may sometimes see a simple if written on a single line. The previous example could have been written: if(number%2 != 0) ++number; // If number is odd, make it even
This is perfectly legal. The compiler ignores excess spaces and newline characters – the semi-colon acts as the delimiter for a statement. Writing an if in this way saves a little space, and occasionally it can be an aid to clarity, when you have a succession of such comparisons for instance, but generally it is better to write the action statement on a separate line to the condition being tested. Statement BlocksIn general, wherever you can have one executable statement in Java, you can replace it with a block of statements enclosed between braces instead. So a statement block between braces can also be nested in another statement block to any depth. This means that we can use a statement block within the basic if statement that we just saw. The if statement can equally well be of the form: if(expression) { statement 1; statement 2; ... statement n; } Now if the value of expression is true, all the statements enclosed in the following block will be executed. Of course, without the braces to enclose the block, the code no longer has a statement block: if(expression) statement 1; statement 2; ... statement n; Here, only the first statement, statement 1, will be omitted when the if expression is false; the remaining statements will always be executed regardless of the value of expression. You can see from this that indenting is just a visual cue to the logic. It has no effect on how the program code executes. This looks as though the sequence of statements belongs to the if, but only the first one does because there are no braces. The indenting is incorrect here. We will adopt the convention of having the opening brace on the same line as the statement. The closing brace will then be aligned with the statement. We will indent all the statements within the block from the braces so that they are easily identified as belonging to the block. There are other conventions that you can use if you prefer, the most important consideration being that you are consistent. As a practical example of an if statement that includes a statement block, we could write: if(number%2 != 0) { // Test if number is odd // If so make it even and output a message ++number; System.out.println("Number was forced to be even and is now " + number); } Now both statements between the braces are executed if the if expression is true, and neither of them is executed if the if expression is false. It is a good practice to always have opening and closing braces even when there is only a single action statement, this helps clarify the code and will stop confusion of its logic. Statement blocks are more than just a convenient way of grouping statements together – they affect the life and accessibility of variables. We will learn more about statement blocks when we discuss variable scope later in this chapter. In the meantime let's look a little deeper into what we can do with the if statement. The else ClauseWe can extend the basic if statement by adding an else clause. This provides a second choice of statement, or statement block, that is executed when the expression in the if statement is false. You can see the syntax of this clause, and how the program's control flow works, in this diagram: This provides an explicit choice between two courses of action – one for when the if expression is true and another for when it is false. We can apply this in a console program and try out the random() method from the Math class at the same time. Try It Out – if-elseWhen you have entered the program text, save it in a file called NumberCheck.java. Compile it and then run it a few times to see what results you get. public class NumberCheck { public static void main(String[] args) { int number = 0; number = 1+(int)(100*Math.random()); // Random integer between 1 & 100 if(number%2 == 0) { // Test if it is even System.out.println("You have got an even number, " + number); } else { System.out.println("You have got an odd number, " + number); } } } How It Works We saw the method random() in the standard class Math in the previous set of notes. It returns a random value of type double between 0.0 and 1.0, but the result is always less than 1.0, so the largest number you will get is 0.9999... (with the number of recurring digits being limited to the maximum number that the type double will allow, of course). Consequently, when we multiply the value returned by 100.0 and convert this value to type int with the explicit cast, we discard any fractional part of the number and produce a random integer between 0 and 99. Adding 1 to this will result in a random integer between 1 and 100, which we store in the variable number. We then generate the program output in the if statement. If the value of number is even, the first println() call is executed, otherwise the second println() call in the else clause is executed. Note the use of indentation here. It is evident that main() is within the class definition, and the code for main() is clearly distinguished. You can also see immediately which statement is executed when the if expression is true, and which applies when it is false. Nested if StatementsThe statement that is executed when an if expression is true can be another if, as can the statement in an else clause. This will enable you to express such convoluted logic as "if my bank balance is healthy then I will buy the car if I have my check book with me, else I will buy the car if I can get a loan from the bank". An if statement that is nested inside another can also itself contain a nested if. You can continue nesting ifs one inside the other like this for as long as you still know what you are doing – or even beyond if you enjoy confusion. To illustrate the nested if statement, we can modify the if from the previous example: if(number%2 == 0) { // Test if it is even
if(number < 50) { // Output a message if number is < 50
System.out.println("You have got an even number < 50, " + number);
}
} else {
System.out.println("You have got an odd number, " + number); // It is odd
}
Now the message for an even value is only displayed if the value of number is also less than 50. The braces around the nested if are necessary here because of the else clause. The braces constrain the nested if in the sense that if it had an else clause, it would have to appear between the braces enclosing the nested if. If the braces were not there, the program would still compile and run but the logic would be different. Let's see how. With nested ifs, the question of to which if statement a particular else clause belongs often arises. If we remove the braces from the code above, we have: if(number%2 == 0) // Test if it is even if(number < 50 ) // Output a message if number is < 50 System.out.println("You have got an even number < 50, " + number); else System.out.println("You have got an odd number, " + number); // It is odd This has substantially changed the logic from what we had before. The else clause now belongs to the nested if that tests whether number is less than 50, so the second println()call is only executed for even numbers that are greater than or equal to 50. This is clearly not what we wanted since it makes nonsense of the output in this case, but it does illustrate the rule for connecting elses to ifs, which is: An else always belongs to the nearest preceding if that is not in a separate block, and is not already spoken for by another else. You need to take care that the indenting of statements with nested ifs is correct. It is easy to convince yourself that the logic is as indicated by the indentation, even when this is completely wrong. Let's try the if-else combination in another program: Try It Out – Deciphering Characters the Hard WayCreate the class LetterCheck, and code its main() method as follows: public class LetterCheck { public static void main(String[] args) { char symbol = 'A'; symbol = (char)(128.0*Math.random()); // Generate random character if(symbol >= 'A') { // Is it A or greater? if(symbol <= 'Z') { // yes, and is it Z or less? // Then it is a capital letter System.out.println("You have the capital letter " + symbol); } else { // It is not Z or less if(symbol >= 'a') { // So is it a or greater? if(symbol <= 'z') { // Yes, so is it z or less? // Then it is a small letter System.out.println("You have the small letter " + symbol); } else { // It is not less than z System.out.println( "The code is greater than a but it's not a letter"); } } else { System.out.println( "The code is less than a and it's not a letter"); } } } else { System.out.println("The code is less than A so it's not a letter"); } } } How It Works This program figures out whether the character stored in the variable symbol is an uppercase letter, a lowercase letter, or some other character. The program first generates a random character with a numeric code between 0 and 127, which corresponds to the characters in the basic 7-bit ASCII (ISO 646) character set. The Unicode coding for the ASCII characters is numerically the same as the ASCII code values. Within this character set, the letters 'A' to 'Z' are represented by a contiguous group of ASCII codes with decimal values from 65 to 90. The lowercase letters are represented by another contiguous group with ASCII code values that have decimal values from 97 to 122. So to convert any capital letter to a lowercase letter, you just need to add 32 to the character code. We have four if statements altogether. The first if tests whether symbol is 'A' or greater. If it is, it could be a capital letter, a small letter, or possibly something else. But if it isn't, it is not a letter at all, so the else for this if statement (towards the end of the program) produces a message to that effect. The nested if statement, which is executed if symbol is 'A' or greater, tests whether it is 'Z' or less. If it is, then symbol definitely contains a capital letter and the appropriate message is displayed. If it isn't then it may be a small letter, so another if statement is nested within the else clause of the first nested if, to test for this possibility. The if statement in the else clause tests for symbol being greater than 'a'. If it isn't, we know that symbol is not a letter and a message is displayed. If it is, another if checks whether symbol is 'z' or less. If it is we have a small letter, and if not we don't have a letter at all. You will have to run the example a few times to get all the possible messages to come up. They all will – eventually. Logical OperatorsThe tests we have put in the if expressions have been relatively simple so far, except perhaps for the last one. The real world is typically more complicated. You will often want to combine a number of conditions so that you execute a particular course, for example, if they are all true simultaneously. You can ride the roller coaster if you are over 12 years old, over four feet tall, and less than six feet six. Failure on any count and it's no go. Sometimes, though, you may need to test for any one of a number of conditions being true, for example, you get a lower price entry ticket if you are under 16, or over 65. You can deal with both of these cases, and more, using logical operators to combine several expressions that have a value true or false. Because they operate on boolean values they are also referred to as boolean operators. There are five logical operators that operate on boolean values:
These are very simple, the only point of potential confusion being the fact that we have the choice of two operators for each of AND and OR. The extra operators are the bitwise & and | that you can also apply to boolean values where they have an effect that is subtly different from && and ||. We'll first consider what each of these are used for in general terms, then we'll look at how we can use them in an example. Boolean AND OperationsYou can use either AND operator, && or &, where you have two logical expressions that must both be true for the result to be true – that is, you want to be rich and healthy. Either operator will produce the same result from the logical expression. We will come back to how they are different in a moment. First, let's explore how they are used. All of the following discussion applies equally well to & as well as &&. Let's see how logical operators can simplify the last example. You could use the && operator if you were testing a variable of type char to determine whether it contained an uppercase letter or not. The value being tested must be both greater than or equal to 'A' AND less than or equal to 'Z'. Both conditions must be true for the value to be a capital letter. Taking the example from our previous program, with a value stored in a char variable symbol, we could implement the test for an uppercase letter in a single if by using the && operator: if(symbol >= 'A' && symbol <= 'Z') System.out.println("You have the capital letter " + symbol); We already know that the relational operators will be executed before the && operator, so no parentheses are necessary. Here, the output statement will be executed only if both of the conditions combined by the operator && are true. However, as we have said before, it is a good idea to add parentheses if they make the code easier to read. It also helps to avoid mistakes. In fact, the result of an && operation is very simple. It is true only if both operands are true, otherwise the result is false. We can now rewrite the set of ifs from the last example. Try It Out – Deciphering Characters the Easy WayReplace the outer if-else loop and its contents in LetterCheck.java with the following: if(symbol >= 'A' && symbol <= 'Z') { // Is it a capital letter System.out.println("You have the capital letter " + symbol); } else { if(symbol >= 'a' && symbol <= 'z') { // or is it a small letter? System.out.println("You have the small letter " + symbol); } else { // It is not less than z System.out.println("The code is not a letter"); } } How It Works Using the && operator has condensed the example down quite a bit. We now can do the job with two ifs, and it's certainly easier to follow what's happening. You might want to note that when the statement in an else clause is another if, the if is sometimes written on the same line as the else, as in: if(symbol >= 'A' && symbol <= 'Z') { // Is it a capital letter
System.out.println("You have the capital letter " + symbol);
} else if(symbol >= 'a' && symbol <= 'z') { // or is it a small letter?
System.out.println("You have the small letter " + symbol);
} else { // It is not less than z
System.out.println("The code is not a letter");
}
I think the original is clearer, so I prefer not to do this. && versus &So what distinguishes && from & ? The difference between them is that the conditional && will not bother to evaluate the right-hand operand if the left-hand operand is false, since the result is already determined in this case to be false. This can make the code a bit faster when the left- hand operand is false. For example, consider the following statements: int number = 50; if(number<40 && (3*number - 27)>100) { System.out.println("number = " + number); } Here the expression (3*number - 27)>100 will never be executed since the expression number<40 is always false. On the other hand, if you write the statements as: int number = 50; if(number<40 & (3*number - 27)>100) { System.out.println("number = " + number); } the effect is different. The whole logical expression is always evaluated, so even though the left-hand operand of the & operator is false and the result is a forgone conclusion once that is known, the right hand operand ((3*number - 27)>100) will still be evaluated. So, we can just use && all the time to make our programs a bit faster and forget about &, right? Wrong – it all depends on what you are doing. Most of the time you can use &&, but there are occasions when you will want to be sure that the right-hand operand is evaluated – and equally, there are instances where you want to be certain the right-hand operand won't be evaluated if the left operand is false. The first situation can arise for instance when the right hand expression involves modifying a variable – and you want the variable to be modified in any event. An example of a statement like this is: if(++value%2 == 0 & ++count < limit) { // Do something } Here, the variable count will be incremented in any event. If you use && instead of &, count will only be incremented if the left operand of the AND operator is true. You get a different result depending on which operator is used. We can illustrate the second situation with the following statement: if(count > 0 && total/count > 5) { // Do something... } In this case the right operand for the && operation will only be executed if the left operand is True – that is, when count is positive. Clearly, if we were to use & here, and count happened to be zero, we will be attempting to divide the value of total by 0, which in the absence of code to prevent it, will terminate the program. Boolean OR OperationsThe OR operators, | and ||, apply when you want a true result if either or both of the operands are true. The conditional OR, ||, has a similar effect to the conditional AND, in that it omits the evaluation of the right-hand operand when the left-hand operand is true. Obviously if the left operand is true, the result will be True regardless of whether the right operand is true or false. Let's take an example. A reduced entry ticket price is issued to under 16 year olds and to those aged 65 or over; this could be tested using the following if: if(age < 16 || age>= 65) { ticketPrice *= 0.9; // Reduce ticket price by 10% } The effect here is to reduce ticketPrice by ten percent if either condition is true. Clearly in this case both conditions cannot be true. With an | or an || operation, you only get a false result if both operands are false. If either or both operands are true, the result is true. Boolean NOT OperationsThe third type of logical operator, !, takes one boolean operand and inverts its value. So if the value of a boolean variable, state, is true, then the expression !state has the value false, and if it is false then !state becomes true. To see how the operator is used with an expression, we could rewrite the code fragment we used to provide discounted ticket price as: if(!(age >= 16 && age < 65)) { ticketPrice *= 0.9; // Reduce ticket price by 10% } The expression (age >= 16 && age < 65) is true if age is from 16 to 64. People of this age do not qualify for the discount, so the discount should only be applied when this expression is false. Applying the ! operator to the result of the expression does what we want. We could also apply the ! operator in an expression that was a favorite of Charles Dickens: !(Income>Expenditure) If this expression is true, the result is misery, at least as soon as the bank starts bouncing your checks. Of course, you can use any of the logical operators in combination if necessary. If the theme park decides to give a discount on the price of entry to anyone who is under 12 years old and under 48 inches tall, or someone who is over 65 and over 72 inches tall, you could apply the discount with the test: if((age < 12 && height < 48) || (age > 65 && height > 72)) { ticketPrice *= 0.8; // 20% discount on the ticket price } The parentheses are not strictly necessary here, as && has a higher precedence than ||, but adding the parentheses makes it clearer how the comparisons combine and makes it a little more readable. Don't confuse the bitwise operators &, |, and !, with the logical operators that look the same. Which type of operator you are using in any particular instance is determined by the type of operand with which you use it. The bitwise operators apply to integer types and produce an integer result. The logical operators apply to operands that have boolean values and produce a result of type boolean – true or false. You can use both bitwise and logical operators in an expression if it is convenient to do so.
Character Testing Using Standard Library MethodsWhile testing characters using logical operators is a useful way of demonstrating how these operators work, in practice there is an easier way. The standard Java packages provide a range of standard methods to do the sort of testing for particular sets of characters such as letters or digits that we have been doing with if statements. They are all available within the class Character, which is automatically available in your programs. For example, we could have written the if statement in our LetterCheck program as shown in the following example. Try It Out – Deciphering Characters TriviallyReplace the code body of the LetterCheck class with the following code: if(Character.isUpperCase(symbol)) { System.out.println("You have the capital letter " + symbol); } else { if(Character.isLowerCase(symbol)) { System.out.println("You have the small letter " + symbol); } else { System.out.println("The code is not a letter"); } } How It Works The isUpperCase() method returns true if the char value passed to it is uppercase, and false if it is not. Similarly, the isLowerCase() method returns true if the char value passed to it is lowercase. The following table shows some of the other methods included in the class Character that you may find useful for testing characters. In each case the argument to be tested is of type char, and is placed between the parentheses following the method name:
|
|
|