Basic Java Syntax



Topics in This Chapter
  • Primitive types
  • Arithmetic, logical, and relational operators
  • Conditional expressions and loops
  • Mathematical methods
  • Keyboard input and console output
  • Execution of local non-Java programs
  • References
  • Strings
  • Arrays
  • Vectors
  • Simple example of building a binary tree
  • Exceptions

Rules of Syntax

As you start writing real-world programs and try to decipher cryptic error messages from your compiler, it is nice to know the rules of the game. This short section describes some of the lexical and grammatical rules in Java.
Careful use of descriptive comments, white space, and indentation can make your source code easier to read. Two types of comments are permitted: block style and line style. Block-style comments are contained between /* (slash-star) and */ (star-slash) tokens; they can span multiple lines and are sometimes used to quickly comment-out a large block of code during testing. Line-style comments begin with two slashes, //; these comments extend just until the end of the line of code.
White space refers to a sequence of nondisplaying characters, for example, space, tab, and newline characters, which are used to separate pieces of code. White space is used principally for clarity, for example, to separate individual statements into different lines, to distinguish arguments in a function call, or to make expressions using mathematical operators easier to read. Another major use of white space is to provide indentation that helps to offset a section of code, typically sections of code in looping or if-else structures. Here is an example using comments, white space, and indentation:
/* Block style comments. These may span multiple
   lines. They may not be nested. */

// Single-line comment

while (int i=1; i<=5; i++) {
  if (i==2)
    System.out.println("Tea for two.");
  else
    System.out.println("Not two.");
}
All of the comments and most of the spaces in this example are optional. The following code snippet would be treated identically to the example above by a Java compiler. In fact, this code could be expressed on a single line and the compiler would still not complain.
while(int i=1;i<=5;i++){if(i==2)
System.out.println("Tea for two.");else
System.out.println("Not two.");}
You might ask, "Why is the space in the fragment 'int i' required?" The answer is that this space separates two tokens, the Java keyword int and the variablei. In the same way that English sentences are made up of words, Java programs consist of tokens such as numbers, variable names, punctuation characters, and special keywords. Just as we use rules of grammar to properly construct sentences when we speak or write in human languages, computers use grammatical rules to make programs clear and unambiguous. Two of the key grammatical rules regarding tokenization are:
  1. Tokens are case sensitive. For example, While or WHILE are not considered the same as the token while.
  2. Identifiers (i.e., the names of variables and methods), must start with an alphabetical character or an underscore (_) and may contain letters, numbers, and underscores. Technically, dollar signs and other currency symbols are also allowed where underscores are permitted; however, such use is not recommended since some compilers use dollar signs as special symbols internally.
Finally, separators are special symbols used to delimit parts of code. Semicolons, periods, commas, parentheses, and braces all act as separators: semicolons indicate the end of an expression, periods qualify variable and method identifiers, commas separate arguments in a method call, parentheses clarify arithmetic expressions and enclose argument lists, curly braces denote the start and end of control blocks, and square brackets indicate the use of arrays.
For additional details about Java syntax, refer to The Java Language Specification, which you can view on-line at: http://java.sun.com/docs/books/jls/.

Primitive Types

Java has two fundamental kinds of data types: primitive and reference. Primitive types are those simple types that are not "objects" (described in the previous chapter)�integers, characters, floating-point numbers, and the like. There are eight primitive types: booleancharbyteshortintlongfloat, anddouble. A ninth type, void, is used only to indicate when a method does not return a value.
boolean This is a type with only two possible values: true and false. A boolean is an actual type, not merely a disguised int. For example:
boolean flag1 = false;
boolean flag2 = (6 < 7); // true
boolean flag3 = !true;   // false
boolean flag4 = 0;       // compiler error!
char This is a 16-bit unsigned integer value representing a Unicode character. You can specify values numerically or with a character enclosed inside single quotes. These characters can be keyboard chars, unicode escape chars (\uxxxx with x in hex), or one of the special escape sequences \b(backspace), \t (tab), \n (newline), \f (form feed), \r (carriage return), \" (double quote), \' (single quote), or \\ (backslash). For instance:
char c0= 3;
char c1 = 'Q';
char c2 = '\u0000'; // Smallest value
char c3 = '\uFFFF'; // Biggest value
char c4 = '\b';     // Backspace
Learn more about the Unicode standard at http://www.unicode.org/.
byte This is an 8-bit, signed, two's-complement integer. See the description of int for ways to represent integral values. Bytes can range in value from-128 to +127.
short This is a 16-bit, signed, two's-complement integer. See the description of int for ways to represent integral values. Shorts range in value from-32768 to +32767.
int This is a 32-bit, signed, two's-complement integer. You can specify integer constants in base 10 (110, and 100 for 1, 10, and 100, respectively), octal with a prefix of 0 (010120144 for 1, 10, and 100), or hex by using a prefix of 0x (0x10xA0x64 for 1, 10, and 100). For hexadecimal numbers, you can use uppercase or lowercase for xABCDE, and F. Ints range from Integer.MIN_VALUE (-231) to Integer.MAX_VALUE(231 - 1). For example:
int i0 = 0;
int i1 = -12345;
int i2 = 0xCafeBabe; // Magic number of .class files
int i3 = 0777;       // Octal number, 511 in decimal
long This is a 64-bit, signed, two's-complement integer. Use a trailing L for literals. A lowercase l is also legal to designate a long literal, but discouraged. Depending on the display font, the lowercase l can be confused with a numerical 1 (one). You can use base 10, 8, or 16 for values. Longs range from Long.MIN_VALUE (-263) to Long.MAX_VALUE (263 - 1). Some examples:
long a0 = 0L;
long a1 = -12345l;
long a2 = 0xBabeL; // Tower of Babel?
long a3 = -06767l;
Except for char, the integral types (bytecharshortint, and long) are signed values. There is no built-in support for unsigned integer values in Java as in the C or C++ programming languages. When using integral types, especially smaller types such as byte or short, you should ensure that the numbers you wish to represent do not exceed the representable range of the primitive type. For example, if you want to represent the day of the year, you cannot use a byte, because it can only store a number as large as 127. Instead, you need to use a shortint, or long. Anint is probably sufficient for most applications.
float This is a 32-bit, IEEE 754 floating-point number. You must use a trailing f or F to distinguish single precision floating-point literals. In the example below, the f is required or else the compiler interprets the constant as a double precision floating-point number that needs a cast before being assigned to a float:
float f0 = -1.23f;
You can also use an e or E to indicate an exponent (power of 10). For instance, the first expression below assigns the value 6.02 x1023 to the variablef1 while the second gives the value 4.5 x 10-17 to f2.
float f1 = 6.02E23F;
float f2 = 4.5e-17f;
Floats range from Float.MIN_VALUE (1.4 x 10-45) to Float.MAX_VALUE (3.4 x 1038). Floating-point arithmetic never generates an exception, even in divide-by-zero cases. The Float class defines the constants POSITIVE_INFINITYNEGATIVE_INFINITY, and NaN (not-a-number) to use for some of these special cases. Use Float.isNaN to compare to NaN because (Float.NaN == Float.NaN) returns false, in conformance with the IEEE specification, which states that all comparisons to NaNs should fail.
double This is a 64-bit, IEEE 754 floating-point number. You are allowed to append a trailing d or D, but it is normally omitted. Some examples:
double d0 = 1.23;
double d2 = -4.56d;
double d3 = 6.02214E+23;
double d4 = 1e-99;
Doubles range from Double.MIN_VALUE (4.9 x 10-324) to Double.MAX_VALUE (1.7 x 10308). As with float, double-precision arithmetic never generates an exception. To handle unusual situations, the Double class also defines fields named POSITIVE_INFINITY,NEGATIVE_INFINITY, and NaN. Use Double.isNaN to compare a double to Double.NaN.

Primitive-Type Conversion

The Java programming language requires explicit typecasts to convert a value stored in a larger primitive type into a type with a smaller range or different domain. For example:
Type2 type2Var = (Type2)type1Var;
Truncation or loss of some significant digits may result from these casts, but even so, an exception is not thrown. For instance:
int i = 3;
byte b = (byte)i; // Cast i to a byte; no effect
long x = 123456L;
short s = (short)x; // Cast x to a short; lossy
Note that in the last example s does not contain an equivalent value to x because 123456 is not representable as a 16-bit integer quantity. In addition to downward conversions, those from larger to smaller types, conversions from floating-point to integer types also require a cast:
double d = 3.1416;
float f = (float)d; // Cast from 64 to 32 bits
short s = (short)f; // Cast a float to a short
int i = s; // Upward conversion, no cast is required
To perform rounding instead of truncation when performing cast conversions, use the rounding methods in the Math class; see Section 8.4 for more information. Note that numeric types may not be cast to boolean, or vice versa. The Java Language Specification, http://java.sun.com/docs/books/jls/, explains in detail the cases when casts are required between types.

Operators, Conditionals, Iteration

This section describes the basic arithmetic operators (+-*, and so forth), conditionals (if, and switch), and looping constructs (whiledo, and for). Some languages such as C++ permit programmers to adopt built-in operators as a syntactic shorthand for user-defined classes. For example, a C++ programmer might write the following code to add two geometric points together:
Point p1(3,4), p2(1,3); // C++ constructor syntax
p1 += p2; // To translate point p1 by p2
The Java programming language does not allow programmers to overload operators, a technique which some programmers find confusing when they try it with user-defined types. In such cases, method calls are used in the Java programming language instead, for example:
p1.translate(p2);

Arithmetic Operators

Table  summarizes the basic numerical operators. You might notice the lack of an exponentiation operator. Don't panic; exponentiation is possible through methods in the Math class . Also, note that + can be used for String concatenation;
Table . Numerical Operators
OperatorsMeaningExample
+, -addition, subtraction
x = y + 5;
*, /, %multiplication, division, remainder
int x = 3, y = 2;
int z = x / y; // 1
(integer division truncates)
++, --prefix/postfix increment/ decrement
int i = 1, j = 1;
int x = i++; // x=1, i=2
int y = ++j; // y=2, j=2
<<, >>, >>>signed and unsigned shifts
int x = 3;
int y = x << 2; // 12
~bitwise complement
int x = ~127; // -128
&, |, ^bitwise AND, OR, XOR
int x = 127 & 2; // 2
int y = 127 | 2; // 127
int z = 127 ^ 2; // 125
Java, like C and C++, lets you write
var op= val;
as a shorthand for
var = var op val;
For example, instead of
i = i + 5;
x = x * 3;
you can write
i += 5;
x *= 3;

Conditionals

The Java programming language has three conditional constructs: ifswitch, and "? :". , with more details given in the following section. If you are familiar with C or C++, you can skip this section because these operators are virtually identical to their C and C++ counterparts, except that conditions must be boolean valued. summarizes the 
Table  Conditionals
OperatorStandard Forms
if
if (boolean-expression) {
  statement;
}
if (boolean-expression) {
  statement1;
} else {
  statement2;
}
? :
boolean-expression ? val1 : val2;
switch
switch(someInt) {
  case val1: statement1;
             break;
  case val2: statement2a;
             statement2b;
             break;
  ...
  default: statementN;
}
Table  Boolean Operators
OperatorMeaning
==, !=Equality, inequality. In addition to comparing primitive types, == tests if two objects are identical (the same object), not just if they appear equal (have the same fields).
<, <=, >, >=Numeric less than, less than or equal to, greater than, greater than or equal to.
&&, ||Logical AND, OR. Both use short-circuit evaluation to more efficiently compute the results of complicated expressions.
!Logical negation.
if (boolean-expression) statement
if (boolean-expression) statement1 else statement2
The if keyword expects a boolean expression in parentheses. If the expression evaluates to true, the subsequent statement is executed. If the expression is false, the else statement (if present) is executed. Supplying a non-boolean expression results in a compile-time error, unlike the case with C and C++, which treat anything not equal to zero as true. Here is an example that returns the larger of two integers:
// See Math.max
public static int max2(int n1, int n2) {
  if (n1 >= n2)
    return(n1);
  else
    return(n2);
}
You can combine multiple statements in the if-else clause by enclosing them in curly braces. For instance:
public static int max2Verbose(int n1, int n2) {
  if (n1 >= n2) {
    System.out.println(n1 + " is larger.");
    return(n1);
  } else {
    System.out.println(n2 + " is larger.");
    return(n2);
  }
}
Next, note that an else always goes with the most recent preceding if that does not already have a matching else. For example:
public static int max3(int n1, int n2, int n3) {
  if (n1 >= n2)
    if (n1 >= n3)
      return(n1);
    else
      return(n3);
  else
    if (n2 >= n3)
      return(n2);
    else
      return(n3);
}
Two more points should be made here. First of all, note that the nested (indented) if statements are considered single statements; thus, curly braces are not required even though the statements flow over several lines. More importantly, see how indentation makes the association of the else clauses clearer.
Several different indentation styles are consistent with this approach. Following are a few of the most popular; we use the first style throughout most of the book.
// Indentation Style 1
public SomeType someMethod(...) {
  if {
    statement1;
    ....
    statementN
  } else {
    statementA;
    ...
    statementZ;
  }
}

// Indentation Style 2
public SomeType someMethod(...)
{ if
  { statement1;
    ...
    statementN;
  } else
  { statementA;
    ...
    statementZ;
  }
}

// Indentation Style 3
public SomeType someMethod(...)
{
  if
  {
    statement1;
    ...
    statementN;
  }
  else
  {
    statementA;
    ...
    statementZ;
  }
}
In certain cases, you can simplify multiple comparisons by combining them using logical operators && (logical AND) or || (logical OR). As in C and C++, these operators perform "short circuit" evaluation, which means that they return an answer as soon as they have enough information to do so (even if all the subexpressions have not been evaluated). In particular, a comparison with && evaluates to false whenever the leftmost conjunct isfalse; the right side is not then evaluated. Likewise, an expression with || immediately evaluates as true if the leftmost disjunct is true. Here's an example:
public static int max3(int n1, int n2, int n3) {
  if ((n1 >= n2) && (n1 >= n3))
    return(n1);
  else if ((n2 >= n1) && (n2 >= n3))
    return(n2);
  else
    return(n3);
}
There are single character forms of the logical operators, & and |, that do evaluate all of their operands. However, they are rarely used and may be confused with the bitwise arithmetic operators.
boolean-expression ? thenValue : elseValue
Since if statements do not return a value, Java provides a shortcut when the purpose of the if is to assign to a single variable. For example, you can express the following four lines
if (someCondition)
  someVar = value1;
else
  someVar = value2;
more simply as
someVar = (someCondition ? value1 : value2);
In fact, you can use this form whenever you need to return a value, although overuse can make code difficult to read. Here is a variation of max2 that uses it:
public static int max2Short(int n1, int n2) {
  return((n1 >= n2) ? n1 : n2);
}
switch(integralExpression) { switchBody }
The switch construct provides a compact way to compare an expression to a variety of integer types (charbyteshort, or int, but not long). The idea is to supply an integer expression and then provide, inside the switch body, one or more case statements that designate different possible values of the expression. When one matches, it and all subsequent cases are executed. Here is an example that uses switch to generate the string representation of a single-digit integer:
public static String number(int digit) {
  switch(digit) {
    case 0: return("zero");
    case 1: return("one");
    case 2: return("two");
    case 3: return("three");
    case 4: return("four");
    case 5: return("five");
    case 6: return("six");
    case 7: return("seven");
    case 8: return("eight");
    case 9: return("nine");
    default: return("Not a single digit");
  }
}
Section 8.9 (Arrays) describes a simpler way to perform this integer-to-string conversion by using arrays. The most confusing thing about switchstatements is that code "falls through" cases; all statements after the first matching case are executed. This is handy in some situations because it lets you combine cases, as follows:
switch(val) {
  case test1:
  case test2:
    actionForTest1and2();
  ...
}
However, it can catch you by surprise if the case statements do not contain an explicit return or break. For example, consider the following verbose variation of the number method:
// Incorrect version that forgets about case
// fall-through.

public static String numberVerbose(int digit) {
  String result;
  switch(digit) {
    case 0:  System.out.println("zero");
             result = "zero";
    case 1:  System.out.println("one");
             result = "one";
    case 2:  System.out.println("two");
             result = "two";
    case 3:  System.out.println("three");
             result = "three";
    case 4:  System.out.println("four");
             result = "four";
    case 5:  System.out.println("five");
             result = "five";
    case 6:  System.out.println("six");
             result = "six";
    case 7:  System.out.println("seven");
             result = "seven";
    case 8:  System.out.println("eight");
             result = "eight";
    case 9:  System.out.println("nine");
             result = "nine";
    default: System.out.println(
               "Not a single digit");
             result = "Not a single digit";
  }
  return(result);
}
Because there is no explicit direction to exit the switch after the first match, multiple cases are executed. For instance, here is the output whennumberVerbose(5) is called:
five
six
seven
eight
nine
Not a single digit
The standard solution is to use the break statement to exit the switch after the first match, as in the following corrected version:
public static String numberVerboseFixed(int digit) {
  String result;
  switch(digit) {
    case 0: System.out.println("zero");
            result = "zero";
            break;
    case 1: System.out.println("one");
            result = "one";
            break;
    ...
    default: System.out.println("Not a single digit");
             result = "Not a single digit";
  }
  return(result);
}

Loops

The Java programming language supports the same basic looping constructs as do C and C++: whiledo, and for. . In addition, Java supports the break and continue keywords, which are used to exit the loop or to interrupt the body and restart at the beginning, respectively.
Table . Looping Constructs
ConstructStandard Form
while
while (continueTest) {
  body;
}
do
do {
  body;
} while (continueTest);
for
for(init; continueTest; updateOp) {
  body;
}
while loops The while construct tests the supplied boolean continuation test, executing the body as long as the test returns true. For example, the following method prints out the numbers in the range from 0 to max.
public static void listNums1(int max) {
  int i = 0;
  while (i <= max) {
    System.out.println("Number: " + i);
    i++;
  }
}
Executing listNums1(5) results in the following output:
0: zero
1: one
2: two
3: three
4: four
do loops The do construct differs from while in that the test is evaluated after the loop body rather than before. This means that the body will always be executed at least once, regardless of the test's value. Following is a variation of the listNums method, using do. The result of listNums2(5)is identical to that shown for listNums1(5); however, listNums2(-5) would print "Number: 0", while listNums1(-5) would print nothing. The reason is that with a do loop the test is performed after the loop body, whereas a while loop tests before the loop body. In listNums1(-5), the loop body is never entered.
public static void listNums2(int max) {
  int i = 0;
  do {
    System.out.println("Number: " + i);
    i++;
  } while (i <= max); // Don't forget the semicolon
}
Forgetting the final semicolon in a do loop is a common syntax error.
for loops The for construct is by far the most common way to create loops with numbered counters. First, the init part is executed once. Then, as long as the continuation test evaluates to true, the statement is executed and then the update operation is performed. Here's an example that gives the same result as the previous two versions when passed a positive argument.
public static void listNums3(int max) {
  for(int i=0; i<max; i++) {
    System.out.println("Number: " + i);
  }
}
It is also legal to omit any (or all) of the three for clauses. A missing continueTest is treated as true. Thus,
for(;;) { body }
and
while(true) { body }
are equivalent. These forms are occasionally used when the termination test cannot be easily placed in the initial for or while clause. Instead, the body contains a conditional return or break.
The various forms of loops, whiledo, and for, are all equally expressive, and any loop that can be written with one can be rewritten with another instead. Individual programmers usually adopt a style for using each. Some programmers tend to use for loops predominantly, especially when looping over arrays or ranges of numbers. Some prefer while loops in cases where the number of times the loop will be executed is not generally known in advance, for example, based on the number of lines in an input file.

DropBall.java
/** Simulating dropping a ball from the top of the Washington
 *  Monument. The program outputs the height of the ball each
 *  second until the ball hits the ground.
 */

public class DropBall {
  public static void main(String[] args) {
    int time = 0;
    double start = 550.0, drop = 0.0;
    double height = start;
    while (height > 0) {
      System.out.println("After " + time +
                   (time==1 ? " second, " : " seconds,") +
                   "the ball is at " + height + " feet.");
      time++;
      drop = freeFall(time);
      height = start - drop;
    }
    System.out.println("Before " + time + " seconds could " +
                       "expire, the ball hit the ground!");
  }

  /** Calculate the distance in feet for an object in
   *  free fall.
   */

  public static double freeFall (float time) {
    // Gravitational constant is 32 feet per second squared
    return(16.0 * time * time); // 1/2 gt^2
  }
}
Output from DropBall
Prompt> java DropBall
After 0 seconds,the ball is at 550.0 feet.
After 1 second, the ball is at 534.0 feet.
After 2 seconds,the ball is at 486.0 feet.
After 3 seconds,the ball is at 406.0 feet.
After 4 seconds,the ball is at 294.0 feet.
After 5 seconds,the ball is at 150.0 feet.
Before 6 seconds could expire, the ball hit the ground!

The Math Class

Math provides a range of arithmetic methods not available as built-in operators. All of these methods are static, so there would never be any reason to create an instance of the Math class.

Constants

public static final double E
This constant is e, the base for natural logarithms, 2.7182818284590452354.
public static final double PI
This constant is p, 3.14159265358979323846.

General-Purpose Methods

public static int abs(int num)
public static long abs(long num)
public static float abs(float num)
public static double abs(double num)
These methods return the absolute value of the specified number.
public static double ceil(double num)
public static double floor(double num)
The ceil method returns a double corresponding to the smallest integer greater than or equal to the specified number; floor returns a doublecorresponding to the largest integer less than or equal to the number.
public static exp(double num)
This method returns enum.
public static double IEEEremainder(double f1, double f2)
This method returns the remainder of f1 divided by f2, as specified in the IEEE 754 standard.
public static double log(double num)
This method returns the natural logarithm of the specified number. Java does not provide a method for calculating logs in other common bases (e.g., 10 or 2), but following is a method that does this computation, using the relationship:
graphics/08equ01.gif

public static double log(double num, double base) {
  return(Math.log(num) / Math.log(base));
}
public static int max(int num1, int num2)
public static long max(long num1, long num2)
public static float max(float num1, float num2)
public static double max(double num1, double num2)
public static int min(int num1, int num2)
public static long min(long num1, long num2)
public static float min(float num1, float num2)
public static double min(double num1, double num2)
These methods return the bigger (max) or smaller (min) of the two numbers.
public static double pow(double base, double exponent)
The pow method returns baseexponent.
public static double random()
This method returns a random number from 0.0 (inclusive) to 1.0 (exclusive). For more control over random numbers, use thejava.util.Random class.
public static double rint(double num)
public static int round(float num)
public static long round(double num)
These methods round the number toward the nearest integer. They differ in their return types and what they do for a number of the form xxx.5. Theround methods round up in such a case; rint rounds to the nearest even number, as specified in the IEEE 754 standard. Although less intuitive, the behavior of rint avoids skewing sums of rounded numbers upwards.
public static double sqrt(double num)
This method returns graphics/08equ02.gif for nonnegative numbers and returns Double.NaN if the input is NaN or is negative.

Trigonometric Methods

public static double sin(double radians)
public static double cos(double radians)
public static double tan(double radians)
These methods return the sine, cosine, and tangent of the specified number, interpreted as an angle in radians.
public static double toDegrees(double radians)
public static double toRadians(double degrees)
These methods perform conversions between angles expressed in radians and degrees. For example, the following computes the sine of 60 degrees:
Math.sin(Math.toRadians(60.0))
public static double acos(double val)
public static double asin(double val)
public static double atan(double val)
These methods return the arc cosine, arc sine, and arc tangent of the specified value. The result is expressed in radians.
public static double atan2(double y, double x)
This method returns the q part of the polar coordinate (r,q) that corresponds to the cartesian coordinate (x,y). This is the atan of y/x that is in the range -p to p

BigInteger and BigDecimal

The Java programming language supports two arbitrary-precision number formats: java.math.BigInteger and java.math.BigDecimal. These classes contain methods for addition, multiplication, division, exponentiation, primality testing, greatest common divisors, and more. See the API for details, but the key point is that these classes can be used to obtain any desired level of accuracy. For instance, every digit in a BigInteger is significant, and it cannot overflow. To illustrate this, 
Factorial.java
import java.math.BigInteger;

/** Computes an exact factorial, using a BigInteger. */

public class Factorial {
  public static void main(String[] args) {
    for(int i=1; i<=256; i*=2) {
      System.out.println(i + "!=" + factorial(i));
    }
  }

  public static BigInteger factorial(int n) {
    if (n <= 1) {
      return(new BigInteger("1"));
    } else {
      BigInteger bigN = new BigInteger(String.valueOf(n));
      return(bigN.multiply(factorial(n - 1)));
    }
  }
}
 Factorial Output
Prompt> java Factorial
1!=1
2!=2
4!=24
8!=40320
16!=20922789888000
32!=263130836933693530167218012160000000
64!=1268869321858841641034333893351614808028655161745451921988018
94375214704230400000000000000
128!=385620482362580421735677065923463640617493109590223590278828
40327637340257516554356068616858850736153403005183305891634759217
29322624988577661149552450393577600346447092792476924955852800000
00000000000000000000000000
256!=857817775342842654119082271681232625157781520279485619859655
65037726945255314758937744029136045140845037588534233658430615719
68346936964753222892884974260256796373325633687864426752076267945
60187968867971521143307702077526646451464709187326100832876325702
81898077367178145417025052301860849531906813825748107025281755945
94769870346657127381392862052347568082188607012036110831520935019
47437109101726968262861606263662435022840944191408424615936000000
000000000000000000000000000000000000000000000000000000000


Do not confuse the java.math package, where classes BigInteger and BigDecimal are found, with thejava.lang.Math class. The Math class is more commonly used; it provides all of the methods in the standard mathematical library.

Input and Output

The simplest forms of I/O are discussed in this section: printing to standard output and reading from standard input.

Printing to Standard Output

You've already seen examples of printing with System.out.println. As you probably guessed from the Java naming conventions, out is a staticvariable in the System class, and println is a method in the class that belongs to out. That class is PrintStream; it also contains a print method that works just like println except that it omits the trailing newline. Both println and print take a single argument of any type. Primitive types are converted to strings by the String.valueOf method, and non-String objects are converted to strings by their toString method. Longer strings can be formed from components joined through the + concatenation operator. For example:
System.out.println(
   2 + 'B' + " || ! " + new Integer(2) + "B");
In addition to println and print, the PrintStream class also contains a flush method. This method is useful when you want to be sure that output has not been cached (e.g., when reading from standard input just after writing a prompt). For full details, see the on-line API for java.io.PrintStream.
Surprisingly, Java's way of controlling the spacing and formatting of numbers is not as simple as C's printf or sprintf functions. Thejava.text.DecimalFormat class provides this sort of functionality indirectly. DecimalFormat works by creating an object that describes the desired formatting of your number(s). You then use this object's format method as needed to convert numbers into formatted strings.



NumFormat.java


import java.text.*;

/** Formatting real numbers with DecimalFormat. */

public class NumFormat {
  public static void main (String[] args) {
    DecimalFormat science = new DecimalFormat("0.000E0");
    DecimalFormat plain = new DecimalFormat("0.0000");

    for(double d=100.0; d<140.0; d*=1.10) {
      System.out.println("Scientific: " + science.format(d) +
                         " and Plain: " + plain.format(d));
    }
  }
}
NumFormat Output
Prompt> java NumFormat
Scientific: 1.000E2 and Plain: 100.0000
Scientific: 1.100E2 and Plain: 110.0000
Scientific: 1.210E2 and Plain: 121.0000
Scientific: 1.331E2 and Plain: 133.1000
In the previous example, the DecimalFormat constructor used expects a String defining the pattern in which to display the number when converting to aString by the format method. The pattern can indicate the number of digits to display and possible separators. . For example, ,###.0 would format a number with a single digit after the decimal point and would display a comma separator if the number is in the thousands: the number 23767.82 would format as 23,767.8, the number 0.43 would format as .4 (no leading zero).
DecimalFormat provides only coarse control when printing numbers. If you find DecimalFormat too cumbersome, you can use one of the public domainprintf substitutes. One of the best ones is from Jef Poskanzer; see http://www.acme.com/java/software/Acme.Fmt.html.
Finally, output sent to System.out can be redirected to a different stream instead. One situation where redirection is useful occurs when you want to produce a log file instead of sending messages to the console window. To accomplish this, you simply call System.setOut once with the PrintStream to which you want to send output.
Table  Formatting Characters
SymbolMeaning
0Placeholder for a digit.
#Placeholder for a digit. If the digit is leading or trailing zero, then don't display.
.Location of decimal point.
,Display comma at this location.
-Minus sign.
EScientific notation. Indications the location to separate the mantissa from the exponent.
%Multiply the value by 100 and display as a percent.

Printing to Standard Error

In addition to the System.out variable, the System.err variable can be used on operating systems that maintain a distinction between normal output and error output. It, too, is a PrintStream and can be used in exactly the same way as System.out. It also can be redirected; you use System.setErr for this purpose.

Reading from Standard Input

It is relatively uncommon to read from standard input in the Java programming language. Nongraphical applications typically use the command-line arguments for the data they need, and graphical programs use a textfield, button, slider, or other GUI control. If you do need to read input this way, the standard approach is first to turn System.in into a BufferedReader as follows:
BufferedReader keyboard =
  new BufferedReader(
    new InputStreamReader(System.in));
Then, you can use keyboard.readLine to retrieve a line of input:
String line = keyboard.readLine();

Execution of Non-Java Programs

Because of default security restrictions, applets (Java programs embedded in Web pages) cannot execute system programs; however, applications (stand-alone Java programs) can execute system programs. Starting a local program involves the following four steps:
  1. Get the special Runtime object. Use the static getRuntime method of the Runtime class for this, as follows:
    Runtime rt = Runtime.getRuntime();
    
  2. Execute the program. Use the exec method, which returns a Process object, as illustrated below:
    Process proc = rt.exec("someProgram");
    
    This starts the program but does not wait for the program to terminate or print the program results. Note that the exec method does not make use of yourPATH environment variable (used on Windows 98/NT and Unix to identify where to look for programs), so you need to specify the full pathname. Also, execdoes not start a shell, so special shell characters (such as > or | in Unix) will not be recognized. Finally, note that the Runtime class provides versions ofexec that take an array of strings and pass the strings as command-line arguments to a program. For example,
    String[] args = { "-l", "*.java" };
    rt.exec("ls", args); // Directory listing.
    
  3. Optional: wait for the program to exit. The exec method returns immediately, regardless of how long it takes the program to run. This behavior enables you to start long-running programs such as Netscape and still continue processing; however, this behavior catches many users off guard. If you want the program to wait until the program exits before returning, use the waitFor method after you start the process:
    proc.waitFor();
    
    While you might simply use exec to start Netscape, you would add waitFor if one program needs to terminate before another can begin. For example, you might call javac on a source file and use java to execute the result, but the compilation must finish before the program can invoke a new instance of the JVM to execute the complied class file. Note that waitFor does not print the program results; it simply waits for the program to finish before returning.
  4. Optional: process the results. Rather than simply waiting for the program to terminate, you might want to capture its output. For example, telling the system to do a directory listing is not too useful unless you access the results. You can print the results by attaching a BufferedReader to the process, then reading from it, as in the following example:
    try {
      BufferedReader buffer =
       new BufferedReader(
         new InputStreamReader(proc.getInputStream()));
      String s = null;
      while ((s = buffer.readLine()) != null) {
        System.out.println("Output: " + s);
      }
      buffer.close();
    } catch(Exception e) {
      /* Ignore read errors */
    }
    

Finally, because starting processes and then communicating with them requires native operating system support, some risk is associated with their use. In particular, there are situations where the virtual machine can hang due to a deadlocked process.


Be judicious when starting system processes. In situations where input or output streams are not processed efficiently, deadlock can occur.
 Exec.java
import java.io.*;

/** A class that eases the pain of running external processes
 *  from applications. Lets you run a program three ways:
 *  <OL>
 *     <LI><B>exec</B>: Execute the command, returning
 *         immediately even if the command is still running.
 *         This would be appropriate for printing a file.
 *     <LI><B>execWait</B>: Execute the command, but don't
 *         return until the command finishes. This would be
 *         appropriate for sequential commands where the first
 *         depends on the second having finished (e.g.,
 *         <CODE>javac</CODE> followed by <CODE>java</CODE>).
 *     <LI><B>execPrint</B>: Execute the command and print the
 *          output. This would be appropriate for the Unix
 *          command <CODE>ls</CODE>.
 *  </OL>
 *  Note that the PATH is not taken into account, so you must
 *  specify the <B>full</B> pathname to the command, and shell
 *  built-in commands will not work. For instance, on Unix the
 *  above three examples might look like:
 *  <OL>
 *    <LI><PRE>Exec.exec("/usr/ucb/lpr Some-File");</PRE>
 *    <LI><PRE>Exec.execWait("/usr/local/bin/javac Foo.java");
 *        Exec.execWait("/usr/local/bin/java Foo");</PRE>
 *    <LI><PRE>Exec.execPrint("/usr/bin/ls -al");</PRE>
 *  </OL>
 */
public class Exec {

  private static boolean verbose = true;

  /** Determines if the Exec class should print which commands
    * are being executed, and prints error messages if a problem
    * is found. Default is true.
    *
    * @param verboseFlag true: print messages, false: don't.
    */

  public static void setVerbose(boolean verboseFlag) {
    verbose = verboseFlag;
  }

  /** Will Exec print status messages? */

  public static boolean getVerbose() {
    return(verbose);
  }

  /** Starts a process to execute the command. Returns
    * immediately, even if the new process is still running.
    *
    * @param command The <B>full</B> pathname of the command to
    * be executed. No shell built-ins (e.g., "cd") or shell
    * meta-chars (e.g.">") are allowed.
    * @return false if a problem is known to occur, but since
    * this returns immediately, problems aren't usually found
    * in time. Returns true otherwise.
    */

  public static boolean exec(String command) {
    return(exec(command, false, false));
  }

  /** Starts a process to execute the command. Waits for the
    * process to finish before returning.
    *
    * @param command The <B>full</B> pathname of the command to
    * be executed. No shell built-ins or shell metachars are
    * allowed.
    * @return false if a problem is known to occur, either due
    * to an exception or from the subprocess returning a
    * nonzero value. Returns true otherwise.
    */

  public static boolean execWait(String command) {
    return(exec(command, false, true));
  }

  /** Starts a process to execute the command. Prints any output
    * the command produces.
    *
    * @param command The <B>full</B> pathname of the command to
    * be executed. No shell built-ins or shell meta-chars are
    * allowed.
    * @return false if a problem is known to occur, either due
    * to an exception or from the subprocess returning a
    * nonzero value. Returns true otherwise.
    */

  public static boolean execPrint(String command) {
    return(exec(command, true, false));
  }

  /** This creates a Process object via Runtime.getRuntime.exec()
    * Depending on the flags, it may call waitFor on the process
    * to avoid continuing until the process terminates, and open
    * an input stream from the process to read the results.
    */

  private static boolean exec(String command,
                              boolean printResults,
                              boolean wait) {
    if (verbose) {
      printSeparator();
      System.out.println("Executing '" + command + "'.");
    }
    try {
      // Start running command, returning immediately.
      Process p  = Runtime.getRuntime().exec(command);

      // Print the output. Since we read until there is no more
      // input, this causes us to wait until the process is
      // completed.
      if(printResults) {
        BufferedReader buffer = new BufferedReader(
          new InputStreamReader(p.getInputStream()));
        String s = null;
        try {
          while ((s = buffer.readLine()) != null) {
            System.out.println("Output: " + s);
          }
          buffer.close();
          if (p.exitValue() != 0) {
            if (verbose) {
              printError(command + " - p.exitValue() != 0");
            }
            return(false);
          }
        } catch (Exception e) {
          // Ignore read errors; they mean the process is done.
        }

      // If not printing the results, then we should call waitFor
      // to stop until the process is completed.
      } else if (wait) {
        try {
          System.out.println(" ");
          int returnVal = p.waitFor();
          if (returnVal != 0) {
            if (verbose) {
              printError(command);
            }
            return(false);
          }
        } catch (Exception e) {
          if (verbose) {
            printError(command, e);
          }
          return(false);
        }
      }
    } catch (Exception e) {
      if (verbose) {
        printError(command, e);
      }
      return(false);
    }
    return(true);
  }

  private static void printError(String command,
                                 Exception e) {
    System.out.println("Error doing exec(" + command + "): " +
                        e.getMessage());
    System.out.println("Did you specify the full " +
                       "pathname?");
  }

  private static void printError(String command) {
    System.out.println("Error executing '" + command + "'.");
  }

  private static void printSeparator() {
    System.out.println
      ("==============================================");
  }
}

 ExecTest.java
/** A test of the Exec class. */

public class ExecTest {
  public static void main(String[] args) {
    // Note: no trailing "&" -- special shell chars not
    // understood, since no shell started. Besides, exec
    // doesn't wait, so the program continues along even
    // before Netscape pops up.
    Exec.exec("/usr/local/bin/netscape");

    // Run commands, printing results.
    Exec.execPrint("/usr/bin/ls");
    Exec.execPrint("/usr/bin/cat Test.java");

    // Don't print results, but wait until this finishes.
    Exec.execWait("/usr/java1.3/bin/javac Test.java");

    // Now Test.class should exist.
    Exec.execPrint("/usr/bin/ls");
  }
}
 ExecTest Output
Unix> java ExecTest
==============================================
Executing '/usr/local/bin/netscape'.
==============================================
Executing '/usr/bin/ls'.
Output: Exec.class
Output: Exec.java
Output: ExecTest.class
Output: ExecTest.java
Output: Test.java
==============================================
Executing '/usr/bin/cat Test.java'.
Output: public class Test {
Output:   boolean flag;
Output: }
==============================================
Executing '/usr/java1.3/bin/javac Test.java'.
==============================================
Executing '/usr/bin/ls'.
Output: Exec.class
Output: Exec.java
Output: ExecTest.class
Output: ExecTest.java
Output: Test.class
Output: Test.java

 Reference Types

Values that are objects (i.e., class instances or arrays; anything nonprimitive) are known as reference values or simply references. In the Java world, we normally say that the value of such and such a variable "is" an object. Because the Java programming language has no explicit referencing or dereferencing of pointers or pointer arithmetic, it is commonly but erroneously stated that Java does not have pointers. Wrong! In fact, all nonprimitive variables in Java are pointers. So, a C programmer might find it clearer to say that such and such a nonprimitive variable "points to" an object. This is the only kind of nonprimitive type in Java; there is no distinction between variables that are objects and variables that point to objects as in some languages.
If you are not already familiar with pointers, the basic idea is that you can pass big complicated objects around efficiently; Java doesn't copy them every time you pass them from one method to another. If you've used pointers extensively in other languages, be aware that Java forbids dereferencing pointers; given a referenced object, a method cannot modify a reference so that it refers to a different object.

 ReferenceTest.java
import java.awt.Point;

public class ReferenceTest {
  public static void main(String[] args) {
    Point p1 = new Point(1, 2); // Assign Point to p1
    Point p2 = p1; // p2 is new reference to *same* Point
    print("p1", p1); // (1, 2)
    print("p2", p2); // (1, 2)
    triple(p2); // Doesn't change p2
    print("p2", p2); // (1, 2)
    p2 = triple(p2); // Have p2 point to *new* Point
    print("p2", p2); // (3, 6)
    print("p1", p1); // p1 unchanged: (1, 2)
  }

  public static Point triple(Point p) {
    p = new Point(p.x * 3, p.y * 3); // Redirect p
    return(p);
  }

  public static void print(String name, Point p) {
    System.out.println("Point " + name + "= (" +
                       p.x + ", " + p.y + ").");
  }
}
ReferenceTest Output
Prompt> java ReferenceTest
Point p1= (1, 2).
Point p2= (1, 2).
Point p2= (1, 2).
Point p2= (3, 6).
Point p1= (1, 2).
Notice that changing the local variable p in the triple method didn't change the variable passed in (p2); it merely made p point someplace new, leaving p2referring to the original place. To change p2 to a new object, we assigned it to the return value of triple. Although it is not possible for a method to change where an external variable points (i.e., the object to which it refers), it is possible for a method to change the fields of an object, assuming that the field's access permissions are appropriate. 


 ModificationTest.java
import java.awt.Point;

public class ModificationTest extends ReferenceTest {
  public static void main(String[] args) {
    Point p1 = new Point(1, 2); // Assign Point to p1
    Point p2 = p1; // p2 is new reference to *same* Point
    print("p1", p1); // (1, 2)
    print("p2", p2); // (1, 2)
    munge(p2); // Changes fields of the *single* Point
    print("p1", p1); // (5, 10)
    print("p2", p2); // (5, 10)
  }

  public static void munge(Point p) {
    p.x = 5;
    p.y = 10;
  }
}
ModificationTest Output
Prompt> java ModificationTest
Point p1= (1, 2).
Point p2= (1, 2).
Point p1= (5, 10).
Point p2= (5, 10).

Java Argument-Passing Conventions

Now, if you are already familiar with the terms "call by value" and "call by reference," you may be puzzled as to which scheme Java uses. It cannot be call by reference, because the change to p in triple didn't change the external value. But the convention doesn't look like call by value either, because the mungemethod showed that methods don't get copies of objects. Don't worry about the definitions�simply remember the following rule.

 
If you pass a variable to a method in Java, the method cannot change which object the variable references but might be able to change the fields of that object.
If you are absolutely determined to pin the definition down, then you can say that Java uses call by value, but that the values themselves are references (restricted pointers).

The instanceof Operator

The instanceof operator returns true only if the left-hand argument is a direct or indirect instance of the class or interface named by the right-hand argument. For example:
if (item instanceof Breakable) {
  add(item, chinaCabinet);
}
Use this operator with caution; instanceof can often be replaced with polymorphism, yielding a faster, simpler, and more maintainable result. One problem with instanceof is that you need to know the name of the class or interface when you write your code. To provide a general solution that will work in all situations, a dynamic version of this test was added in Java 1.1. This second approach involves calling the isInstance method of an instance ofjava.lang.Class with the object you want to examine. 


 InstanceOf.java
interface Barking {}

class Mammal {}

class Canine extends Mammal {}

class Dog extends Canine implements Barking {}

class Retriever extends Dog {}

public class InstanceOf {
  public static void main(String[] args) {
    Canine wolf = new Canine();
    Retriever rover = new Retriever();

    System.out.println("Testing instanceof:");
    report(wolf, "wolf");
    System.out.println();
    report(rover, "rover");

    System.out.println("\nTesting isInstance:");
    Class barkingClass = Barking.class;
    Class dogClass = Dog.class;
    Class retrieverClass = Retriever.class;
    System.out.println("  Does a retriever bark? " +
                       barkingClass.isInstance(rover));
    System.out.println("  Is a retriever a dog? " +
                       dogClass.isInstance(rover));
    System.out.println("  Is a dog necessarily a retriever? " +
                       retrieverClass.isInstance(new Dog()));
  }

  public static void report(Object object, String name) {
    System.out.println("  " + name + " is a mammal: " +
                       (object instanceof Mammal));
    System.out.println("  " + name + " is a canine: " +
                       (object instanceof Canine));
    System.out.println("  " + name + " is a dog: " +
                       (object instanceof Dog));
    System.out.println("  " + name + " is a retriever: " +
                       (object instanceof Retriever));
  }
}
 InstanceOf Output
prompt> java InstanceOf
Testing instanceof:
  wolf is a mammal: true
  wolf is a canine: true
  wolf is a dog: false
  wolf is a retriever: false

  rover is a mammal: true
  rover is a canine: true
  rover is a dog: true
  rover is a retriever: true

Testing isInstance:
  Does a retriever bark? true
  Is a retriever a dog? true
  Is a dog necessarily a retriever? false

Strings

In Java, strings are real objects, members of the java.lang.String class. However, because they are so frequently used, you are allowed to create them simply by using double quotes, as follows:
String s1 = "This is a String";
The normal object-creation approach of using new is legal also, for example,
String s2 = new String("This is a String too");
but is rarely used.
The most unusual thing about the String class is that strings are immutable; once created they cannot be changed. "Hold on," you say, "I know there is nosetCharacterAt method, but I've seen string concatenation used lots of places." That's a good point; the + character can be used to concatenate strings, as follows:
String test = "foo" + "bar"; // "foobar"
However, in this example three strings are created: foobar, and a new third string foobar. This distinction doesn't seem important in the previous example but is very significant in the following code:
String foo = "foo";
String bar = "bar";
String test = foo + bar;
The key point here is that neither foo nor bar is modified by the concatenation performed on the third line. This is a convenient feature; it means that it is safe to pass strings to arbitrary methods without worrying about them being modified. On the other hand, to implement this unchangeable nature, Java has to copy the strings when concatenation is performed. This can be expensive, so Java supplies a StringBuffer class that is mutable.
Note that + is the only overloaded operators in Java; it has a totally different meaning for strings than it has for numbers. You cannot define your own operators or overload existing ones. One other thing you should know about String is that it is a final class and therefore you cannot create a subclass of String.

String Methods

The Java programming language provides a number of useful methods for working with strings. They are summarized below.
public char charAt(int index)
This method returns the character at the specified location.
public int compareTo(String comparison)
public int compareTo(Object object)
The compareTo method compares the current string to the supplied string, character by character, checking Unicode ordering. It returns 0 if the strings are equal (have the same characters), a negative number if the current string is lexicographically less than the comparison, and a positive number otherwise. This method is generally used for determining if strings are in order. The actual number is the difference in Unicode values between the first nonmatching characters, or the difference in lengths if the shorter string is a prefix of the longer one. To satisfy the Comparable interface, the method for objects was added in Java 1.2. It acts like the string compareTo method but throws a ClassCastException if the input is not a string.
public String concat(String suffix)
The concat method concatenates two strings, forming a new String. The following two forms are identical:
String result = someString.concat(someOtherString);
String result = someString + someOtherString;
Neither someString nor someOtherString is modified in these examples; instead a new String is created.
public static String copyValueOf(char[ ] characters)
public static String copyValueOf(char[ ] data, int startIndex, int count)
These static methods convert character arrays to strings.
public boolean endsWith(String suffix)
This method checks for a suffix of a string.
public boolean equals(Object comparison)
If the comparison object is not a Stringequals returns false. Otherwise, it compares character by character. Thus, two different strings with the same characters will be equals but not ==

Two different String objects that contain the same characters will not be ==. They will, however, be equals. In general, two different objects are not == even when their fields have identical values.
public boolean equalsIgnoreCase(String comparison)
This method performs a case-insensitive, character-by-character comparison.
public byte[ ] getBytes()
public byte[ ] getBytes(String encoding)
These methods convert a string to a byte array.
public void getChars(int sourceStart, int sourceEnd, char[ ] destination, int destinationStart)
This method copies the characters from sourceStart (inclusive) to sourceEnd (exclusive) into the specified part of the destination array.
public int indexOf(int character)
public int indexOf(int character, int startIndex)
public int indexOf(String subString)
public int indexOf(String subString, int startIndex)
These methods return the index of the first occurrence of the specified target.
public native String intern()
The intern method returns a canonical String containing the same characters as the supplied string. The interned result of two strings is == if and only if the strings themselves are equals.
public int lastIndexOf(int character)
public int lastIndexOf(int character, int startIndex)
public int lastIndexOf(String subString)
public int lastIndexOf(String subString, int startIndex)
These methods return the index of the last occurrence of the specified target.
public int length()
This method gives the length of the string. Note that this is a method call, not an instance variable. So, don't forget that for strings you have to do
int len = someString.length(); // length()
and for arrays you do
int len = someArray.length; // No parens
public boolean regionMatches(int startIndex1, String string2, int startIndex2, int count)
public boolean regionMatches(boolean ignoreCase, int startIndex1, String string2, int startIndex2, int count)
These methods perform a case-sensitive or -insensitive comparison of two substrings.
public String replace(char oldChar, char newChar)
The replace method returns a new String that is the result of replacing all occurrences of oldChar by newChar. The original string is not modified.
public boolean startsWith(String prefix)
public boolean startsWith(String prefix, int startIndex)
These methods check for string prefixes.
public String substring(int startIndex, int endIndex)
public String substring(int startIndex)
These methods return substrings in the specified range. If no ending index is supplied, the substring goes to the end of the original string.
public char[ ] toCharArray()
Use this method to generate a character array.
public String toLowerCase()
public String toLowerCase(Locale locale)
public String toUpperCase()
public String toUpperCase(Locale locale)
These methods convert the entire string to lower case or upper case, optionally using the rules of the specified locale.
public String trim()
This method returns a new String with leading and trailing white space and control characters removed. The original String is not modified.
public static String valueOf(boolean b)
public static String valueOf(char c)
public static String valueOf(char[ ] data)
public static String valueOf(char[ ] data, int startIndex, int count)
public static String valueOf(double d)
public static String valueOf(float f)
public static String valueOf(int i)
public static String valueOf(long l)
These static methods convert the specified primitive values to strings.
public static String valueOf(Object o)
This static method uses the object's toString method to generate a string.


 StringTest.java
public class StringTest {
  public static void main (String[] args) {
    String str = "";
    if (args.length > 0) {
        str = args[0];
    }
    if (str.length()>8) {
      System.out.println("String is \"" + str + "\"\n");
      System.out.println("  charAt(3) ------------------ " +
                         str.charAt(3));
      System.out.println("  compareTo(Moscow) ---------- " +
                         str.compareTo("Moscow"));
      System.out.println("  concat(SuFFiX) ------------- " +
                         str.concat("SuFFiX"));
      System.out.println("  endsWith(hic) -------------- " +
                         str.endsWith("hic"));
      System.out.println("  == Geographic -------------- " +
                         (str == "Geographic"));
      System.out.println("  equals(geographic) --------- " +
                         str.equals("geographic"));
      System.out.println("  equalsIgnoreCase(geographic) " +
                         str.equalsIgnoreCase("geographic"));
      System.out.println("  indexOf('o') --------------- " +
                         str.indexOf('o'));
      System.out.println("  indexOf('i',5) ------------- " +
                         str.indexOf('i',5));
      System.out.println("  indexOf('o',5) ------------- " +
                         str.indexOf('o',5));
      System.out.println("  indexOf(rap) --------------- " +
                         str.indexOf("rap"));
      System.out.println("  indexOf(rap, 5) ------------ " +
                         str.indexOf("rap", 5));
      System.out.println("  lastIndexOf('o') ----------- " +
                         str.lastIndexOf('o'));
      System.out.println("  lastIndexOf('i',5) --------- " +
                         str.lastIndexOf('i',5));
      System.out.println("  lastIndexOf('o',5) --------- " +
                         str.lastIndexOf('o',5));
      System.out.println("  lastIndexOf(rap) ----------- " +
                         str.lastIndexOf("rap"));
      System.out.println("  lastIndexOf(rap, 5) -------- " +
                         str.lastIndexOf("rap", 5));
      System.out.println("  length() ------------------- " +
                         str.length());
      System.out.println("  replace('c','k') ----------- " +
                         str.replace('c','k'));
      System.out.println("  startsWith(eog,1) ---------- " +
                         str.startsWith("eog",1));
      System.out.println("  startsWith(eog) ------------ " +
                         str.startsWith("eog"));
      System.out.println("  substring(3) --------------- " +
                         str.substring(3));
      System.out.println("  substring(3,8) ------------- " +
                         str.substring(3,8));
      System.out.println("  toLowerCase() -------------- " +
                         str.toLowerCase());
      System.out.println("  toUpperCase() -------------- " +
                         str.toUpperCase());
      System.out.println("  trim() --------------------- " +
                         str.trim());
      System.out.println("\nString is still \"" + str + "\"\n");
    }
  }
}
Listing 8.17 StringTest Output
  Prompt> java StringTest Geographic
  String is "Geographic"
  charAt(3) ------------------ g
  compareTo(Moscow) ---------- -6
  concat(SuFFiX) ------------- GeographicSuFFiX
  endsWith(hic) -------------- true
  == Geographic -------------- false
  equals(geographic) --------- false
  equalsIgnoreCase(geographic) true
  indexOf('o') --------------- 2
  indexOf('i',5) ------------- 8
  indexOf('o',5) ------------- -1
  indexOf(rap) --------------- 4
  indexOf(rap, 5) ------------ -1
  lastIndexOf('o') ----------- 2
  lastIndexOf('i',5) --------- -1
  lastIndexOf('o',5) --------- 2
  lastIndexOf(rap) ----------- 4
  lastIndexOf(rap, 5) -------- 4
  length() ------------------- 10
  replace('c','k') ----------- Geographik
  startsWith(eog,1) ---------- true
  startsWith(eog) ------------ false
  substring(3) --------------- graphic
  substring(3,8) ------------- graph
  toLowerCase() -------------- geographic
  toUpperCase() -------------- GEOGRAPHIC
  trim() --------------------- Geographic

String is still "Geographic"

Constructors

public String()
This constructor builds a zero-length but non-null string.
public String(byte[ ] bytes)
public String(byte[ ] bytes, String encoding)
public String(byte[ ] bytes, int startIndex, int count)
public String(byte[ ] bytes, int startIndex, int count, String encoding)
These constructors build a string from byte arrays.
public String(char[ ] chars)
public String(char[ ] chars, int startIndex, int count)
These constructors build a string from character arrays.
public String(String string)
This constructor copies the string. The result is equals but not == to the input.
public String(StringBuffer stringBuffer)
This constructor converts a StringBuffer to a String.

 Arrays

An array is a simple and efficient data structure used in virtually all programming languages. Arrays are used principally to provide constant-time access to a fixed-size collection of primitive datatypes or objects and are a way of referring to many distinct values by a single identifier. Arrays are implemented as real objects with the following properties:
  • Their length can be determined through the length field.
  • They can be assigned to variables of type Object as well as to variables of their specific type.
  • Arrays are efficiently passed to methods by reference just like any other Object.
Array indexing is zero-based, so elements in an array of 10 values can be referred to with subscripts from 0 through 9. Arrays are normally created in two steps: allocation and assignment of values. For an array of primitive datatypes, each element of the array is initialized to the default value for the primitive datatype. For an array of objects, each element of the array is initialized to null. When accessing array elements, you should be careful to avoid referring to an array location larger than the size of the array.
Following we present two approaches for allocating an array. The first approach allocates an array in two steps, first declaring the size of the array and then assigning values. The second approach allocates the array in one stop, assigning the values at the same time the array is declared.

Two-Step Array Allocation

In the first step, an array of the proper size and desired type is allocated:
int[] values = new int[2]; // a 2-element array
Point[] points = new Point[5]; // a 5-element array
int numNames = askHowManyNames(); // Set at runtime
String[] names = new String[numNames];
This step does not build any of the objects that actually go into the array. That building is done in a separate step by means of the arrayReference[index]notation to access array locations. For example:
values[0] = 10;
values[1] = 100;
for(int i=0; i<points.length; i++) {
  points[i] = new Point(i*2, i*4);
}
for(int j=0; j<names.length; j++) {
  names[j] = "Name " + j;
}
A common error is to forget the second step. If you get a NullPointerException whenever you access an array element, check for this problem first.


The following allocates n references to SomeObject; it doesn't actually build any instances of SomeObject:
SomeObject[] objArray = new SomeObject[n];
By the way, you are allowed to assign values in an array over time; that is, the array does not have to be completely initialized immediately after it is created, though it is considered good form to do so. Also, if you are a die-hard C hacker, you are permitted to declare arrays with the syntax
Type someVar[] = ...
instead of
Type[] someVar = ...
Just be aware that this reduces your JHF (Java Hipness Factor) by 2.5 units.

One-Step Array Allocation

You can also allocate arrays and assign to them in one fell swoop by specifying comma-separated elements inside curly braces in the initialization portion of a variable declaration. For instance:
int[] values = { 10, 100 };
Point[] points = { new Point(0, 0),
                   new Point(2, 4),
                   new Point(4, 8),
                   ... };
The Java Virtual Machine will count the number of elements you are placing in the array initially and determine the length of the array accordingly.
 Golf.java
/** Report on a round of golf at St. Andy's. */

public class Golf {
  public static void main(String[] args) {
    int[] pars   = { 4,5,3,4,5,4,4,3,4 };
    int[] scores = { 5,6,3,4,5,3,2,4,3 };
    report(pars, scores);
  }

  /** Reports on a short round of golf. */
  public static void report(int[] pars, int[] scores) {
    for(int i=0; i<scores.length; i++) {
      int hole = i+1;
      int difference = scores[i] - pars[i];
      System.out.println("Hole " + hole + ": " +
                         diffToString(difference));
    }
  }

  /** Convert to English. */

  public static String diffToString(int diff) {
    String[] names = {"Eagle", "Birdie", "Par", "Bogey",
                      "Double Bogey", "Triple Bogey", "Bad"};
    // If diff is -2, return names[0], or "Eagle".
    int offset = 2;
    return(names[offset + diff]);
  }
}
 Golf Output
Prompt> java Golf
Hole 1: Bogey
Hole 2: Bogey
Hole 3: Par
Hole 4: Par
Hole 5: Par
Hole 6: Birdie
Hole 7: Eagle
Hole 8: Bogey
Hole 9: Birdie

Multidimensional Arrays

In the Java programming language, multidimensional arrays are implemented by arrays-of-arrays, just as in C and C++. For instance, the following allocates and fills a 12 x 14 array.
int[][] values = new int[12][14];
for(int i=0; i<12; i++) {
  for(int j=0; j<14; j++) {
    values[i][j] = someFunctionOf(i, j);
  }
}
You can access individual elements as follows:
int someVal = values[i][j]; // i<12, j<14
values[i][j] = someInt;
You can also access entire rows by omitting the second subscript:
int[] someArray = values[i]; // 0<=i<=11
values[i] = someOtherArray;
You can generalize this process to dimensions higher than 2. Also, the internal arrays need not be of the same length. To implement nonrectangular arrays, omit the rightmost size declarations. Here is an example:
String[][] names = new String[3][];
String[] name0 = { "John", "Q.", "Public" };
String[] name1 = { "Jane", "Doe" };
String[] name2 = { "Pele" };
names[0] = name0; // 3 elements
names[1] = name1; // 2 elements
names[2] = name2; // 1 element
The "shorthand" array declaration is legal with multidimensional arrays also:
String[][] altNames = { { "John", "Q.", "Public" },
                        { "Jane", "Doe" },
                        { "Pele" }
                      };

Vectors

Arrays are extremely useful, but they are limited by the fact that they cannot grow or change in size over time. To address this limitation, Java provides a "stretchable" array class: java.util.Vector. It is used for many of the same purposes as linked lists because you can insert or remove elements at any location. Arrays are used for the underlying implementation of Vector. Therefore, it only takes constant time to access a specified location, but takes time proportional to the number of elements contained to insert elements at the beginning or in the middle of the Vector.
Following is a summary of the Vector methods; for an example. Notice that the insertion and retrieval methods return elements of typeObject. This choice makes it difficult, but not impossible, to make vectors that can hold objects only of a particular type and that let you retrieve values without typecasting the return value.

Constructors

public Vector()
public Vector(int initialCapacity)
public Vector(int initialCapacity, int capacityIncrement)
These constructors build an empty Vector. The initial capacity (size of the underlying array) is 10 if not specified, but Java automatically copies the data into a bigger array if more elements are added than the current vector size allows.

Methods

public void addElement(Object object)
public void insertElementAt(Object object, int index)
public void setElementAt(Object object, int index)
These synchronized methods add elements to the Vector. The addElement method inserts at the end; the other two methods use the location specified. With insertElementAt, the objects at and to the right of the specified location are shifted one location to the right. WithsetElementAt, the object at the specified location is replaced.
public int capacity()
This method returns the size of the underlying array, that is, the number of elements the Vector can hold before it will be resized.
public boolean contains(Object object)
The contains method determines whether the Vector contains an object that equals the one specified.
public void copyInto(Object[ ] newArray)
This synchronized method copies the object references into the specified array, in order.
public Object elementAt(int index)
The synchronized elementAt method returns the element at the specified location.
public Enumeration elements()
The java.util.Enumeration class defines an interface used by several enumerable classes. You can use elements to get an Enumerationobject corresponding to the Vector.
public void ensureCapacity(int minimum)
This synchronized method guarantees that the underlying array has at least the specified number of elements.
public Object firstElement()
public Object lastElement()
These synchronized methods return the first and last entry in the Vector, respectively.
public int indexOf(Object object)
public int indexOf(Object object, int startIndex)
public int lastIndexOf(Object object)
public int lastIndexOf(Object object, int startIndex)
These synchronized methods return the leftmost or rightmost index of the element that equals the object specified.
public boolean isEmpty()
This method returns false if the Vector has any elements; true otherwise.
public boolean removeElement(Object object)
public void removeElementAt(int index)
public void removeAllElements()
These synchronized methods let you remove entries from the Vector.
public void setSize(int newSize)
This synchronized method sets a specific size for the Vector. It differs from ensureCapacity in that it will truncate the Vector if the Vector is larger than the specified size.
public int size()
The size method returns the number of elements in the Vector (not the size of the underlying array, which might be larger).
public void trimToSize()
This synchronized method sets the underlying array to be exactly the same size as the current number of elements. You should avoid this method while elements are being added and removed, but it might save memory if the method is used once the Vector elements are fixed.
Many of the Vector methods are synchronized to prevent potential race conditionals as a result of multiple threads accessing the same data. Synchronization does incur a performance hit. Therefore, Java 2 added two unsynchronized classes, similar in function to Vector class: ArrayList and LinkedList. However, these two new classes are only available in JDK 1.2 and later and are not available in most browsers supporting applets. For additional information on synchronization and multithreaded programs, 

8.11 Example: A Simple Binary Tree

This section shows how references and the Vector class can be used to create a binary tree class. This data structure includes a depthFirstSearchmethod, which traverses the tree in depth-first order (staying to the left and going as deep as possible until having to backtrack). Notice that this method is recursive; recursion is natural for depth-first search. The depthFirstSearch method also uses the NodeOperator interface  to generalize the operation that will be performed on each node. This interface lets you change what to do with a tree without modifying the Node class, w. Leaf nodes are implemented as a subclass of Node,  The data structure also includes a breadthFirstSearch method that uses a Vector to build a queue that traverses the tree in breadth-first order (visiting all nodes on a given level before moving on to the next).
Note that many data structures like this have been added as a core part of the language in Java 2. For details, seehttp://java.sun.com/j2se/1.3/docs/guide/collections/. The Java Collections Framework comes with an extensible API for building, manipulating, and iterating over data structures. Implementations of hash tables, growing arrays, doubly linked lists, and balanced binary trees are provided. Although existing classes likeVector and Hashtable provide some of the same functionality, the older classes are explicitly synchronized and therefore possibly slower in certain situations. Collections also provides standard methods for sorting, filling arrays, and binary search that were missing in earlier Java releases.
 Node.java
import java.util.Vector;

/** A data structure representing a node in a binary tree.
 *  It contains a node value and a reference (pointer) to
 *  the left and right subtrees.
 */

public class Node {
  private Object nodeValue;
  private Node leftChild, rightChild;

 /** Build Node with specified value and subtrees. */

  public Node(Object nodeValue, Node leftChild,
              Node rightChild) {
    this.nodeValue = nodeValue;
    this.leftChild = leftChild;
    this.rightChild = rightChild;
  }

  /** Build Node with specified value and L subtree. R child
   *  will be null. If you want both children to be null, use
   *  the Leaf constructor.
   */

  public Node(Object nodeValue, Node leftChild) {
    this(nodeValue, leftChild, null);
  }

  /** Return the value of this node. */

  public Object getNodeValue() {
    return(nodeValue);
  }

  /** Specify the value of this node. */

  public void setNodeValue(Object nodeValue) {
    this.nodeValue = nodeValue;
  }

 /** Return the L subtree. */

  public Node getLeftChild() {
    return(leftChild);
  }

  /** Specify the L subtree. */

  public void setLeftChild(Node leftChild) {
    this.leftChild = leftChild;
  }

  /** Return the R subtree. */

  public Node getRightChild() {
    return(rightChild);
  }

  /** Specify the R subtree. */

  public void setRightChild(Node rightChild) {
    this.rightChild = rightChild;
  }

  /** Traverse the tree in depth-first order, applying
   *  the specified operation to each node along the way.
   */

  public void depthFirstSearch(NodeOperator op) {
    op.operateOn(this);
    if (leftChild != null) {
      leftChild.depthFirstSearch(op);
    }
    if (rightChild != null) {
      rightChild.depthFirstSearch(op);
    }
  }

  /** Traverse the tree in breadth-first order, applying the
   *  specified operation to each node along the way.
   */

  public void breadthFirstSearch(NodeOperator op) {
    Vector nodeQueue = new Vector();
    nodeQueue.addElement(this);
    Node node;
    while(!nodeQueue.isEmpty()) {
      node = (Node)nodeQueue.elementAt(0);
      nodeQueue.removeElementAt(0);
      op.operateOn(node);
      if (node.getLeftChild() != null) {
        nodeQueue.addElement(node.getLeftChild());
      }
      if (node.getRightChild() != null) {
        nodeQueue.addElement(node.getRightChild());
      }
    }
  }
}
NodeOperator.java
/** An interface used in the Node class to ensure that
 *  an object has an operateOn method.
 */

public interface NodeOperator {
  void operateOn(Node node);
}
 Leaf.java
/** Leaf node: a node with no subtrees. */

public class Leaf extends Node {
  public Leaf(Object value) {
    super(value, null, null);
  }
}
Now that we have a general data structure, let's build a specific test case. Figure 1 shows a simple tree; Figure 1. Parse tree for "Java hackers hack Java."
graphics/08fig01.gif
 
 TreeTest.java
/** A NodeOperator that prints each node. */

class PrintOperator implements NodeOperator {
  public void operateOn(Node node) {
    System.out.println(node.getNodeValue());
  }
}

/** A sample tree representing a parse tree of
 *  the sentence "Java hackers hack Java", using
 *  some simple context-free grammar.
 */

public class TreeTest {
  public static void main(String[] args) {
    Node adjective =
      new Node("  Adjective", new Leaf("   Java"));
    Node noun1 =
      new Node("  Noun", new Leaf("   hackers"));
    Node verb =
      new Node("  TransitiveVerb", new Leaf("   hack"));
    Node noun2 =
      new Node("  Noun", new Leaf("   Java"));
    Node np = new Node(" NounPhrase", adjective, noun1);
    Node vp = new Node(" VerbPhrase", verb, noun2);
    Node sentence = new Node("Sentence", np, vp);
    PrintOperator printOp = new PrintOperator();
    System.out.println("Depth first traversal:");
    sentence.depthFirstSearch(printOp);
    System.out.println("\nBreadth first traversal:");
    sentence.breadthFirstSearch(printOp);
  }
}
 TreeTest Output
Prompt> java TreeTest
Depth first traversal:
Sentence
 NounPhrase
  Adjective
   Java
  Noun
   hackers
 VerbPhrase
  TransitiveVerb
   hack
  Noun
   Java

Breadth first traversal:
Sentence
 NounPhrase
 VerbPhrase
  Adjective
  Noun
  TransitiveVerb
  Noun
   Java
   hackers
   hack
   Java



 Exceptions

The Java programming language has a very nice error-handling system: exceptions. Exceptions can be "thrown" (generated) in one block of code and "caught" (handled) in an outer block or in a method that called the current one. Java exceptions differ from C++ exceptions in two major ways. The first major difference is that the exception-handling construct (try/catch) has a finally clause that always gets executed, regardless of whether or not an exception was thrown. The second significant difference is that you can require users of your methods to handle exceptions your methods generate; if they fail to do that, their code will not compile.

Basic Form

The simplest form of exception handling is a block of the following form:
try {
  statement1;
  statement2;
  ...
} catch(SomeException someVar) {
  handleTheException(someVar);
}
For example, the constructor for java.net.URL potentially generates a java.net.MalformedURLException, and the readLine method ofjava.io.BufferedReader potentially generates a java.io.IOException


import java.net.*; // For URL, MalformedURLException
import java.io.*;  // For BufferedReader

/** A small class to demonstrate try/catch blocks. */

public class URLTest {
  public static void main(String[] args) {
    URLTest test = new URLTest();
    test.getURL();
    test.printURL();
  }

  private URL url = null;

  /** Read a string from user and create a URL from it. If
   *  reading fails, give up and report error. If reading
   *  succeeds but URL is illegal, try again.
   */

  public URL getURL() {
    if (url != null) {
      return(url);
    }
    System.out.print("Enter URL: ");
    System.out.flush();
    BufferedReader in = new BufferedReader(
                          new InputStreamReader(System.in));
    String urlString;
    try {
      urlString = in.readLine();
    } catch(IOException ioe) {
      System.out.println("IOError when reading input: " + ioe);
      ioe.printStackTrace(); // Show stack dump.
      return(null);
    }
    try {
      url = new URL(urlString);
    } catch(MalformedURLException mue) {
      System.out.println(urlString + " is not valid.\n" +
                         "Try again.");
      getURL();
    }
    return(url);
  }

  /** Print info on URL. */

  public void printURL() {
    if (url == null) {
      System.out.println("No URL.");
    } else {
      String protocol = url.getProtocol();
      String host = url.getHost();
      int port = url.getPort();
      if (protocol.equals("http") && (port == -1)) {
        port = 80;
      }
      String file = url.getFile();
      System.out.println("Protocol: " + protocol +
                         "\nHost: " + host +
                         "\nPort: " + port +
                         "\nFile: " + file);
    }
  }
}
URLTest Output
> java URLTest
> Enter URL: http://java.sun.com/ConvertingToActiveX.html
Protocol: http
Host: java.sun.com
Port: 80
File: /ConvertingToActiveX.html
Note the use of the printStackTrace method in getURL. This shows the method call stack at the point the exception occurred. In many implementations, it even includes line numbers in the source files. This is such a useful debugging tool that it is sometimes used even when no exceptions are generated. For instance, the following simply prints a stack dump:
new Throwable().printStackTrace();

Multiple Catch Clauses

A single try can have more than one catch. If an exception is generated, Java executes the first catch clause that matches the type of exception thrown. Since exceptions can be created hierarchically like other Java classes, you must catch a more specific exception before a more general one. For instance, although the getURL method could be simplified to use a single try block with two catch clauses , the order of the catch clauses needs to be reversed since a MalformedURLException is actually a subclass of IOException.


 
If you have multiple catch clauses, you must order them from the most specific to the most general.
Simplified getURL Method
public URL getURL() {
  if (url != null) {
    return(url);
  }
  System.out.print("Enter URL: ");
  System.out.flush();
  BufferedReader in = new BufferedReader(
                        new InputStreamReader(System.in));
  String urlString = null;
  try {
    urlString = in.readLine();
    url = new URL(urlString);
  } catch(MalformedURLException mue) {
    System.out.println(urlString + " is not valid.\n" +
                      "Try again.");
    getURL();
  } catch(IOException ioe) {
    System.out.println("IOError when reading input: " + ioe);
    ioe.printStackTrace(); // Show stack dump
    return(null);
  }
  return(url);
}

The Finally Clause

After the last catch clause, you are permitted a finally clause that always gets executed, regardless of whether or not exceptions are thrown. It is executed even if breakcontinue, or return is used within the try or catch clauses. 

 Further Simplified getURL Method
public URL getURL() {
  if (url != null) {
    return(url);
  }
  System.out.print("Enter URL: ");
  System.out.flush();
  BufferedReader in = new BufferedReader(
                        new InputStreamReader(System.in));
  String urlString = null;
  try {
    urlString = in.readLine();
    url = new URL(urlString);
  } catch(MalformedURLException mue) {
    System.out.println(urlString + " is not valid.\n" +
                       "Try again.");
    getURL();
  } catch(IOException ioe) {
    System.out.println("IOError when reading input: " + ioe);
    ioe.printStackTrace(); // Can skip return(null) now
  } finally {
    return(url);
  }
}

Thrown Exceptions

If you write a method that potentially generates one or more exceptions and you don't handle them explicitly, you need to declare them with the throwsconstruct, as follows:
public SomeType someMethod(...) throws SomeException {
or
public SomeType someMethod(...)
       throws ExceptionType1, ExceptionType2 {
This declaration lets you do two things. First, it permits you to write methods that have enforced safety checking; users are required to handle the exception when calling the methods. Second, it permits you to postpone exception handling to a method higher in the method call chain by declaring them in the method declaration but ignoring them in the method body.
If you want to explicitly generate an exception, use the throw construct as illustrated:
throw new IOException("Blocked by firewall");
throw new MalformedURLException(
            "Invalid protocol: telephone");
Using throw is more common with exceptions you define yourself. You can make your own exception classes by subclassing any of the existing exception types.
 NegativeLengthException.java
import java.io.*;

public class NegativeLengthException extends Exception {

  /** Test NegativeLengthException */

  public static void main(String[] args) {
    try {
      int lineLength = readLength();
      for(int i=0; i<lineLength; i++) {
        System.out.print("*");
      }
      System.out.println();
    } catch (NegativeLengthException nle) {
      System.out.println("NegativeLengthException: " +
                         nle.getMessage());
    }
  }

  public NegativeLengthException() {
    super("Negative dimensions not permitted.");
  }

  public NegativeLengthException(String message) {
    super(message);
  }
  // readLength catches IOExceptions locally but lets the
  // calling method handle NegativeLengthExceptions.
  private static int readLength() throws NegativeLengthException {
    BufferedReader in = new BufferedReader(
                          new InputStreamReader(System.in));
    System.out.print("Enter length: ");
    System.out.flush();
    int len = 0;
    try {
      String line = in.readLine();
      len = Integer.parseInt(line);
      if (len < 0) {
        throw new NegativeLengthException();
      }
    } catch (IOException ioe) {
      System.out.println("Problem reading from keyboard");
    }
    return(len);
  }
}
 Throwing NegativeLengthExceptions
> java NegativeLengthException
> Enter length: 4
****

> java NegativeLengthException
> Enter length: -345
NegativeLengthException: Negative dimensions not permitted.

Unchecked Exceptions

The exceptions discussed so far have been checked exceptions; exceptions that you are required to handle. Java also includes two classes of unchecked exceptions: Error and RuntimeException. You are permitted to handle these exceptions but are not required to, since the number of places from which they could be generated is too large. For instance, members of the Error class include OutOfMemoryError (e.g., array allocation or call to new failed because of insufficient memory) and ClassFormatError (e.g., a .class file in illegal format, perhaps because text mode instead of binary mode was used when the file was FTP'd).
The RuntimeException subclasses include ArithmeticException (e.g., an integer division-by-zero) and ArrayIndexOutOfBoundsException(e.g., you forgot to bound a loop at the array's length). A catch-all RuntimeException often extended in user code is IllegalArgumentException. This exception lets you create hooks in your code for the handling of unusual cases without requiring users to catch the exceptions.

Post a Comment

Copyright © Rough Record. Designed by OddThemes