Chapter 7. Java Statements

Java Statements

Statements are the way we get things done in a program. Statements live in methods and in blocks. Any statement may be prefixed by a label, as shown here:

months: for(int m = 1; m <= 12; m++) { ... 

The general syntax for a statement is this:

optIdentifier: statement 

Java doesn’t have a goto statement. If a label appears, it is either just empty documentation (rare—use a comment instead), or it is used to break out of certain enclosing statements in a clean way.

Statements in Java can be conveniently divided into several groups:

  • “Organizing” statements

  • Expression statements

  • Selection, Iteration, and Transfer statements

  • Guarding statements

First we will describe all but the guarding statements. We will then introduce the topic of exceptions, which provides the context in which to talk about guarding statements.

An entirely new kind of statement was introduced with JDK 1.4: the assert statement. We will describe the assert statement after the material on exceptions. Exceptions and asserts are two ways of dealing with unexpected and unwanted error situations. Exceptions give you a chance to recover from the error and continue program execution. Assert statements provide a way to stop a program dead when it hits some kind of error. You can configure at runtime whether you want this “stop on error” behavior or not.

Most of Java’s statements are pretty much identical to their counterparts in other languages and will be readily recognizable to any programmer. Accordingly, we can limit our discussion to showing the general form of each statement and noting any special rules or “gotchas” that apply.

“Organizing” Statements

There are two statements whose purpose is primarily to organize your code. It is convenient to group them in with the other statements because the Java Language Specification says they are regular statements. The two organizing statements (my term) are the block statement and the empty statement.

A block statement is a pair of curly braces, “ { ... } ”, that contains zero or more statements and local variable declarations in any order. Wherever you can legally put one statement, you can put a block statement. We’ve seen block statements many times. Use them to put a whole group of statements in an “if” branch or to declare a variable that will be used just within the block. A block statement looks like this:

{
     Window w = new WarningWindow(f); 
     w.setSize(200,100); 
     w.setVisible(true); 
} 

An empty statement is simply a semicolon by itself. The empty statement does nothing. Wherever you can legally put a statement, you can put an empty statement. In the example below, we are saying “if the condition is true, do nothing; otherwise, invoke the method.”

boolean noRecordsLeft = ... 
if (noRecordsLeft) 
     ; // empty statement 
else {
          alertTheMedia(); ... 

The code is written this way for a reason: rewriting it so the “else” part becomes the “then” part causes the condition to become a double negative (“not no records left”). It’s usual to comment the empty statement and put it on a line by itself.

Expression Statements

Certain kinds of expression are counted as statements. You write the expression, put a semicolon after it, and voila, it’s an expression statement. In particular, an assignment, method invocation, the instantiation of a class, and pre-increment, post-increment, and decrement are all expressions that can be statements.

new WarningWindow(f); // instance creation 
w.setSize(200,100);   // method invocation 
i++;                 // post increment 
a = b;               // assignment 

An expression statement is executed by evaluating the expression. Any ultimate result after an assignment has taken place is discarded. You usually save a reference to something that you create an instance of. For example, you have:

foo = new WarningWindow(f); // instance creation 

not:

new WarningWindow(f); // instance, but no ref saved 

However, there are certain classes that you can instantiate for which you don’t necessarily need to save a reference, like Threads and inner classes. So, you might see this either way.

Selection Statements

The general form of the “if” statement looks like this:

if (Expression) Statement  [ else  Statement ] 
Selection Statements

Statement Notes

Statement Notes

Statement Notes
Statement Notes

The general form of the “switch” statement is impossible to show in any meaningful form in a syntax diagram with less than about two dozen production rules. That tells you something about how badly designed the statement is right there. If you look at Kernighan and Ritchie’s C book, The C Programming Language, you’ll note that even they were not up to the task of showing the syntax in any better way than this:

switch ( Expression ) Statement

Neither has any other C book since. Ignoring syntax diagrams, the switch statement is a poor man’s “case” statement. It causes control to be transferred to one of several statements depending on the value of the Expression, which must be of type char, byte, short, or int. It generally looks like this:

switch (Expression) { 
   case constant_1 : Statement; break; 
   case constant_5 : 
   case constant_3 : Statement; break; 
        ... 
   case constant_n : Statement; break; 
         default : Statement; break; 
    } 
    

Statement Notes

Statement Notes

Statement Notes

Statement Notes

Statement Notes

Statement Notes

JDK 1.4 has a compiler option to check for and warn about switch fall-through. Use this command line:

javac -Xswitchcheck filename.java 

Iteration Statements

Iteration Statements

The “for” statement looks like this:

for (Initial; Test; Increment) Statement 

Statement Notes

Statement Notes
for( i=0; i<100; i++ ) { ... 

A typical infinite loop will look like:

for (;;) 

Statement Notes
for( int i=0; i<100; i++ ) { ... 

This is a nice feature created for the convenience of the programmer.

Statement Notes
for(i=0,j=0; i<100; i++, j+=2 ) { ... 
Statement Notes

The “while” statement looks like this:

while ( Expression ) Statement 

Statement Notes

Statement Notes

Statement Notes
Statement Notes

The “do while” statement looks like this:

do Statement while ( Expression ) ; 

Statement Notes

Statement Notes

Statement Notes
Statement Notes

There may be “continue” statements in a loop. These look like:

continue; continue Identifier ; 

Continue statements occur only in loops. When a continue statement is executed, it causes the flow of control to pass to the next iteration of the loop. It’s as though you say, “Well, that’s it for iteration N; increment the loop variable (if this is a “for” loop), do the test, and continue with iteration N+1.”

The “continue Identifier” form is used when you have nested loops, and you want to break out of an inner one altogether and start with the next iteration of the outer loop.

The loop which you want to continue is labeled at its “for” statement with the matching identifier, and it does the same trick. Namely, that’s it for iteration N of the labeled loop; increment the loop variable (if this is a “for” loop), do the test, and continue with iteration N+1. You continue with the next iteration, even though the label is (confusingly) at the beginning, rather than labeling, say, the end of the loop. Here is an example “continue” statement:

Statement Notes

There may be “break” statements in a loop or switch. These look like this:

Statement Notes
break; 

Or they look like this:

break identifier; 

Break is a more dramatic version of continue. Break with no identifier causes control to pass to just after the end of the enclosing “for, do, while,” or “switch” statement. The loop or switch statement is “broken out of.” Break with no identifier can appear only in a statement by virtue of the whole thing being nested in an iteration or switch statement. You will break to the end of the iteration or switch, not the statement it’s immediately nested in.

Statement Notes

If an identifier is included, it must be an identifier matching the label on some enclosing statement. The enclosing statement can be any kind of statement, not just an iterative or switch statement. In other words, it’s OK to break out of any kind of enclosing block as long as you explicitly indicate it with a label. In practice, it’s almost always a loop or switch that you break out of, not an if or block. Again, there is the slightly confusing feature that statements are labeled at their beginning, but “break” causes you to jump to their end. Here is an example:

Statement Notes

Transfer of Control Statements

Transfer of Control Statements

A “return” statement looks like this:

          return; 
return  Expression; 

Statement Notes

Statement Notes

Statement Notes

There is a reserved word “goto” in Java, but there is no goto statement. The designers grabbed the keyword to ensure that no one uses it as a variable name in case it later turns out to be convenient to support (perhaps for automatically generated code).

Exceptions

At several points in the preceding text I mentioned exceptions, only to defer discussion. This is where I deliver on the promise of describing the purpose and use of exceptions following this order:

  1. The purpose of exceptions.

  2. How to cause an exception (implicitly and explicitly).

  3. How to handle (“catch”) an exception within the method where it was thrown.

  4. Handling groups of related exceptions.

  5. How the exception propagates if not handled in the method where it was thrown.

  6. How and why methods declare the exceptions that can propagate out of them.

  7. Fancy exception stuff.

The Purpose of Exceptions

Exceptions are for changing the flow of control when some important or unexpected event, usually an error, has occurred. They divert processing to a part of the program that can try to cope with the error, or at least die gracefully. The error can be any condition at all, ranging from “unable to open a file” to “array subscript out of range” to “no memory left to allocate” to “division by zero.” Java exceptions are adapted from C++, which itself borrowed them from the research language ML. Like C and C++, ML (Meta Language) was developed at Bell Labs. Java exception terminology is presented in Table 7-1.

Table 7-1. Exception Terminology of Java

Note

Java

Some Other Languages

An error condition that happens at runtime

Exception

Exception

Causing an exception to occur

Throwing

Raising

Capturing an exception that has just occurred and executing statements to resolve it in some way

Catching

Handling

The block that does this

Catch clause

Handler

The sequence of method calls that brought control to the point where the exception happened

Stack trace

Call chain

An exception can be set in motion explicitly with the “throw” statement, or implicitly by carrying out some illegal or invalid action. The exception then diverts the normal flow of control (like a goto statement).

If the programmer has made provision, control will transfer to a section of the program that can recover from the error. That section can be in the same method, in the method that called the one where the exception occurred, or in the one that called that method. If no catch clause is found there, the thrown object continues up the stack of calls that were made at runtime. You might want to refresh your memory on how the stack is used to keep track of method invocations by looking at the diagram that was presented back in Chapter 3.

If the thrown object gets to the top where your program execution started, and no handler for the exception has yet been found, then program execution will cease with an explanatory message.

Therefore, the places that you can jump to are strictly limited. You must even explicitly stipulate, “In this block, I will listen for and deal with this type of exception.”

How to Cause an Exception (Implicitly and Explicitly)

Exceptions are caused in one of two ways: the program does something illegal (common case), or the program explicitly generates an exception by executing the throw statement (less common case). The throw statement has this general form:

throw   ExceptionObject; 

The ExceptionObject is an object of a class that extends the class java.lang.Exception.

Triggering an Exception

Here is a simple program that causes a “division by zero” exception:

class melon {
   public static void main(String[] a) {
      int i=1, j=0, k; 

      k = i/j;    // Causes division-by-zero exception 
   } 
} 

Compiling and running this program gives this result:

> javac melon.java 
> java melon 
     java.lang.ArithmeticException: / by zero 
           at melon.main(melon.java:5) 

There are a certain number of predefined exceptions, like ArithmeticException, known as the runtime exceptions. Actually, since all exceptions are runtime events, a better name would be the “irrecoverable” exceptions. They mean “runtime” in the sense of “thrown by the runtime library code, not your code.”

Runtime exceptions contrast with the user-defined exceptions which are generally held to be less severe, and in some instances can be recovered from. If a filename cannot be opened, prompt the user to enter a new name. If a data structure is found to be full, overwrite some element that is no longer needed. You don’t have to make provisions for catching runtime exceptions. You do have to make provisions for catching other exception types

User-Defined Exceptions. Here is an example of how to create your own exception class by extending System.exception:

class OutofGas extends Exception {} 

class banana {
        : 

      if (fuel < 0.1) throw   new OutofGas(); 
} 

Any method that throws a user-defined exception must also either catch it or declare it as part of the method interface. What, you may ask, is the point of throwing an exception if you are going to catch it in the same method? The answer is that exceptions don’t reduce the amount of work you have to do to handle errors. Their advantage is they let you collect it all in well-localized places in your program so you don’t obscure the main flow of control with zillions of checks of return values.

Some Predefined Exceptions and How They Extend More Basic Classes

How to Handle (“Catch”) an Exception Within the Method Where It Was Thrown

Of the types of statements we defined at this chapter’s opening, here is where guarding statements fit in.

Here is the general form of how to catch an exception:

How to Handle (“Catch”) an Exception Within the Method Where It Was Thrown

The “try” statement says, “Try these statements and see if you get an exception.” The “try” statement must be followed by at least one “catch” clause or the “finally” clause.

Each catch says, “I will handle any exception that matches my argument.” Matching an argument means that the thrown exception could legally be assigned to the argument exception. There can be several successive catches, each looking for a different exception. Don’t try to catch all exceptions with one clause, like this:

catch (Exception e) { ... 

That is way too general to be of use and you might catch more than you expected. You are better off letting the exception propagate to the top and give you a reasonable error message.

The “finally” block, if present, is a “last chance to clean up” block. It is always executed—even if something in one of the other blocks did a “return!” The “finally” block is executed whether an exception occurred or not and whether it was caught or not. It is executed after the catch block, if present, and, regardless of the path taken, through the try block and the catch block.

The “finally” block can be useful in the complete absence of any exceptions. It is a piece of code that is executed irrespective of what happens in the “try” block. There may be numerous paths through a large and complicated “try” block. The “finally” block can contain the housekeeping tasks that must always be done (counts updated, locks released, and so on) when finishing this piece of code.

Here is an example of an exception guarding statement in full adapted from the window toolkit code:

public void printComponents(Graphics g) {
     // ... some code omitted ... 
     Graphics cg = g.create(); 
     try {
          cg.clipRect(i.left, i.top, vs.width, vs.height); 
          cg.translate(p.x, p.y); 
          c.printAll(cg); 
     } finally {
          cg.dispose(); 
     } 
} 

The method prints components in a scrolling window. It puts a pixel representation of the components onto g, the Graphics context. Graphics contexts are an operating system concept, not a Java concept.The finally clause was designed for recycling (releasing) resources like this.

After the whole try ... catch ... finally series of blocks are executed, if nothing else was done to divert it, execution continues after the last catch or finally (whichever is present). The kinds of things that could make execution divert to elsewhere are the regular things: a continue, break, return, or the raising of a different exception. If a “finally” clause also has a transfer of control statement, then that is the one that is obeyed.

Handling Groups of Related Exceptions

We mentioned before that “matching an argument” means that the thrown exception can be assigned legally to the argument exception. This permits a subtle refinement. It allows a handler to catch any of several related exception objects with common parentage. Look at this example:

class Grumpy extends Exception {} 
class TooHot   extends Grumpy {} 
class TooTired extends Grumpy {} 
class TooCross extends Grumpy {} 
class TooCold  extends Grumpy {} 

   . 
   : 

      try {
        if ( temp > 40 ) throw (new TooHot() ); 
        if ( sleep < 8 ) throw (new TooTired() ); 
      } 
      catch (Grumpy g) {
           if (g instanceof TooHot) 
              {System.out.println("caught too hot!"); return;} 
           if (g instanceof TooTired) 
              {System.out.println("caught too tired!"); return;} 
      } 
      finally {System.out.println("in the finally clause.");} 
   } 

The catch clauses are checked in the order in which they appear in the program. If there is a match, then the block is executed. The instanceof operator can be used to learn the exact identity of the exception.

How the Exception Propagates If Not Handled in the Method Where It Was Thrown

If none of the catch clauses match the exception that has been thrown, then the finally clause is executed (if there is one). At this point (no handler for this exception), what happens is the same as if the statement that threw the exception was not nested in a try statement at all. The flow of control abruptly leaves this method, and a premature return is done to the method that called this one. If that call was in the scope of a try statement, then we look for a matching exception again, and so on.

Figure 7-1 shows what happens when an exception is not dealt within the routine where it occurs. The runtime system looks for a “try . . . catch” block further up the call chain, enclosing the method call that brought us here. If the exception propagates all the way to the top of the call stack without finding a matching exception handler, then execution ceases with a message. You can think of this as

The result of an exception not dealt within the occurring routine.

Figure 7-1. The result of an exception not dealt within the occurring routine.

Java setting up a default catch block for you around the program entry point that just prints an error message and quits.

There is no overhead to putting some statements in a “try” statement. The only overhead comes when an exception occurs.

How and Why Methods Declare the Exceptions That Can Propagate Out of Them

Earlier we mentioned that a method must either catch the exceptions that it throws or declare it along with its signature, [1] meaning it must announce the exception to the outside world. This is so that anyone who writes a call to that method is alerted to the fact that an exception might come back instead of a normal return.

This allows the programmer calling that method to make the choice between handling the exception or allowing it to propagate further up the call stack. Here is the general form of how a method declares the exceptions that might be propagated out of it:

modifiers_and_returntype name (params)  throws e1, e2, e3  { } 

The names e1 through e3 must be exception or error names (that is, any type that is assignable to the predefined type Throwable). Note that just as a method declaration specifies the return type, it specifies the exception type that can be thrown, rather than an exception object.

An example, taken from the Java I/O system, follows:

 byte readByte() throws IOException; 
short readShort() throws IOException; 
 char readChar() throws IOException; 

The interesting thing to note here is that the routine to read a char can return a char—not the int that is required in C. C requires an int to be returned so that it can pass back any of the possible values for a char, plus an extra value (traditionally –1) to signify that the end of file (EOF) was reached. Some of the Java routines just throw an exception when the EOF is hit. Out-of-band-signaling can be effective in keeping your code well organized. The EOF exception is a subclass of the IOException, so the technique suggested above for handling groups of related exceptions can be applied.

The rules for how much and what must match when one method that throws an exception overrides another work in the obvious way. Namely, if you never do this, you will never obviously be bothered by it. Well, OK, another way to think about it is to consider the exception as an extra parameter that must be assignment-compatible with the exception in the class being overridden.

Fancy Exception Stuff

When you create a new exception by subclassing an existing exception class, you have the chance to associate a message string with it. The message string can be retrieved by a method. Usually, the message string will be some kind of message that helps resolve the problem or suggests an alternative action.

class OutofGas extends Exception {
     OutofGas(String s) {super(s);}  // constructor 
} 

    ... 
// in use, it may look like this 
try {
        if (j<1) throw  new OutofGas("try the reserve tank"); 
      } 
catch ( OutofGas o) {
         System.out.println( o.getMessage() ); 
      } 
   ... 

//At runtime, this message will appear: 
  try the reserve tank 

Another method that is inherited from the superclass Throwable is “printStackTrace().” Invoking this method on an exception will cause the call chain at the point where the exception was thrown (not where it is being handled) to be printed out. For example:

// catching an exception in a calling method 

class test {
   static int myArray[] = {0,1,2,3,4}; 

   public static void main(String[] a) {
      try {
          bob(); 
      } catch (Exception e) {
          System.out.println("caught exception in main()"); 
          e.printStackTrace(); 
      } 
   } 

   static void bob() {

      try {
        myArray[-1] = 4; //obvious out of bounds exception 
      } 
      catch (NullPointerException e) {
         System.out.println("caught a different exception"); 
      } 

   } 
} 

At runtime it will look like this:

caught exception in main() 
java.lang.ArrayIndexOutOfBoundsException: -1 
     at test.bob(test5p.java:19) 
     at test.main(test5p.java:9) 

Summary of Exceptions

  • Their purpose is to allow safer programming by providing a distinct path to deal with errors.

  • Use them. They are a useful tool for organized error-handling.

  • The main use of exceptions is getting a decent error message explaining what failed, where, and why. It’s a bit much to expect recovery. Graceful degradation is often the most you can obtain.

We will next review the assert statement, then conclude this chapter with a look at our featured class, Integer.

The Assert Statement

Introduced with Java 1.4, the assert statement helps to debug code and also troubleshoot applications after they have been deployed. You write an assert statement stating some very important condition that you believe will always be true at this point in your program. If the condition is not true, the assertion throws an Error (an exception that is not intended to be caught). You can do that already in Java. The part that is new is that assertion statements let you choose at runtime whether the assertion checking is done or not. There are two key pieces to using asserts.

First, you sprinkle assert statements at a few critical places in your program. For example, after calculating a checksum, you could assert that the calculated value equals the stored checksum. You only use assert statements for fatal errors—something has gone so wrong that the only thing to do is stop before more data disappears or whatever.

The second half of assert statements is that you control whether the assert statements are in effect, or not, at runtime. There is a command line option to the JVM that enables or disables whether the assertions are executed, and this can be applied to individual packages and even classes.

The usual scenario is that you keep the assert statements on during debugging and testing. After testing, when you are confident that the application works correctly, you no longer need to do all that checking. So you disable the assert statements, but leave them compiled in the source code. If the application later hits a problem, you can enable asserts and rerun the failure case to see if any assertions are untrue. This can be done in the field or over telephone support.

An “assert” statement looks like either of these alternatives:

assert booleanExpression; 
assert booleanExpression : Expression2; 

If the boolean is not true, a java.lang.AssertionError is thrown. The second form of the statement allows you to write an expression that will be passed to the constructor of the AssertionError. The expression is supposed to resolve to a message about what went wrong. You should just pass a String. An expression of other types (such as int) is allowed to accommodate any nimrods who want to number their error messages or label them with a character instead of using self-identifying strings.

Here’s a complete example of the use, compilation, and run of a program with assert.

public class asst {
    public static void main(String[] args) {

        int a = Integer.parseInt(args[0]); 
        System.out.println("a = "+a); 

        assert a>0 : "argument too negative"; 

        // if a OK, go on with program 
    } 
} 

That assert statement is equivalent to this line of code:

if (a<=0) throw new java.lang.AssertionError(“argument too negative”); 

except that you have the additional ability to configure whether such statements should be executed or not.

For backwards compatibility, the compiler will only accept code containing assertions when you use the “-source 1.4” command line option. So people who have tried to create their own version of assertions in the past and used the identifier “assert” will not have their code broken. Compile as follows:

javac -source 1.4 asst.java 

By default, assertions are disabled. Here is a regular program execution where no error occurs, even though we provided a command line argument that triggers the problem.

java asst -3 

To turn on the assertion checking for a particular run, use the “-ea” (enable assertions) option:

java -ea asst -3 
Exception in thread “main” java.lang.AssertionError: argument too negative 
at asst.main(asst.java:1) 

There is also a syntax for enabling just one package tree or a class, but you might as well do everything. A separate switch is provided to enable asserts in the system classes (i.e., to set the assertion status for java.* packages to true).

java  -esa  MyProgram 

If you ever get a runtime error in the JVM, such as a core dump, try running with the “-esa” option and including the output in your bug report to Sun. You can search and file bug reports on the JDK at the Java Developer Connection site developer.java.sun.com.

There are a couple of caveats with assertion statements. First, you must test your code both ways, with assertions enabled and disabled. Second, you must avoid side effects in the assertion expression. Otherwise, program behavior would be different depending on whether you run with assertions on or off. A “side effect” is a change to the value of some variable, as part of evaluating the expression, e.g.,

boolean noMoreData = true; 
boolean checkingMethod() {
    noMoreData = false; 
    return noMoreData; 
} 
assert checkingMethod(); 

Now, variable noMoreData has a different value from this point in the program, depending on whether assertions are on or off! Avoid this.

Finally, assertions are supposed to be unrecoverable errors, so do not try to repair the problem and continue. That is what exceptions are for. Assert statements provide the ability to check for significant errors and to make the checking configurable at runtime.

The Class Integer. In the previous chapter we referred to the class java.lang.Integer as a class wrapper for the primitive type int. There is a similar class wrapper for all the primitive types boolean, char, int, long, etc., as shown in Table 7-2.

Table 7-2. Primitive Types and Their Corresponding Classes

Primitive Type

Corresponding Class (in src/java/lang)

boolean

Boolean

char

Character

byte

Byte

short

Short

int

Integer

long

Long

float

Float

double

Double

void

Void

There are three purposes for having a class version of each basic type:

  • To provide an object wrapper for data values. A wrapper is useful because most of Java’s utility classes require the use of Objects. Since variables of the primitive types are not objects in Java, it’s convenient to provide a simple way to “promote” them when needed.

  • To support some useful constants and methods associated with the type, like range boundaries and conversion to and from String.

  • To give primitive types the same kind of introspection as non-primitive types. “Introspection” is a Java term for looking at the characteristics of a Java object. It allows you to write component software, debuggers, class inspectors, and other systems programs in Java.

Void (no return value from a method) isn’t a type, but it was included for completeness. Here is an example of moving an int to an Integer object and back again, using methods from the Integer class:

// changes int to Integer and back 
Integer myIntObj; 
int i=42; 

myIntObj = new Integer(i);  // int to an Integer object 
i = myIntObj.intValue();    // Integer object to an int 

As with Strings, once one of these objects has been created with a given value, that value cannot be changed. You can throw away that object and create a new one, but the object itself doesn’t change its identity once assigned. If you need a class that can hold an int that changes, it is trivial to declare. Here it is:

public class AnyInt { public int i; } 

Here is the declaration of class java.lang.Integer:

public final class java.lang.Integer extends java.lang.Number 
                                   implements java.lang.Comparable {
     public static final int MIN_VALUE = 0x80000000; // -2147483648 
     public static final int MAX_VALUE = 0x7fffffff; // +2147483647 
     public static final java.lang.Class TYPE; // synonym for Integer.class 
// constructors 
     public java.lang.Integer(int); 
     public java.lang.Integer(java.lang.String) throws 
                              java.lang.NumberFormatException; 
// integer/string conversion 
     public static int parseInt(java.lang.String) throws 
                                        NumberFormatException; 
     public static int parseInt(java.lang.String, int) throws 
                                        NumberFormatException; 
     public static java.lang.String toBinaryString(int); 
     public static java.lang.String toHexString(int); 
     public static java.lang.String toOctalString(int); 
     public java.lang.String toString(); 
     public static java.lang.String toString(int); 
     public static java.lang.String toString(int, int); 
     public static java.lang.Integer valueOf(java.lang.String) 
                              throws java.lang.NumberFormatException; 
     public static java.lang.Integer valueOf(java.lang.String, int) 
                              throws java.lang.NumberFormatException; 
     // converts between Integer values & system properties 
     public static java.lang.Integer getInteger(java.lang.String); 
     public static java.lang.Integer getInteger(java.lang.String, int); 
     public static java.lang.Integer getInteger(java.lang.String, Integer); 
     public static java.lang.Integer decode(java.lang.String) throws 
                              java.lang.NumberFormatException; 
     public int compareTo(java.lang.Integer); 
     public int compareTo(java.lang.Object); 
     public byte byteValue(); 
     public short shortValue(); 
     public int intValue(); 
     public long longValue(); 
     public float floatValue(); 
     public double doubleValue(); 

     public boolean equals(java.lang.Object); 
     public int hashCode(); 
} 

You might be wondering about that “ implements Comparable ” clause at the start of the class. That says, “This class has the methods demanded by the interface whose name is Comparable.” It is the subject of the very next chapter.

Further Reading

There is more information on the assert statement, including a couple of clever idioms, at the Sun site java.sun.com/j2se/1.4/docs/guide/lang/assert.html. One of the idioms is code to prevent a program from running if assertions are turned off.

Exercises

  1. Write the “if” statements that call different methods do0_9(), do10_99(), and do100_999() based on the value of i being in the range 0-9, 10-99, or 100-999. Don’t forget to allow for other values of i, including negative values.

  2. Write a switch statement that corresponds to the if statement in question 1. Which is more compact? Which is easier to read?

  3. Dump out the byte code for the statements in questions 1 and 2. Use “javap -c” to do this. Review the online JVM specification, and write a description of which byte codes each statement is translated to.

  4. Write a method that uses ands, ors, and shifts to reverse the order of bytes in an int. Instead of b1 b2 b3 b4, your routine should rearrange in byte-swapped order to b4 b3 b2 b1.

  5. Write a method that counts the number of “1” bits in an int value. Write another method that counts the number of “1” bits in a long value. Is there any way to share code between the two? (Hint: a long is two ints wide.) Would you do so in practice? Explain why or why not. Then reimplement it using java.math.BigInteger.bitCount().

Some Light Relief—MiniScribe: The Hard Luck Hard Disk

Most readers will know the term “hard disk,” which contrasts with “floppy disk,” but how many people know about MiniScribe’s pioneering efforts in the fields of very hard disks, inventory control, and accounting techniques?

MiniScribe was a successful start-up company based in Longmont, Colorado, that manufactured disk drives. In the late 1980s, Miniscribe ran into problems when IBM unexpectedly cancelled some very big purchasing contracts. The venture capitalists behind MiniScribe, Hambrecht & Quist, brought in turnaround expert Q.T. Wiles to get the company back on track.

Wiles mercilessly drove company executives to meet revenue targets, even as sales fell still further. In desperation, the beleaguered executives turned to outright record falsification. It must have seemed so easy. Over the space of a couple of years they came up with an impressive range of fraudulent techniques for making a failing company have the appearance of prospering.

The Miniscribe executives started off with the easy paper-based deceit, like:

  • Counting raw inventory as finished goods (with a higher value).

  • Anticipating shipments before they were made to customers.

  • Counting imaginary shipments on non-existent ships.

When they were not found out, they graduated to more brazen activities like parading inventory past the accountants twice, so it would be counted twice, and shipping obsolete product to a fake customer called “BW.” “BW” stood for “Big Warehouse” and was a MiniScribe storage building. And so it went, with smaller crimes leading to bigger crimes, just the way your kindergarten teacher warned it would.

Miniscribe employed more than 9,000 people worldwide at the height of its fortunes, so this was no fly-by-night, two-guys-in-a-garage undertaking. This was a fly-by-night, 9,000-guys-in-a-Big-Warehouse undertaking. The companies that supplied Miniscribe were doing less and less business with them and were finding it hard to get paid. One analyst surveyed the entire computer industry and found only one large MiniScribe customer. At the same time, MiniScribe was issuing press releases talking about “record sales.”

The most breathtaking coup, though, was the brick scam. Desperate to show shipments on the books, executives brought in their assistants, spouses, and even children for a crazy weekend of filling disk shipping boxes with house bricks. They also created a special computer program called “Cook book” (these guys were well aware of what they were doing) that facilitated shipping the bricks to good old “BW” and recognizing the “revenue” from that customer. These bricks were surely the ultimate hard drive.

Of course, it all came unglued in the end. On January 1, 1990, MiniScribe announced massive layoffs and filed for bankruptcy. Chief Financial Officer Owen Taranto, the genius who devised the brick shipment plan, was granted immunity for his testimony. The stock went into a precipitous decline, but not before the aptly-named Wiles had unloaded a parcel of it at premium prices. So the people who lost their jobs and the stockholders bore the brunt of all this dishonesty.

There was plenty of blame to go around. After a trial, Cooper & Lybrand, Hambrecht & Quist, and 16 MiniScribe executives were ordered to pay $568 million in restitution to defrauded stockholders. Wiles was sentenced to three years in the Big House. The remains of MiniScribe were bought out by rival Maxtor. The later Maxtor model 8541s looked just like Miniscribe 8541s, so they were still being made, but any resemblance to a brick was long since gone.

You want to know the thing that really kills me about this case, though? It’s just not that unusual an event. I taught a programming class at beautiful Foothill College, in Los Altos Hills, California, recently. As well as filling the students’ heads with knowledge about stacks, interrupts, kernels, device drivers, heaps, and such, I took pains to talk about the computer industry as a whole. As part of that, I wanted to give a brief lecture on ethics in the computer industry.

I figured I’d dredge up a few shocking tales about benchmark shenanigans, mention whatever was the most recent deceit from Microsoft corporate executives, and remind the class to avoid dealing from the bottom of the deck. I started collecting news stories and reports of ethical lapses within the computer industry to provide material for the lecture.

To my horror, I found that lack of integrity at high levels within a company was not as rare as I had supposed. My files swelled up with material and case studies to the point where I stopped collecting it. So if the MiniScribe story tells us anything, it is this: you will likely be confronted with something ethically wrong at some point in your programming career. When that happens, you’ll have a choice between going along with it, or refusing to. If you have thought about it beforehand, it will be easier to do the right thing. That’s all.



[1] The exceptions a method throws are not part of the signature, though.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.159.224