AhmadLang / Java, How To Program, 2004
.pdf
Common Programming Error 6.6
Placing a semicolon after the right parenthesis enclosing the parameter list of a method declaration is a syntax error.
[Page 241]
Common Programming Error 6.7
Redeclaring a method parameter as a local variable in the method's body is a compilation error.
Common Programming Error 6.8
Forgetting to return a value from a method that should return a value is a compilation error. If a return value type other than void is specified, the method must contain a return statement that returns a value consistent with the method's return-value-type. Returning a value from a method whose return type has been declared void is a compilation error.
[Page 241 (continued)]
6.6. Method Call Stack and Activation Records
To understand how Java performs method calls, we first need to consider a data structure (i.e., collection of related data items) known as a stack. Students can think of a stack as analogous to a pile of dishes. When a dish is placed on the pile, it is normally placed at the top (referred to as pushing the dish onto the stack). Similarly, when a dish is removed from the pile, it is always removed from the top (referred to as popping the dish off the stack). Stacks are known as last-in, first-out (LIFO) data structuresthe last item pushed (inserted) on the stack is the first item popped (removed) from the stack.
When a program calls a method, the called method must know how to return to its caller, so the return address of the calling method is pushed onto the program execution stack (sometimes referred to as the method call stack). If a series of method calls occurs, the successive return addresses are pushed onto the stack in last-in, first-out order so that each method can return to its caller.
The program execution stack also contains the memory for the local variables used in each invocation of a method during a program's execution. This data, stored as a portion of the program execution stack, is known as the activation record or stack frame of the method call. When a method call is made, the activation record for that method call is pushed onto the program execution stack. When the method returns to its caller, the activation record for this method call is popped off the stack and those local variables are no longer known to the program. If a local variable holding a reference to an object is the only variable in the program with a reference to that object, when the activation record containing that local variable is popped off the stack, the object can no longer be accessed by the program and will eventually be deleted from memory by the JVM during "garbage collection." We'll discuss garbage collection in Section 8.10.
Of course, the amount of memory in a computer is finite, so only a certain amount of memory can be used to store activation records on the program execution stack. If more method calls occur than can have their activation records stored on the program execution stack, an error known as a stack overflow occurs.
[Page 241 (continued)]
6.7. Argument Promotion and Casting
Another important feature of method calls is argument promotionconverting an argument's value to the type that the method expects to receive in its corresponding parameter. For example, a program can call Math method sqrt with an integer argument even though the method expects to receive a double argument (but, as we will soon see, not vice versa). The statement
[Page 242]
System.out.println( Math.sqrt( 4 ) );
correctly evaluates Math.sqrt( 4 ) and prints the value 2.0. The method declaration's parameter list causes Java to convert the int value 4 to the double value 4.0 before passing the value to sqrt. Attempting these conversions may lead to compilation errors if Java's promotion rules are not satisfied. The promotion rules specify which conversions are allowed, that is, which conversions can be performed without losing data. In the sqrt example above, an int is converted to a double without changing its value. However, converting a double to an int TRuncates the fractional part of the double valuethus, part of the value is lost. Converting large integer types to small integer types (e.g., long to int) may also result in changed values.
The promotion rules apply to expressions containing values of two or more primitive types and to primitive-type values passed as arguments to methods. Each value is promoted to the "highest" type in the expression. (Actually, the expression uses a temporary copy of each valuethe types of the original values remain unchanged.) Figure 6.5 lists the primitive types and the types to which each can be promoted. Note that the valid promotions for a given type are always to a type higher in the table. For example, an int can be promoted to the higher types long, float and double.
|
Figure 6.5. Promotions allowed for primitive types. |
Type |
Valid promotions |
|
|
double |
None |
float |
double |
long |
float or double |
int |
long, float or double |
char |
int, long, float or double |
short |
int, long, float or double (but not char) |
byte |
short, int, long, float or double (but not char) |
boolean |
None (boolean values are not considered to be numbers in Java) |
|
|
Converting values to types lower in the table of Fig. 6.5 will result in different values if the lower type cannot represent the value of the higher type (e.g., the int value 2000000 cannot be represented as a short, and any floating-point number with digits after its decimal point cannot be represented in an integer type such as long, int or short). Therefore, in cases where information may be lost due to conversion, the Java compiler requires the programmer to use a cast operator (introduced in Section 4.9) to explicitly force the conversion to occurotherwise a compilation error occurs. This enables the programmer to "take control" from the compiler. The programmer essentially says, "I know this conversion might cause loss of information, but for my purposes here, that's fine." Suppose method square calculates the square of an integer and thus requires an int argument. To call square with a
double argument named doubleValue, we would be required to write the method call as square( (int)
doubleValue ). This method call explicitly casts (converts) the value of doubleValue to an integer for use in method square. Thus, if doubleValue's value is 4.5, the method receives the value 4 and returns
16, not 20.25.
[Page 243]
Common Programming Error 6.9
Converting a primitive-type value to another primitive type may change the value if the new type is not a valid promotion. For example, converting a floating-point value to an integral value may introduce truncation errors (loss of the fractional part) into the result.
[Page 243 (continued)]
6.8. Java API Packages
As we have seen, Java contains many predefined classes that are grouped into categories of related classes called packages. Together, we refer to these packages as the Java Application Programming Interface (Java API), or the Java class library.
Throughout the text, import declarations specify the classes required to compile a Java program. For example, a program includes the declaration
import java.util.Scanner;
to specify that the program uses class Scanner from the java.util package. This allows programmers to use the simple class name Scanner, rather than the fully qualified class name java.util.Scanner, in the code. A great strength of Java is the large number of classes in the packages of the Java API. Some key Java API packages are described in Fig. 6.6, which represents only a small portion of the reusable components in the Java API. When learning Java, spend a portion of your time browsing the packages and classes in the Java API documentation (java.sun.com/j2se/5.0/docs/api/index.html).
Figure 6.6. Java API packages (a subset).
|
[Page 244] |
Package |
Description |
|
|
java.applet |
The Java Applet Package contains a class and several interfaces required |
|
to create Java appletsprograms that execute in Web browsers. (Applets |
|
are discussed in Chapter 20, Introduction to Java Applets; interfaces are |
|
discussed in Chapter 10, Object-Oriented Programming: Polymorphism.) |
java.awt |
The Java Abstract Window Toolkit Package contains the classes and |
|
interfaces required to create and manipulate GUIs in Java 1.0 and 1.1. In |
|
current versions of Java, the Swing GUI components of the javax.swing |
|
packages are often used instead. (Some elements of the java.awt |
|
package are discussed in Chapter 11, GUI Components: Part 1, Chapter |
|
12, Graphics and Java2D, and Chapter 22, GUI Components: Part 2.) |
java.awt.event |
The Java Abstract Window Toolkit Event Package contains classes and |
|
interfaces that enable event handling for GUI components in both the |
|
java.awt and javax.swing packages. (You will learn more about this |
|
package in Chapter 11, GUI Components: Part 1 and Chapter 22, GUI |
|
Components: Part 2.) |
java.io |
The Java Input/Output Package contains classes and interfaces that |
|
enable programs to input and output data. (You will learn more about this |
|
package in Chapter 14, Files and Streams.) |
java.lang |
The Java Language Package contains classes and interfaces (discussed |
|
throughout this text) that are required by many Java programs. This |
|
package is imported by the compiler into all programs, so the programmer |
|
does not need to do so. |
java.net |
The Java Networking Package contains classes and interfaces that |
|
enable programs to communicate via computer networks like the Internet. |
|
(You will learn more about this in Chapter 24, Networking.) |
java.text |
The Java Text Package contains classes and interfaces that enable |
|
programs to manipulate numbers, dates, characters and strings. The |
|
package provides internationalization capabilities that enable a program to |
|
be customized to a specific locale (e.g., a program may display strings in |
|
different languages, based on the user's country). |
java.util |
The Java Utilities Package contains utility classes and interfaces that |
|
enable such actions as date and time manipulations, random-number |
|
processing (class Random), the storing and processing of large amounts of |
|
data and the breaking of strings into smaller pieces called tokens (class |
|
StringTokenizer). (You will learn more about the features of this |
|
package in Chapter 19, Collections.) |
javax.swing |
The Java Swing GUI Components Package contains classes and |
|
interfaces for Java's Swing GUI components that provide support for |
|
portable GUIs. (You will learn more about this package in Chapter 11, GUI |
|
Components: Part 1 and Chapter 22, GUI Components: Part 2.) |
javax.swing.event |
The Java Swing Event Package contains classes and interfaces that |
|
enable event handling (e.g., responding to button clicks) for GUI |
|
components in package javax.swing. (You will learn more about this |
|
package in Chapter 11, GUI Components: Part 1 and Chapter 22, GUI |
|
Components: Part 2.) |
|
|
The set of packages available in the J2SE Development Kit (JDK) is quite large. In addition to the packages summarized in Fig. 6.6, the JDK includes packages for complex graphics, advanced graphical user interfaces, printing, advanced networking, security, database processing, multimedia, accessibility (for people with disabilities) and many other capabilities. For an overview of the packages in the JDK 5.0, visit
java.sun.com/j2se/5.0/docs/api/overview-summary.html
Many other packages are also available for download at java.sun.com.
[Page 244]
You can locate additional information about a predefined Java class's methods in the Java API documentation at java.sun.com/j2se/5.0/docs/api/index.html. When you visit this site, click the Index link to see an alphabetical listing of all the classes and methods in the Java API. Locate the class name and click its link to see the online description of the class. Click the METHOD link to see a table of the class's methods. Each static method will be listed with the word "static" preceding the method's return type. For a more detailed overview of navigating the Java API documentation, see Appendix G, Using the Java API Documentation.
[Page 245]
Good Programming Practice 6.2
The online Java API documentation is easy to search and provides many details about each class. As you learn a class in this book, you should get in the habit of looking at the class in the online documentation for additional information.
and displays the value of each roll. We begin by using nextInt to produce random values in the range
05, as follows:
face = randomNumbers.nextInt( 6 );
The argument 6called the scaling factorrepresents the number of unique values that nextInt should produce (in this case six0, 1, 2, 3, 4 and 5). This manipulation is called scaling the range of values produced by Random method nextInt.
A six-sided die has the numbers 16 on its faces, not 05. So we shift the range of numbers produced by adding a shifting valuein this case 1to our previous result, as in
face = 1 + randomNumbers.nextInt( 6 );
The shifting value (1) specifies the first value in the desired set of random integers. The preceding statement assigns face a random integer in the range 16.
Figure 6.7 shows two sample outputs which confirm that the results of the preceding calculation are integers in the range 16, and that each run of the program can produce a different sequence of random numbers. Line 3 imports class Random from the java.util package. Line 9 creates the Random object randomNumbers to produce random values. Line 16 executes 20 times in a loop to roll the die. The if statement (lines 2122) in the loop starts a new line of output after every five numbers, so the results can be presented on multiple lines.
Figure 6.7. Shifted and scaled random integers.
(This item is displayed on page 247 in the print version)
1 |
// |
Fig. 6. |
7: RandomIntegers.java |
2 |
// |
Shifted |
and scaled random integers. |
3 |
import java.util.Random; // program uses class Random |
||
4 |
|
|
|
5public class RandomIntegers
6{
7public static void main( String args[] )
8{
9Random randomNumbers = new Random(); // random number generator
10int face; // stores each random integer generated
11
12 // loop 20 times
13 for ( int counter = 1; counter <= 20; counter++ )
14{
15// pick random integer from 1 to 6
16face = 1 + randomNumbers.nextInt( 6 );
18 |
System.out.printf( "%d |
", |
face |
); // |
display |
generated value |
||||
19 |
|
|
|
|
|
|
|
|
|
|
20 |
// |
if |
counter |
is |
divisible |
by 5, |
start |
a new |
line of output |
|
21 |
if |
( |
counter |
% 5 |
== 0 |
) |
|
|
|
|
22 |
|
System.out |
.println(); |
|
|
|
|
|||
23} // end for
24} // end main
25} // end class RandomIntegers
1 |
5 |
3 |
6 |
2 |
5 |
2 |
6 |
5 |
2 |
4 |
4 |
4 |
2 |
6 |
3 |
1 |
6 |
2 |
2 |
|
|
|
|
|
6 |
5 |
4 |
2 |
6 |
1 |
2 |
5 |
1 |
3 |
6 |
3 |
2 |
2 |
1 |
6 |
4 |
2 |
6 |
4 |
|
|
|
|
|
Rolling a Six-Sided Die 6000 Times
To show that the numbers produced by nextInt occur with approximately equal likelihood, let us simulate 6000 rolls of a die with the application in Fig. 6.8. Each integer from 1 to 6 should appear approximately 1000 times.
Figure 6.8. Rolling a six-sided die 6000 times.
(This item is displayed on pages 247 - 249 in the print version)
1 |
// |
Fig. 6.8: RollDie.java |
2 |
// |
Roll a six-sided die 6000 times. |
3 |
import java.util.Random; |
|
4 |
|
|
5public class RollDie
6{
7public static void main( String args[] )
8{
9Random randomNumbers = new Random(); // random number generator
11int frequency1 = 0; // maintains count of 1s rolled
12int frequency2 = 0; // count of 2s rolled
13int frequency3 = 0; // count of 3s rolled
14int frequency4 = 0; // count of 4s rolled
15int frequency5 = 0; // count of 5s rolled
16int frequency6 = 0; // count of 6s rolled
18int face; // stores most recently rolled value
20// summarize results of 6000 rolls of a die
21 |
for ( int |
roll |
= 1; roll <= 6000; roll++ |
) |
22 |
{ |
|
|
|
23 |
face = |
1 + |
randomNumbers.nextInt( 6 ); |
// number from 1 to 6 |
24 |
|
|
|
|
25// determine roll value 1-6 and increment appropriate counter
26switch ( face )
27{
28 |
case |
1: |
29 |
++frequency1; // increment the 1s counter |
|
30 |
break; |
|
31 |
case |
2: |
32 |
++frequency2; // increment the 2s counter |
|
33 |
break; |
|
34 |
case |
3: |
35 |
++frequency3; // increment the 3s counter |
|
36 |
break; |
|
37 |
case |
4: |
38 |
++frequency4; // increment the 4s counter |
|
39 |
break; |
|
40 |
case |
5: |
41 |
++frequency5; // increment the 5s counter |
|
42 |
break; |
|
43 |
case |
6: |
44 |
++frequency6; // increment the 6s counter |
|
45 |
break; // optional at end of switch |
|
46} // end switch
47} // end for
48
49System.out.println( "Face\tFrequency" ); // output headers
50System.out.printf( "1\t%d\n2\t%d\n3\t%d\n4\t%d\n5\t%d\n6\t%d\n",
51frequency1, frequency2, frequency3, frequency4,
52frequency5, frequency6 );
53} // end main
54} // end class RollDie
Face Frequency
1982
21001
31015
41005
51009
6988
Face Frequency
11029
2994
31017
41007
5972
6981
As the two sample outputs show, scaling and shifting the values produced by method nextInt enables the program to realistically simulate rolling a six-sided die. The application uses nested control statements (the switch is nested inside the for) to determine the number of times each side of the die occurred. The for statement (lines 2147) iterates 6000 times. During each iteration, line 23 produces a random value from 1 to 6. That value is then used as the controlling expression (line 26) of the switch statement (lines 2646). Based on the face value, the switch statement increments one of the six counter variables during each iteration of the loop. (When we study arrays in Chapter 7, we will show an elegant way to replace the entire switch statement in this program with a single statement!) Note that the switch statement has no default case because we have a case for every possible die value that the expression in line 23 could produce. Run the program several times, and observe the results. As you will see, every time you execute this program, it produces different results.
[Page 249]
6.9.1. Generalized Scaling and Shifting of Random Numbers
Previously, we demonstrated the statement
face = 1 + randomNumbers.nextInt( 6 );
which simulates the rolling of a six-sided die. This statement always assigns to variable face an integer in the range 1 < face < 6. The width of this range (i.e., the number of consecutive integers in the range) is 6, and the starting number in the range is 1. Referring to the preceding statement, we see that the width of the range is determined by the number 6 that is passed as an argument to Random
