Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 150 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
150
Dung lượng
2,05 MB
Nội dung
do sum += i; // Add the current value of i to sum while(++i <= limit); Of course, you can and should still put the braces in. I advise that you always use braces around the body of a loop, even when it is only a single statement. There are often several ways of writing the code to produce a given result, and this is true here— you could also move the incrementing of the variable i back inside the loop and write it as follows: do { sum += i++; // Add the current value of i to sum } while (i <= limit); The value of i is now incremented using the postfix increment operator. If you were to use the prefix form, you would get the wrong result. Note that the semicolon after the while condition is present in each version of the loop. This is part of the loop statement so you must not forget to put it in. The pri- mary reason for using this loop over the while loop would be if you want to be sure that the loop code always executes at least once. Nested Loops You can nest loops of any kind one inside another to any depth. Let’s look at an example where you can use nested loops. A factorial of an integer, n, is the product of all the integers from 1 to n. It is written as n!. It may seem a little strange if you haven’t come across it before, but the factorial of an integer is very useful for calcu- lating combinations and permutations of things. For example, n! is the number of ways you can arrange n different things in sequence, so a deck of cards can be arranged in 52! different sequences. Let’s try cal- culating some factorial values. Try It Out Calculating Factorials This example will calculate the factorial of every integer from 1 up to a given limit. Enter the following code: public class Factorial { public static void main(String[] args) { long limit = 20L; // Calculate factorials of integers up to this value long factorial = 1L; // A factorial will be stored in this variable // Loop from 1 to the value of limit for (long i = 1L; i <= limit; i++) { factorial = 1L; // Initialize factorial for (long factor = 2; factor <= i; factor++) { factorial *= factor; } System.out.println(i + “! is “ + factorial); } } } 121 Loops and Logic 06_568744 ch03.qxd 11/23/04 9:25 PM Page 121 This program will produce the following output: 1! is 1 2! is 2 3! is 6 4! is 24 5! is 120 6! is 720 7! is 5040 8! is 40320 9! is 362880 10! is 3628800 11! is 39916800 12! is 479001600 13! is 6227020800 14! is 87178291200 15! is 1307674368000 16! is 20922789888000 17! is 355687428096000 18! is 6402373705728000 19! is 121645100408832000 20! is 2432902008176640000 How It Works All the variables used in this example are of type long. Factorial values grow very rapidly so by using type long you allow much larger factorials to be calculated than if you used type int. You still could have declared factor and i as type int without limiting the size of the factorial value that the program can produce, but the compiler would then need to insert casts to make the int values type long when- ever they were involved in an operation with a value of type long. The outer loop, controlled by i, walks through all the integers from 1 to the value of limit. In each itera- tion of the outer loop, the variable factorial is initialized to 1, and the nested loop calculates the facto- rial of the current value of i using factor as the control counter that runs from 2 to the current value of i. The resulting value of factorial is then displayed before going to the next iteration of the outer loop. Although you have nested a for loop inside another for loop here, as I said at the outset, you can nest any kind of loop inside any other. You could have written the nested loop as: for (long i = 1L; i <= limit; i++) { factorial = 1L; // Initialize factorial long factor = 2L; while (factor <= i) { factorial *= factor++; } System.out.println(i + “! is “ + factorial); } Now you have a while loop nested in a for loop. It works just as well, but it is rather more naturally coded as two nested for loops because they are both controlled by a counter. 122 Chapter 3 06_568744 ch03.qxd 11/23/04 9:25 PM Page 122 The continue Statement There are situations where you may want to skip all or part of a loop iteration. Suppose you want to sum the values of the integers from 1 to some limit, except that you don’t want to include integers that are multiples of three. You can do this using an if and a continue statement: for(int i = 1; i <= limit; i++) { if(i % 3 == 0) { continue; // Skip the rest of this iteration } sum += i; // Add the current value of i to sum } The continue statement is executed in this example when i is an exact multiple of 3, causing the rest of the current loop iteration to be skipped. Program execution continues with the next iteration if there is one, and if not, with the statement following the end of the loop block. The continue statement can appear anywhere within a block of loop statements. You may even have more than one continue in a loop. The Labeled continue Statement Where you have nested loops, there is a special form of the continue statement that enables you to stop executing the inner loop — not just the current iteration of the inner loop— and continue at the begin- ning of the next iteration of the outer loop that immediately encloses the current loop. This is called the labeled continue statement. To use the labeled continue statement, you need to identify the loop statement for the enclosing outer loop with a statement label. A statement label is simply an identifier that is used to reference a particu- lar statement. When you need to reference a particular statement, you write the statement label at the beginning of the statement in question, separated from the statement by a colon. Let’s look at an example: Try It Out Labeled continue You could add a labeled continue statement to omit the calculation of factorials of odd numbers greater than 10. This is not the best way to do this, but it does demonstrate how the labeled continue statement works: public class Factorial2 { public static void main(String[] args) { long limit = 20L; // to calculate factorial of integers up to this value long factorial = 1L; // factorial will be calculated in this variable // Loop from 1 to the value of limit If you have been concentrating, you may well have noticed that you don’t really need nested loops to display the factorial of successive integers. You can do it with a single loop that multiplies the current factorial value by the loop counter. However, this would be a very poor demonstration of a nested loop. 123 Loops and Logic 06_568744 ch03.qxd 11/23/04 9:25 PM Page 123 Try It Out Calculating Primes I There’s a little more code to this than the previous example. This program will find all the primes from 2 to 50: public class Primes { public static void main(String[] args) { int nValues = 50; // The maximum value to be checked boolean isPrime = true; // Is true if we find a prime // Check all values from 2 to nValues for(int i = 2; i <= nValues; i++) { isPrime=true; // Assume the current i is prime // Try dividing by all integers from 2 to i-1 for(int j = 2; j < i; j++) { if(i % j == 0) { // This is true if j divides exactly isPrime = false; // If we got here, it was an exact division break; // so exit the loop } } // We can get here through the break, or through completing the loop if(isPrime) // So is it prime? System.out.println(i); // Yes, so output the value } } } You should get the following output: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 How It Works There are much more efficient ways to calculate primes, but this program does demonstrate the break statement in action. The first step in main() is to declare two variables: int nValues = 50; // The maximum value to be checked boolean isPrime = true; // Is true if we find a prime 125 Loops and Logic 06_568744 ch03.qxd 11/23/04 9:25 PM Page 125 OuterLoop: for(long i = 1L; i <= limit; i++) { factorial = 1; // Initialize factorial for(long j = 2L; j <= i; j++) { if(i > 10L && i % 2L == 1L) { continue OuterLoop; // Transfer to the outer loop } factorial *= j; } System.out.println(i + “! is “ + factorial); } } } If you run this it will produce the following output: 1! is 1 2! is 2 3! is 6 4! is 24 5! is 120 6! is 720 7! is 5040 8! is 40320 9! is 362880 10! is 3628800 12! is 479001600 14! is 87178291200 16! is 20922789888000 18! is 6402373705728000 20! is 2432902008176640000 How It Works The outer loop has the label OuterLoop. In the inner loop, when the condition in the if statement is true, the labeled continue is executed causing an immediate transfer to the beginning of the next itera- tion of the outer loop. The condition in the if statements causes the calculation of the factorial to be skipped for odd values greater than 10. In general, you can use the labeled continue to exit from an inner loop to any enclosing outer loop, not just the one immediately enclosing the loop containing the labeled continue statement. Using the break Statement in a Loop You have seen how to use the break statement in a switch block. Its effect is to exit the switch block and continue execution with the first statement after the switch. You can also use the break statement to break out from a loop. When break is executed within a loop, the loop ends immediately, and execu- tion continues with the first statement following the loop. To demonstrate this, you will write a program to find prime numbers. In case you have forgotten, a prime number is an integer that is only exactly divisible by itself and 1. 124 Chapter 3 06_568744 ch03.qxd 11/23/04 9:25 PM Page 124 The first variable is the upper limit for integers to be checked to see if they are prime. The isPrime vari- able will be used to record whether a particular value is prime or not. The basic idea of the program is to go through the integers from 2 to the value of nValues and check each one to see if it has an integer divisor less than itself. The nested loops do this: for(int i = 2; i <= nValues; i++) { isPrime=true; // Assume the current i is prime // Try dividing by all integers from 2 to i-1 for(int j = 2; j < i; j++) { if(i % j == 0) { // This is true if j divides exactly isPrime = false; // If we got here, it was an exact division break; // so exit the loop } } // We can get here through the break, or through completing the loop if(isPrime) // So is it prime? System.out.println(i); // Yes, so output the value } The outer loop is indexed by i and steps through the possible values that need to be checked for prime- ness. The inner loop is indexed by j, the value of j being a trial divisor. This determines whether any integer less than the value being tested for primality is an exact divisor. The checking is done in the if statement in the inner loop. If j divides i exactly, i%j will be 0, so isPrime will be set to false. In this case the break will execute to exit the inner loop — there is no point in continuing as you now know that the value being tested is not prime. The next statement to be executed will be the if statement after the closing brace of the inner loop block. You can also reach this point by a normal exit from the loop that occurs when the value is prime so you need a way to deter- mine whether the current value of i was found to be prime or not. The isPrime variable solves this problem. You just check the value of isPrime and if it has the value true, you have a prime to display so you execute the println() call. You could simplify this example if you used the labeled continue statement instead of the break statement: Try It Out Calculating Primes II Try the following changes to the code in the Primes class: public class Primes2 { public static void main(String[] args) { int nValues = 50; // The maximum value to be checked // Check all values from 2 to nValues OuterLoop: for(int i = 2; i <= nValues; i++) { // Try dividing by all integers from 2 to i-1 for(int j = 2; j < i; j++) { if(i%j == 0) { // This is true if j divides exactly 126 Chapter 3 06_568744 ch03.qxd 11/23/04 9:25 PM Page 126 continue OuterLoop; // so exit the loop } } // We only get here if we have a prime System.out.println(i); // so output the value } } } If you’ve keyed it in correctly, you’ll get the same output as the previous example. How It Works You no longer need the isPrime variable to indicate whether you have a prime or not, as the output state- ment can be reached only through a normal exit from the inner loop. When this occurs it means you have found a prime. If you get an exact divisor in the inner loop, it implies that the current value of i is not prime, so the labeled continue statement transfers immediately to the next iteration of the outer loop. Breaking Indefinite Loops You will find that sometimes you need to use a loop where you don’t know in advance how many itera- tions will be required. This can arise when you are processing external data items that you might be reading in from the keyboard, for example, and you cannot know in advance how many there will be. You can often use a while loop in these circumstances, with the loop condition determining when the loop should end, but sometimes it can be convenient to use an indefinite loop instead and use a break statement in the loop body to end the loop. An indefinite loop is a loop where the control condition is such that the loop apparently continues to execute indefinitely. In this case, the mechanism to end the loop must be in the body of the loop. Try It Out Calculating Primes III Suppose you want the Primes program to generate a given number of primes, rather than check up to a given integer value. In this case, you don’t know how many numbers you need to check to generate the required number of primes. This is a case where an indefinite loop is useful. You can code this as follows: public class FindPrimes { public static void main(String[] args) { int nPrimes = 50; // The maximum number of primes required OuterLoop: for(int i = 2; ; i++) { // This loop runs forever // Try dividing by all integers from 2 to i-1 for(int j = 2; j < i; j++) { if(i % j == 0) { // This is true if j divides exactly continue OuterLoop; // so exit the loop } } // We only get here if we have a prime System.out.println(i); // so output the value 127 Loops and Logic 06_568744 ch03.qxd 11/23/04 9:25 PM Page 127 if( nPrimes == 0) { // Decrement the prime count break; // It is zero so we have them all } } } } This program will output the first 50 primes. How It Works This program is very similar to the previous version. The principal differences are that nPrimes contains the number of primes required, so the program will produce the first 50 primes, instead of finding the primes between 2 and 50, and the for outer loop, controlled by i, has the loop condition omitted, so the loop has no direct mechanism for ending it. The loop must be terminated by the code within the loop; otherwise, it will continue to execute indefinitely. Here the termination of the outer loop is controlled by the if statement following the output statement. As you find each prime, the value is displayed, after which the value of nPrimes is decremented in the if statement: if( nPrimes == 0) { // Decrement the prime count break; // It is zero so we have them all } The break statement will be executed when nPrimes has been decremented to zero, and this will exit the outer loop. The Labeled break Statement Java also makes a labeled break statement available to you. This enables you to jump immediately to the statement following the end of any enclosing statement block or loop that is identified by the label in the labeled break statement. The label precedes the opening brace of the block that it identifies. Figure 3-9 illustrates how the labeled break statement works. The labeled break enables you to break out to the statement following an enclosing block or loop that has an identifying label, regardless of how many levels of nested blocks there are. You might have sev- eral loops nested one within the other, for example, where you could use the labeled break to exit from the innermost loop (or indeed any of them) to the statement following the outermost loop. You just need to add a label to the beginning of the relevant block or loop that you want to break out of, and use that label in the break statement. 128 Chapter 3 06_568744 ch03.qxd 11/23/04 9:25 PM Page 128 Figure 3-9 Just to see it working you can alter the previous example to use a labeled break statement: public class FindPrimes2 { public static void main(String[] args) { int nPrimes = 50; // The maximum number of primes required // Check all values from 2 to nValues OuterLoop: for(int i = 2; ; i++) { // This loop runs forever // Try dividing by all integers from 2 to i-1 for(int j = 2; j < i; j++) { if(i % j == 0) { // This is true if j divides exactly continue OuterLoop; // so exit the loop } } // We only get here if we have a prime System.out.println(i); // so output the value if( nPrimes == 0) { // Decrement the prime count break OuterLoop; // It is zero so we have them all } } // break OuterLoop goes to here } } } breaks our beyond Block1 breaks our beyond Block2 breaks our beyond OuterLoop Block1: { } // end of Block1 Block2: { } // end of Block2 OuterLoop: for( ) { break Block1; while( ) { } break Block2; break OuterLoop; 129 Loops and Logic 06_568744 ch03.qxd 11/23/04 9:25 PM Page 129 The program works in exactly the same way as before. The labeled break ends the loop operation begin- ning with the label OuterLoop, and so effectively branches to the point indicated by the comment. Of course, in this instance its effect is no different from that of an unlabeled break. However, in general this would work wherever the labeled break statement was within OuterLoop. For example, it could be nested inside another inner loop, and its effect would be just the same— control would be transferred to the statement following the end of OuterLoop. The following code fragment illustrates this sort of situa- tion. The label this time is Outside: Outside: for(int i = 0 ; i< count1 ; i++) { for(int j = 0 ; j< count2 ; j++) { for(int k = 0 ; k< count3 ; k++) { break Outside; } } } // The labeled break transfers to here The labeled break is not needed very often, but when you need to break out of a deeply nested set of loops, it can be invaluable since it makes it a simple operation. Assertions Every so often you will find that the logic in your code leads to some logical condition that should always be true. If you test an integer and establish that it is odd, it is certainly true that it cannot be even, for example. You may also find yourself writing a statement or statements that, although they could be executed in theory, in practice they never really should be. I don’t mean by this the usual sorts of errors that occur, such as some incorrect data being entered somehow, which should be handled ordi- narily by the normal code. I mean circumstances where if the statements were to be executed, it would imply that something was very seriously wrong with the program or its environment. These are pre- cisely the circumstances to which assertions apply. A simple assertion is a statement of the form assert logical_expression; Here, assert is a keyword, and logical_expression is any expression that results in a value of true or false. When this statement executes, if logical_expression evaluates to true, then the program continues normally. If logical_expression evaluates to false, the program will be terminated with an error message starting with: java.lang.AssertionError 130 Chapter 3 06_568744 ch03.qxd 11/23/04 9:25 PM Page 130 [...]... temperature at at at at at at at at at at location location location location location location location location location location 1 = 12. 27333 45 2 = 12. 01 25 1 9 3 = 11 .54 522 4 = 12. 49 054 3 5 = 12 .57 4791 6 = 11. 950 3 15 7 = 11.4 929 08 8 = 13.176439 9 = 12 .56 5 457 10 = 12. 981103 You should get different results 147 Arrays and Strings The inner for loop iterates over the elements in the array that is currently... is shown in Figure 4 -5 samples[0][0] samples[0] samples [2] .length is 3 samples[1][0] samples [2] [1] samples [2] [0] samples [2] [1] samples [2] [2] samples[3][0] samples[3][1] samples[3] [2] samples[3][3] samples[4][0] samples[4][1] samples[4] [2] samples[4][3] samples[4][4] samples [5] [0] samples [5] [1] samples [5] [2] samples [5] [3] samples [5] [4] samples[1] samples[4].length is 5 samples [2] samples.length is 6... Figure 4 -2 138 Arrays and Strings primes[0] primes[1] primes [2] primes[3] primes[4] primes [5] primes[6] primes[7] primes[8] primes[9] Reference to old array is replaced Old array is discarded primes New array is created Refers to new array primes[0] primes[1] primes [2] primes[3] primes[47] primes[48] Reassigning an Array Variable Figure 4 -2 After executing the statement shown in Figure 4 -2, the array... Chapter 3: import static java. lang.Math.ceil; import static java. lang.Math.sqrt; public class MorePrimes { public static void main(String[] args) { long[] primes = new long [20 ]; // Array to store primes primes[0] = 2L; // Seed the first prime primes[1] = 3L; // and the second int count = 2; // Count of primes found – up to now, // which is also the array index long number = 5L; // Next integer to be... specific example The number 24 has a square root that is a bit less than 5 You can factorize it as 2 * 12, 3 * 8, 4 * 6; then you come to cases where the first factor is greater than the square root so the second is less, 6 * 4, 8 * 3, etc., and so you are repeating the pairs of factors you already have You first declare the array primes to be of type long, and define it as having 20 elements You set the... samples[3] samples[4] samples [5] [5] samples [5] Figure 4 -5 The 21 elements in the array will occupy 84 bytes When you need a two-dimensional array with rows of varying length, allocating them to fit the requirement can save a considerable amount of memory compared to just using rectangular arrays where the row lengths are all the same To check out that the array is as shown in Figure 4 -5, you could define it... 4-3 long[] even = (2L, 4L, 6L, 8L, 10L); even even[0] even[1] 2 value[0] even [2] 4 value[1] even[3] 6 value [2] even[4] 10 8 value[3] value[4] value long[] value = even; Figure 4-3 You have created two array variables, but you have only one array Both arrays refer to the same set of elements, and you can access the elements of the array through either variable name — for example, even [2] refers to the... second expression in the assertion statement: java. lang.AssertionError: daysInMonth has the value 32 at TryAssertions.main(TryAssertions .java: 15) Exception in thread “main” I will use assertions from time to time in the examples in subsequent chapters Summar y In this chapter you have learned about all of the essential mechanisms for making decisions in Java You have also learned all of the looping... Don’t forget that, once you have compiled the program, you must execute it with assertions enabled, like this: java -enableassertions TryAssertions You should then get the following output: java. lang.AssertionError at TryAssertions.main(TryAssertions .java: 15) Exception in thread “main” 1 32 Chapter 3 ❑ The labeled break statement enables you to break out of a loop or block of statements that encloses... char[] to hold 50 characters with the following statement: char[] message = new char [50 ]; Keep in mind that characters are stored as Unicode in Java so each element occupies 2 bytes If you wanted to initialize every element of this array to a space character, you could either use a for loop to iterate over the elements of the array, or just use the fill() method in the Arrays class, like this: java. util.Arrays.fill(message, . 1 2! is 2 3! is 6 4! is 24 5! is 120 6! is 720 7! is 50 40 8! is 40 320 9! is 3 628 80 10! is 3 628 800 12! is 479001600 14! is 8717 829 120 0 16! is 20 922 789888000 18! is 64 023 737 057 28 000 20 ! is 24 329 020 08176640000 How. output: 1! is 1 2! is 2 3! is 6 4! is 24 5! is 120 6! is 720 7! is 50 40 8! is 40 320 9! is 3 628 80 10! is 3 628 800 11! is 39916800 12! is 479001600 13! is 622 7 020 800 14! is 8717 829 120 0 15! is 1307674368000 16!. 622 7 020 800 14! is 8717 829 120 0 15! is 1307674368000 16! is 20 922 789888000 17! is 355 687 428 096000 18! is 64 023 737 057 28 000 19! is 121 6 451 004088 320 00 20 ! is 24 329 020 08176640000 How It Works All the variables