Bristle Software Java Tips

This page is offered as a service of Bristle Software, Inc.  New tips are sent to an associated mailing list when they are posted here.  Please send comments, corrections, any tips you'd like to contribute, or requests to be added to the mailing list, to tips@bristle.com.

Table of Contents:

  1. Differences from C++
  2. Java Versions
    1. Java SE 6.0
  3. Getting Started
    1. Applications
    2. Applets
    3. Servlets
    4. JSP - JavaServer Pages
    5. Java Beans
    6. JDBC - Java Database Connectivity
    7. Javadoc - Generating documentation automatically
    8. EJB - Enterprise Java Beans
  4. Quick Reference
    1. Operators
    2. Literals
    3. Magic Code
    4. JVM Command Line Options
  5. Casts
  6. Overflow
  7. Containers
    1. Arrays vs. Containers
    2. Type-Specific Containers
    3. Inheriting from Containers
    4. Creating hash key classes
    5. Java 1.0 Containers vs Java 2 Containers
  8. Scope of Classes
  9. Multiple Implementation Inheritance
  10. Exceptions
    1. Declaring Exceptions
    2. Catch all exceptions with catch (Throwable t)
    3. Querying Exception Info
    4. Propagating and Re-Throwing Exceptions
  11. RTTI -- Run-Time Type Identification
    1. Original RTTI
    2. Reflection
  12. Interaction with the Host Environment
  13. Web Programming
    1. Reading from a URL
  14. Efficiency
    1. System.currentTimeMillis -- Simplistic Execution Timing
    2. System.arraycopy -- Copying arrays
    3. Arrays.equals -- Comparing arrays
  15. Javadoc
    1. Default Javadoc Behavior
    2. Javadoc Comments
    3. Javadoc Tags
    4. Javadoc Command Line Interface
    5. Javadoc Formatting
    6. Javadoc Example
    7. Bristle Java Library Javadocs
    8. Overriding Javadoc Behavior
  16. JSP - JavaServer Pages
    1. JSP Intro
    2. JSP Directives
    3. JSP Scripting Elements and Other Syntax
    4. JSP/JSTL Actions
    5. JSP/JSTL Implicit Objects
    6. JSP/JSTL EL Syntax
    7. Accessing Properties of Objects in JSP and JSP/JSTL EL
    8. JSP/JSTL EL Convenience Objects
    9. Enabling EL Expression Evaluation
    10. Looping Through Cookies in JSP and JSP/JSTL EL
    11. Looping Through Parameters in JSP and JSP/JSTL EL
    12. Looping Through Headers in JSP and JSP/JSTL EL
    13. Avoiding "code too large" errors
  17. Finding JAR Files
  18. Why Teach Java?
  19. Easing Into Java
  20. See Also

Details of Tips:

  1. Differences from C++

    Last Updated: 9/5/2000
    Applies to:  Java 1.0+

    Here are some of the differences between Java and C++:

    1. Compiler/Interpreter Features

      1. Interpreted, not compiled

        Java is interpreted, not compiled.  Therefore, it is somewhat slower than C++, but since Java interpreters are available for all (almost all?) browsers, operating systems, and other platforms, it is very portable.  The Java "compiler" compiles the Java source code to "bytecodes" which are interpreted at runtime.  Most traditional compile-time errors (type mismatches, undeclared variables, etc.) are caught at compile time.

      2. No preprocessor

        Java has no equivalent of the C/C++ preprocessor.  This has the following ramifications:

        1. No #include

          Java has no #include statement.  You can refer to classes in other files of the same package directly.  You can refer to classes in other packages via their fully qualified names (or use import).  

        2. Class names = file names

          Since Java has no #include, but still needs to find classes in other files, class names must exactly match disk file names (including case), and package names must exactly match disk directory names. 

        3. No #define

          Java has no macros.  Use methods (functions) instead of parameterized macros.  Use final variables for constants.  See "final" vs "const" for more details.

        4. No #if or #ifdef

          Java has no conditional compilation.

      3. No forward declarations needed

        Java uses a 2 pass compiler, which means that it reads the entire file once, then goes back again to resolve references.  In C/C++, you must order your classes and functions in a source file with all called ones before any that call them, or use forward declarations (function prototypes and incomplete class declarations).  This is not necessary in Java.

      4. No header files or function prototypes.

        C/C++ has header files (.H files) that contain class declarations, function prototypes, constants, etc., but not class and function implementations.  These files serve two purposes:  to be read by the compiler, and to be read by the programmer as documentation of the interfaces to the classes and functions.  Java uses no header files.  Classes and members are declared in source files that also contain the implementations.  The Java compiler doesn't need the header files, and the Java programmer uses the javadoc tool or a class browser to extract documentation.

      5. Introspection

        Like all interpreted languages, Java has traditional compile-time info available to it at runtime.  It allows you to query such info programmatically.   For example, at runtime, you can determine the class name of an object, what methods it has, etc.  See Introspection/Reflection for more details.


    2. Data Types

      1. Standardized sizes of numeric types.

        Each numeric data type in Java has a fixed number of bits regardless of the operating system or other platform:

        boolean (Size not specified, but only 2 values supported:  true, false)
        char 16 (Unicode)
        byte 8
        short 16
        int 32
        long 64
        float 32
        double 64
        void N/A

         

      2. No sizeof

        Java has no sizeof operator.  In C/C++, you need sizeof to determine the size of the primitive types, which have standard known sizes in Java.  In C/C++, you also need sizeof to read/write structs and classes to persistent storage.  Java offers "lightweight persistence" through "object serialization", which uses "introspection" internally to determine the sizes of the objects.  More details in the tips below.

      3. No unsigned types

        Java has no unsigned numeric data types (except for char which is an unsigned 16-bit integer).

      4. Explicit boolean data type

        Java has an explicit boolean data type and 2 boolean values: true and false.  It does not allow you to treat integers, pointers, etc. as booleans.  However, you can explicitly cast the integers 1 and 0 to true and false.  Also, Java converts the boolean data type (and all other data types) to string as needed.  Java can catch common C/C++ errors like:
                while (x = y)     // should be while (x == y)
        automatically.

        Note:  As James Higgins points out, C++ has recently added a bool data type, but it is not yet implemented by all compilers, and many places in the language (if, while, the ?: operator, etc.) still tolerate non-bool expressions.

      5. No structs, unions, or typedefs

        Java has no structs, unions, or typedefs.  Everything except the primitive data types is an object -- an instance of a class.

      6. Built-in String data type

        Java has a built-in String class.  It is a full-fledged class, not simply a C/C++ style null-terminated array of characters.  Methods of the String class include: length(), substring(), indexOf(), charAt(), compareTo(), etc.

        Note:  As James Higgins points out, the STL (Standard Template Library) of C++ now includes a standard String class.  However, much C++ code pre-dates the STL and still uses char* or home-grown String classes.

    3. "final" vs "const"

      C++ uses the keyword const for a variety of purposes.  The Java keyword final is similar in some cases, but not all.

      1. const/final variable

        C++ uses const to say that a variable or data member cannot change.  Java uses final for variables and data members of primitive data types.

      2. const/final pointer

        C++ uses const to say that a pointer cannot change.  Java doesn't have pointers, but uses final to say that an object declaration (which holds a reference to an object since objects are always allocated on the heap, not the stack) cannot be changed to refer to a different object instance.

      3. const heap variable

        C++ uses const to say that the storage space pointed to by a pointer cannot be changed by code that accesses the storage space via the pointer.  However, the storage space can still be changed via another pointer.  Also, the const attribute of the pointer can be "cast away" via a cast operation, so that the same pointer can be used to update the storage space. 

        Java offers no such feature.  To achieve a similar effect, you can create a class with access specifiers that prevent its members from being updated.  For a really good discussion of this technique, including how it is used by the standard String and StringBuffer classes of Java, see Appendix A "Passing & Returning Objects" of [Eckel00].

      4. const/final argument

        C++ uses const to say that an argument of a function is not changed by the function.   Java uses final.

      5. const method

        C++ uses const to say that a member function does not change any of the data members of the class.  Java has no equivalent.

      6. final method

        Java uses final to say that a method cannot be overridden in any subclass.  C++ has no equivalent.  In Java, this also allows the method to be early bound (like a non-virtual method in C++).

      7. final class

        Java uses final to say that a class cannot be subclassed.  C++ has no equivalent keyword, though you can accomplish the same thing in C++ (and in Java) by making all constructors of the class private.

      8. blank final

        Java 1.1 allows a variable to be declared final without being initialized at the declaration.  A value must be provided in every constructor.

    4. Memory Management

      1. No explicit pointers

        Java has no explicit pointers.  The data type of every variable is either a primitive (boolean, char, byte, short, ...) or a class.  When the data type is a class, the variable holds a reference to an instance, not an actual instance.

      2. All objects on heap

        Only primitives and object references are stored on the stack.  All objects are dynamically allocated on the heap.  No primitives are on the heap, except as part of a class or array.

      3. Garbage Collection vs. "delete"

        Java has no "delete" function.  The memory for all dynamically allocated heap objects is reclaimed automatically by the garbage collector.  This means you can easily pass arrays, buffers, etc. into and out of functions without worrying about memory management.

      4. C++ "references"

        Unlike C++ "references", Java "references" can be changed at runtime to point to a different object.  However, declaring a Java object variable or parameter (which are both object references) as final prevents this.

    5. Arrays

      1. Array range-checking

        Java does not let you index off the end of an array like C++.

      2. Array length member

        Java arrays have a length member to return the current length of the array.

      3. Array initialization

        Java arrays are automatically initialized to empty values like zero (numeric), false (boolean), etc. when allocated.

      4. Arrays are objects

        Java arrays are objects, not just linear blocks of storage space.  Like all Java object variables, array variables hold a reference (pointer) to the array contents, not the contents themselves.  Therefore, you cannot declare an array to have a specific size (though you can specify the size of an array instance that you assign to the array variable).  Also, you cannot do the C/C++ style tricks of keeping a pointer into the middle of an array.  You can index into an array, but cannot do pointer arithmetic.

    6. Operators

      1. Shift operators are different

        In Java, char, byte, and short variables are promoted to int before being shifted.  Only the 5 low order bits of the right hand operand are used as the shift bit counter (0-31) when shifting int variables (or those promoted to int).   Similarly, only the 6 low order bits of the right hand operand are used as the shift bit counter (0-63) when shifting long variables.

      2. No comma operator

        Java has no equivalent of the C/C++ comma operator.  However, it does explicitly support one of the most common uses of the comma operator -- it allows multiple statements in the initialization and update portions of a for loop, as:
        	for (i = 1, j = 1; i < 10; i++, j++) {...}
      3. String concatenation

        The Java plus operator (+) can be used to concatenate strings, and is internally overloaded to convert other operands to strings as necessary when concatenating.

    7. Statements

      1. No goto

        Java has no goto statement.  Most uses you would have had for it are handled by C/C++ style break, continue, and return, along with the new Java finally clause.

    8. Subroutines/Functions/Methods

      1. Parameters passed by reference

        In C, all parameters are passed by value.  To achieve the effect of pass by reference, you use ampersand (&) to explicitly pass the value of the address of the argument.  The one exception to this is arrays (which includes strings -- arrays of characters) which are passed by reference. 

        In C++, you have an additional option.  You can use ampersand (&) on the function declaration to cause a parameter to be always passed by reference.   Otherwise, parameters are passed as in C.  You can further use const to cause the parameter to be passed by reference but preventing the function from updating the parameter (unless the function "casts away the const-ness").  (Thanks to James Higgins for reminding me of the C++ references.  I must have been sleep-typing when I wrote the first cut at this tip -- left it out completely.)

        In Java, primitives (int, boolean, char, long, etc.) are passed by value, but all objects (including arrays) are passed by reference.

      2. No variable length argument lists

        C/C++ has a "..." syntax to support variable numbers of arguments.  This does not exist in Java.  To accomplish a similar effect, pass an array of Object (the ancestor of all classes) and use RTTI (run-time type identification) inside the method to determine the actual types of the array elements.

      3. No default argument values

        Java does not support default argument values.  You must explicitly pass a value for each argument when calling a method.

      4. Command line arguments

        Similar to C/C++, Java receives command line arguments as elements of an array of strings passed to the main() method.  In C/C++, the 0th element of the array is the name of the program and the 1st element is the first command line argument.  In Java, the 0th element is the first argument.

    9. Scope/Nesting/Access

      1. No global variables or functions

        Java has no global variables or functions.  You can create static members of a global class as a workaround.

      2. No hiding variables via nested blocks

        In C++, you can declare variables of the same name in nested blocks and have the inner one hide the outer one, as:
                {
                    int i = 1;
                    {
                        int i = 2;
                    }
                }

        Java does not allow this.  However, it does allow the following where the inner variable goes out of scope before the outer variable is declared:

                {
                    {
                        int i = 2;
                    }
                    int i = 1;
                }
        
      3. Access specifiers apply to only one declaration each

        Like C++, Java has access specifiers public, private, and protected.  In C++, the specifier applies to all member declarations until the next access specifier or the end of the class.  In Java, the access specifier must be repeated for each member declaration.

      4. Default access to class member

        In addition to the C++ access specifiers public, private, and protected, Java has a default access commonly referred to as "package" access.  Any member without an explicit access specifier is visible to all classes in the same Java package.  Also, for some reason, protected access implies "package" access -- all protected members are available not only to subclasses, but also to all other classes in the package.  There was originally a way to prevent this by specifying private protected as the access specifier, but this has been removed from the language.  Anyone know why?

      5. Packages/Namespaces

        Java uses packages instead of namespaces.  The package hierarchy must exactly match the directory tree (including case).  You should use your domain name in reverse order (for example, use /com/mycompany if your domain name is mycompany.com), as the root of the directory tree containing your classes.

      6. No "::" scope resolution operator

        Java has no "::" scope resolution operator.  Use dot notation for static members, as:
            ClassName.method
            objectName.method

      7. No "virtual" keyword required for dynamic binding

        In C++ all methods use "early binding" by default; you must specify the "virtual" keyword to cause "late binding" (aka "dynamic binding").  In Java, all methods use dynamic binding, except those that cannot be overridden because you specified the "final" keyword.  Thus, unlike C++, there is never any difference between the following calls where ParentClass is the parent of ChildClass:
                ParentClass.method1()
                ChildClass.method1()

        In C++, these 2 calls would invoke different implementations of method1 if it was not defined as a virtual method, and was implemented by both classes.

      8. No operator overloading

        In Java, you can overload methods, but not operators.

    10. Inheritance

      1. All objects inherit from Object

        In Java, all objects inherit from the Object class.  Like Smalltalk and other object-oriented languages, there is a single inheritance tree.  C++ supports a forest of trees, with no enforced single root class.

      2. super keyword

        In C++, to refer to a member of a parent class that has the same name as a member of the current class, you must repeat the name of the parent class as:
                MyParent::member1

        Java uses the keyword super for this as:

                super.member1
        
      3. Calling parent constructors

        In both C++ and Java, each subclass constructor automatically calls the default (parameterless) base class constructor.  In both languages, you can explicitly call a different base class constructor instead (one with parameters) from the subclass constructor.  In C++ you do this with a "constructor initializer" clause as:
                class MySubClass : public MyBaseClass
                {
                    MySubClass (char* s) : MyBaseClass(s)
                    {
                        ...
                    }
                };

        In Java, you call the base class constructor via the super keyword as:

                class MySubClass extends MyBaseClass
                {
                    MySubClass (String s)
                    {
                        super (s);
                        ...
                    }
                }

        The call to super must be the very first thing in the subclass constructor.  It can't even be nested inside a try block to catch exceptions.

      4. Methods in subclass don't hide all same-named methods in base class.

        In C++, if you declare a method A in a subclass, it hides all methods named A in the parent class, regardless of their signatures.  In Java, only the method with the same signature is hidden.

      5. Explicit "abstract" class

        An "abstract" class is a class which has no implementation.  You cannot create instances of an abstract class; only instances of its non-abstract subclasses.   In C++, a class becomes abstract implicitly if it contains at least one "pure virtual" method (a method with "= 0" in place of the method body).  In Java, there is an explicit abstract keyword.  You can explicitly declare a method to be abstract.  You can also explicity declare the entire class to be abstract, which you must do if it contains at least one abstract method.

      6. Bodies of abstract methods

        In Java, as in C++, you can provide a body (implementation) of an abstract method.   Because the method is abstract, all subclasses are forced to override the method.   However, the code in the overriding methods can still explicitly call the abstract method.

      7. Explicit interface classes

        In C++, you can effectively make a class into an interface with no implementation, by making all methods into pure virtual methods and including no non-const data members.   In Java, you can be more explicit, using the interface keyword in place of the class keyword.

      8. No multiple implementation inheritance

        C++ allows a class to inherit the implementation of multiple base classes, as:
                class MySubClass : public MyBaseClass1, 
                                   public MyBaseClass2
                { ... };

        Java allows implementation inheritance from only one base class:

                class MySubClass extends MyBaseClass { ... }

        However, you can accomplish a similar effect via inner classes, as described in Multiple Implementation Inheritance.

      9. Multiple interface inheritance by a class

        In addition to one implementation, Java allows a class to inherit multiple interfaces via the implements keyword, as:
                class MyBaseClass { ... }
                interface Interface1 { ... }
                interface Interface2 { ... }
                interface Interface3 { ... }
                class MySubClass extends MyBaseClass
                                 implements Interface1, 
                                            Interface2, 
                                            Interface3
                { ... }

        In this case, MySubClass automatically inherits the implementation of the methods in MyBaseClass.  However, it inherits only the interfaces of Interface1, Interface2, and Interface3 -- it must explicitly provide an implementation of each method declared in Interface1, Interface2, and Interface3, though these implementations can also be inherited from MyBaseClass.

      10. Multiple interface inheritance by an interface

        Java allows interfaces (but not classes) to inherit multiple interfaces via the extends keyword, as:
                interface Interface1 { ... }
                interface Interface2 { ... }
                interface Interface3 { ... }
                interface MyInterface extends Interface1, 
                                              Interface2, 
                                              Interface3
                { ... }

        In this case, MyInterface is still an interface, and so provides no implementation of any methods.  However, any class that inherits MyInterface is required to provide implementations of all methods from Interface1, Interface2, and Interface3.

      11. No private or protected inheritance

        In C++, you can inherit from a base class in any of 3 modes:  public, private, protected.  The syntax is:
                class MySubClass : public    MyBaseClass { ... }
                class MySubClass : private   MyBaseClass { ... }
                class MySubClass : protected MyBaseClass { ... }

        Java offers only public inheritance.  The syntax is:

                class MySubClass extends MyBaseClass { ... }
      12. Can't restrict visibility via inheritance

        In Java, you cannot restrict the visibility of a class member via inheritance.  In C++, for example, you can define a method as public, but subclasses can restrict it to protected or private.  In Java, this is not allowed.  Public methods and data members of a parent class can be overridden, but must be at least as visible in the child class as in the parent.

        To accomplish this effect in Java, you must use composition and delegation instead of inheritance.  You create an instance of the "parent" class inside of the "child" class, and write stubs for all the methods you want to make visible, with each stub explicitly calling the corresponding method of the "parent" class.

    11. Enums

      C++ allows you to define a set of related constants as an enum (enumerated type).  In Java, use a class containing data members, as:
              public class Colors 
              {
                public final static int RED = 1;
                public final static int GREEN = 2;
                public final static int BLUE = 3;
              }

      Note:  An earlier version of this tip recommended using an interface instead of a class.   This requires less typing, since all data members of an interface are automatically public, final, and static.  However, as Ken Swanson and Alex Blakemore pointed out, you can't declare variables of an interface type.  Therefore, the class approach is better.

    12. Initialization

      1. Guaranteed initialization

        In C/C++, variables are not necessarily initialized to any predictable value.  When you declare a variable on the stack or allocate one from the heap, it's initial value is likely to be whatever was left at that location in memory by the previous variable or code segment that resided there.  It is a common mistake to use an uninitialized value in a computation or as a pointer.  Such mistakes are hard to debug, because they may cause mysterious and intermittent problems in parts of the code that seem unrelated to the uninitialized variable.  For example, if a pointer is not initialized, but happens to contain a value that is the address of another variable, any attempt to increment the variable it was intended to point to will increment the other variable instead, reporting no error.

        In Java, all member variables of classes and all elements of arrays are automatically initialized to empty values like zero (numeric), false (boolean), etc. when allocated.  Local variables (declared inside a method) are not initialized, but any attempt to use an uninitialized variable is caught at runtime.

      2. Data member initialization clauses

        Java allows you to initialize a member variable at the point of its declaration: 
            class MyClass
            {
                int      i   = 0;
                MyObject obj = new MyObject(57);
            }

        C++ does not allow this.  It requires you to initialize the variable with a separate statement in the class constructor, which is typically in a different file from the class declaration.

      3. Data member initialization blocks

        For cases where the initial value is not so simple, Java allows you to embed an explicit block of initialization code among your member variable declarations, as:

            int i = 0;
            int j = 29;
            int k;
            {
                if (i < j) k = j;
                else k = i;
            }

        This code is executed for each instance of the class before the constructor is executed.  C++ does not offer such a feature.  Such code would have to occur in the class constructor.

      4. Static data member initialization clauses

        As with non-static data members, Java allows you to initialize a static member variable at the point of its declaration: 
            static int      i   = 0;
            static MyObject obj = new MyObject(57);

        C++ does not allow this.  It requires you to use a "static member initializer" statement.  Such a statement cannot occur inside the class declaration, or the class constructor or any other method.  It is typically in a separate file with the bodies of the constructors and other methods of the class.   For example, the C++ static data member declarations in the .H file might look like:

            class MyClass
            {
                static int      i;
                static MyObject obj;
            }

        and the separate static member initializer statements in the .CPP file might look like:

            int      MyClass::i   = 0;
            MyObject MyClass::obj = new MyObject(57);
      5. Static data member initialization blocks

        As with non-static data members, Java allows you to embed an explicit block of initialization code among your static member variable declarations, as: 

            static int i = 0;
            static int j = 29;
            static int k;
            static
            {
                if (i < j) k = j;
                else k = i;
            }

        As with the static data member initialization clauses, this code is executed once for the entire class, not once per instance.  It executes before any instance of the class is created and before the static data member is accessed. 

        C++ does not offer such a feature.  Such code would have to occur in a separate function called by the C++ "static member initializer" statement.  Putting such code in the C++ constructor doesn't work because the constructor can be called too often (once per instance), too late (after the static data member is accessed), or not at all (if the static members and methods of a class are used, but no instance is ever created).  The Java technique deals with all of these possibilities.

    13. Inner/nested/local classes

      A Java "inner" class can access the private and protected members of the enclosing class.  This is not true of C++ "nested" classes, which have no special access to the internals of the enclosing class.  Also, C++ nested and "local" classes cannot be anonymous, or declared inside of expressions, like Java inner classes.  See Multiple Implementation Inheritance for an example of an anonymous inner class declared in an expression.

    14. No destructors

      Each C++ class can have a "destructor" method, named with the class name preceded by a tilda ("~").  The destructor of the class (and those of all ancestor classes in reverse order) are executed automatically.  They are executed for an automatic variable (variable declared inside a function or method and allocated on the stack) when the variable goes out of scope, and for a dynamically allocated variable (allocated on the heap via new) when the variable is explicitly deallocated via delete

      Java does not have destructors.  The finalize() method is not a destructor.  It runs when the garbage collector reclaims the space, which may be never.

    15. Exceptions

      1. Exception specifications on methods

        In C++, you can use a "throw" clause on a function to list all exceptions thrown by the function.  Any attempt by a function to throw an exception not listed in its throw clause is caught at runtime.  However, the throw clause is optional -- a function with no throw clause can throw any exception.  In Java, the corresponding throws clause is not optional, and all checking is done at compile time.  (If you need to bypass the checking, throw an exception derived from the Throwable class, but not the Exception class.)

      2. Object types thrown

        In C++, you can throw any type of object (int, char*, class, etc.).  In Java, you can only throw objects derived from the Throwable class.  Therefore, all exception handlers can use the methods of the Throwable class (getMessage(), toString(), printStackTrace(), etc.).  See Querying Exception Info for an example.

    16. "finally" clause

      One of the most useful features of Java is the finally clause.  How many times have you gone to huge amounts of trouble to ensure that all exit paths from a function get funneled through a common stretch of code to clean things up?  The simplest example is in user interface code where you set the mouse pointer to an hourglass, then perform a series of error-prone operations like accessing a database, then change the mouse pointer back to an arrow.  If you have multiple explicit returns from the function, you have to remember to reset the mouse pointer at each one.   Also, you have to catch all exceptions that can occur in the function or any other functions that it calls, resetting the mouse pointer, and then handling or re-raising the error.  Common workarounds involve using goto to jump to a common exit point, or calling a common cleanup routine at each exit point.  Yuck!  A more sophisticated (but still tedious) workaround involves allocating a local object whose sole purpose in life is to perform the cleanup code when it goes out of scope (during its destructor).  Still yuck!

      Java is the first language I've seen that explicitly deals with this problem.  It extends the try ... catch syntax to include a finally clause.  For example: 
          try
          {
              SetMousePointer();
              DoSomeRiskyStuff();
          }
          catch (Exception e)
          {
              DealWithErrors();
          }
          finally
          {
              ResetMousePointer();
          }

      The code in the finally clause is guaranteed to be executed.  If the code in the try block runs to completion, it executes after the code in the try block.  If the try block contains a return statement, it executes just before control is returned to the caller.  If an exception occurs in the try block, it executes after the local handler (if any) that catches the exception.  If an unhandled exception occurs, or a handled exception is re-thrown, it executes just before the exception is propagated to the caller.  It can be used with or without a catch clause, but requires a try block.

    17. Introspection/Reflection

      Java classes are "introspective".  That is, you can call the getClass() method of any class to get an instance of a Class object that contains information about the class.  Via the Class object, you can get the name of the class, name of the parent, name of the enclosing class (if an inner class), lists of constructors, fields, methods, interfaces implemented, the enclosing package, etc.  Thus, it is extraordinarily easy to write your own Java class browser in Java.

      Java 1.1 supports a feature called "reflection", implemented by enhancements to the Class object and the addition of the Java 1.1 java.reflect package.  Rather than just getting the items listed above as strings, you can get them as objects of type Class, Constructor, Field, Method, Package, etc.  Then you can use the get() and set() methods of Field to access the fields of the class, use the invoke() method of Method to invoke the methods, etc. 

      You can also use the forName() method of the Class object to get the Class object of a class if you have only its name, not an instance.  Thus, you don't need an instance of a class to get started.  Finally, you can call the newInstance() method to create an instance of a class from its corresponding Class object.  Thus it is also very easy to write a Java class loader in Java.

    18. No templates (yet!)

      Java doesn't have templates, though there are efforts underway to add them to the language.

    19. Multi-threading support
      1. Thread class
      2. synchronized keyword
      3. volatile keyword

    20. Object Serialization

    21. Lightweight persistence

    22. Javadoc

    23. Coding conventions
      1. Package names lowercase
      2. Class names mixed case
      3. Member names mixed case w/initial lowercase
      4. Constants (static final variables initialized with constant values at compile time) in all uppercase.
      5. See http://java.sun.com/docs/codeconv/index.html

    24. Different class library

      Java and C++ have entirely different class libraries.
      1. Different I/O routines
      2. Tokenizing support for simplistic parsing of strings and files.
      3. Compression support (ZIP, GZIP, etc.)
    25. --Fred

  2. Java Versions

    1. Java SE 6.0

      Last Updated: 2/22/2007
      Applies to:  Java 6.0+

      Java SE 6.0 was released in December 2006.  For a summary of new features, see:

          http://java.sun.com/developer/technicalArticles/J2SE/Desktop/javase6/beta2.html
          An article by Danny Coward, the lead developer.

          http://java.sun.com/javase/6/features.jsp
          The key features list at the Sun Web site.

          http://jcp.org/aboutJava/communityprocess/final/jsr270/index.html
          The official specification of the final release contents.

      --Fred

  3. Getting Started

    1. Applications

      Last Updated: 10/13/2000
      Applies to:  Java 1.0+

      Here is a simple Java console application:

      	class App1
      	{
      	    public static void main(String[] args)
      	    {
              	System.out.println("Hello World!");
      	    }
      	}

      It must reside in a file named exactly App1.java (case sensitive) to match the class name.  It can be compiled (using the Sun JDK compiler, available for free download at http://java.sun.com) as:

      	javac App1.java

      and invoked from the command line as:

      	java App1

      Like C/C++ programs, Java console applications always begin with the main() method.  They can accept command line arguments, read from standard input, write to standard output, return a status code to the command line processor, read/write files, etc.

      --Fred

    2. Applets

      Original Version: 10/13/2000
      Last Updated: 2/5/2006
      Applies to:  Java 1.0+

      A Java applet is a Java class that runs in the context of an applet container (typically a Web Browser).  Here is a simple Java applet:

      	import java.applet.Applet;
      	import java.awt.Graphics;
      	public class Applet1 extends Applet 
      	{
      	    public void paint(Graphics g)
      	    {
      	        g.drawString("Hello world!", 50, 25);
      	    }
      	}

      It must be a subclass of Applet and must reside in a file named exactly Applet1.java (case sensitive) to match the class name.  It can be compiled (using the Sun JDK compiler, available for free download at http://java.sun.com) as:

      	javac Applet1.java

      It can't be invoked directly from the command line because it has no main() method.

      Java applets can contain several methods that are invoked at various times by the applet container.  This example contains only a paint() method, but a more typical applet might contain the following:

      init() Called to initialize the applet.
      start() Called when the applet becomes visible (a good place to start an animation).
      stop() Called when the applet moves out of sight of the user (may as well stop any animation here to save CPU time).
      destroy() Called when the applet is unloaded from the container.
      paint() Called when the applet should re-draw itself.

      Typically applets are run in the context of a Web Browser, but the Sun JDK includes a tool (a simple applet container) called appletviewer that can also be used to run an applet.  In either case, you run them as part of an HTML page, like the one below:

      	<html>
      	 <body>
      	  Here is the output of my program:
      	  <applet code="Applet1.class" width="150" height="25">
      	  </applet>
      	 </body>
      	</html>

      To run the applet, load this HTML page into a Web Browser.  To run it via appletviewer, specify the name of the HTML file as the command line argument, as:

      	appletviewer Page1.html

      There are lots of restrictions on applets, mostly due to security concerns.  Applets typically reside on a Web server, but are downloaded automatically as part of the Web page, and executed by the Web Browser.   Therefore, they are not permitted to do things that might be dangerous to the computer running the Web Browser, like reading/writing/deleting files, etc.  However, you can get around these restrictions with signed, trusted applets.

      --Fred

    3. Servlets

      Original Version:  10/14/2000
      Last Updated: 2/5/2006
      Applies to:  Java 1.1+

      A Java servlet is a Java class that runs in the context of a servlet container (typically a Web Server).  Here is a simple Java servlet:

      	import java.io.*;
      	import javax.servlet.*;
      	import javax.servlet.http.*;
      	public class Servlet1 extends HttpServlet
      	{
      	    public void doGet(HttpServletRequest request,
      	                      HttpServletResponse response)
      	        throws IOException, ServletException
      	    {
      	        response.setContentType("text/html");
      	        PrintWriter out = response.getWriter();
      	
      	        out.println("<html>");
      	        out.println(" <body>");
      	        out.println("  <h1>Hello World!</h1>");
      	        out.println(" </body>");
      	        out.println("</html>");
      	    }
      	}

      It must implement the Servlet interface (typically by being a subclass of HttpServlet) and must reside in a file named exactly Servlet1.java (case sensitive) to match the class name.

      To compile the servlet, you must have access to a Java compiler (the Sun JDK compiler is available for free download at http://java.sun.com) and the standard Java servlet classes (javax.servlet.* used in the import statements above).  If your Web Server supports servlets (most do) it should include a .JAR or .ZIP file that contains these classes.   Otherwise, you can download "Tomcat", the official reference implementation of a servlet container for free from http://jakarta.apache.org/tomcat.

      Tomcat is easy to download, unzip, and run.  No installation required.  Its servlet.jar file contains the servlet classes.  You can compile the servlet (using the Sun SDK Java compiler and the Tomcat servlet.jar file) as:

      	javac -classpath c:\tomcat\lib\servlet.jar Servlet1.java

      The servlet can't be invoked directly from the command line because it has no main() method.  Before you run it as a servlet, you must register it with a servlet container.  With Tomcat, there are configuration files you can edit to register locations of servlets, but the easiest way to get started is to simply copy the Servlet1.class file (created by the compile command above) into an existing subdirectory of the Tomcat tree.   For example, copy it to:

      	c:\tomcat\webapps\examples\WEB-INF\classes

      Once the servlet is registered, start Tomcat by running the "startup.bat" (Windows) or "startup.sh" (Unix) file.   You can then run the servlet by loading the following URL into your Web Browser:

      	http://localhost:8080/examples/servlet/Servlet1

      Note that, by default, the Tomcat server listens on port 8080. You can change this by editing the server.xml configuration file.

      Java servlets can contain several methods that are invoked at various times by the servlet container.  This example contains only a doGet() method, but the following are also defined:

      init() Called to initialize the servlet.
      doGet() Called to handle all GET requests from an HTTP client.
      doPost() Called to handle all POST requests from an HTTP client.
      service() Called to handle all requests from an HTTP client.
      destroy() Called when the servlet is unloaded from the container.

      This servlet simply writes a hardcoded stream of HTML to the Web Browser.  A more typical servlet would accept parameters (passed as part of the URL and accessed via the request parameter to the servlet's method), access a relational database or other data source, perform some computation, perhaps read and write files on the Web Server, and write a stream or HTML or XML to the Web Browser.

      For more information, see the O'Reilly Java Servlet Programming book.

      --Fred

    4. JSP - JavaServer Pages

      Original Version: 10/14/2000
      Last Updated: 12/12/2006
      Applies to:  Java 1.1+

      JavaServer Pages (JSPs) are similar to Microsoft "Active Server Pages" (ASPs).  They simplify the job of writing a servlet when the primary purpose of the servlet is to generate an HTML page.  Such a servlet would otherwise consist of a sequence of println() calls to print out the HTML, intermixed with occasional other Java statements.  The bulk of the file would be HTML, but all of the HTML would be wrapped in double quotes to make it into Java string literals, making it more difficult to use quotes in the HTML itself.  For example, the following is a valid Java servlet:

      	import java.io.*;
      	import javax.servlet.*;
      	import javax.servlet.http.*;
      	public class Servlet1 extends HttpServlet
      	{
      	    public void doGet(HttpServletRequest request,
      	                      HttpServletResponse response)
      	        throws IOException, ServletException
      	    {
      	        response.setContentType("text/html");
      	        PrintWriter out = response.getWriter();
      	
      	        out.println("<html>");
      	        out.println(" <body>");
              	out.println("  <p><font color=\"red\">" + 
      			    "The Web Server is running Java version " +
                          	    System.getProperty("java.version") +
      			    "</font></p>");
      	        out.println(" </body>");
      	        out.println("</html>");
      	    }
      	}

      The corresponding JSP page consists of a sequence of HTML with occasional embedded Java code:

      	<html>
      	 <body>
      	  <p><font color="red">" 
      	  The Web Server is running Java 
                version <%= System.getProperty("java.version") %>
      	  </font></p>
      	 </body>
      	</html>

      The <% and %> delimiters are used to enclose the Java code.  The rest of the lines are wrapped automatically in Java println() calls as shown in the servlet above.   When a client requests a JSP page, the server automatically calls the JSP compiler to translate the JSP page into a servlet source file, then calls the Java compiler to compile it, then executes the servlet.  Unnecessary steps are skipped based on the last modification date/time of the JSP file, .java file and .class file.

      By default, all of the JSP code ends up in the service() method of the generated servlet.  However, you can exercise more control over the generated code via JSP directives and JSP declarations.

      The above describes the use of "scriptlets" in JSP pages, which is how many JSP programmers get started. However, the real power of JSP is the use of custom tags, like the Struts tag library, the JSTL tag library, JavaServer Faces libraries, and even your own homegrown tag libraries.

      For more info, see:

          JSP - JavaServer Pages

      --Fred

    5. Java Beans

      Original Version: 2/5/2006
      Last Updated: 5/19/2007
      Applies to:  Java 1.0+

      Unlike Java applets and Java servlets, Java beans are not required to implement any particular interface or inherit from any particular class.  Being a Java bean is accomplished by adhering to a design pattern, a coding convention.

      The basic requirement is that Java beans have a public "default constructor" (a constructor with no parameters) and make their properties available via pairs of "accessor" methods known as "getters" and "setters" using the prefixes:

          "set" for setters
         
      "get" for non-boolean getters
          "is" for boolean getters

      For example, the following is a valid (but not very useful) Java bean:

      	public class BeanWithNoProperties
      	{
      	}

      The following is a simple contrived example that is slightly more useful:

      	public class Rectangle
      	{
      	    private Integer width;
      	    private Integer height;
      	    private String  name;
      
      	    public void setWidth(Integer value)   { width = value; }
      	    public Integer getWidth()             { return width; }
      
      	    public Integer getHeight()            { return height; }
              
      	    public void setSquare(boolean square) { height = (square ? width : null); }
      	    public boolean isSquare()             { return width == height; }
              
      	    public void setName(String newname)   { name = newname; }
      	}

      Notes:

      1. Public constructor exists by default.
      2. Standard getters and/or setters are defined for zero or more of the properties.
      3. Internal property values are declared "private" to prevent bypassing the accessor methods.
      4. Each property may have a getter, a setter, both or neither.
      5. Getters and setters may compute values instead of mapping directly to internal variables.
      6. Names of the arguments for getters and setters are irrelevant.
      7. Setters must return "void".
      8. Getters must take no arguments.

      Common uses of Java beans are:

      1. As UI components, where a drag/drop UI builder uses "reflection" to determine what properties are defined for a bean so that it can offer them to the user in a property sheet.
      2. As simple data objects that are pluggable into a wide variety of frameworks.  For example, "backing beans" for JavaServer Faces applications.
      3. As "Enterprise Java Beans" (EJBs), which use the basic Java bean interface, but have additional requirements in order to support features for remote access, concurrency, scalability, data access, etc.

      Other features/requirements of Java beans are:

      1. Must be persistable which the above is by default.  Technically it should implement one of the interfaces:
                java.io.Serializable
                java.io.Externalizable
        but neither of these requires any methods, and many applications requiring Java beans do not require them.
      2. Must support "introspection" which all Java objects do via "reflection", but a bean can choose to explicitly use the BeanInfo class instead.
      3. Can register with other beans of interest as a "listener" to be informed of "events" that occur to those beans.
      4. Can support custom "property editors" for use in property sheets of an enclosing application.

      For more info, see:

      http://en.wikibooks.org /wiki /Computer_programming /Component_based_software_development #The_JavaBeans_Component_Model

       

      --Fred

    6. JDBC - Java Database Connectivity

      Original Version: 2/5/2006
      Last Updated: 5/19/2007
      Applies to:  Java 1.0+

      JDBC (Java Database Connectivity) is the Java equivalent of ODBC.  It provides access to a relational database.  Here is a simple Java application using JDBC:

      import java.sql.*;
      public class JDBCSample
      {
          public static void main(String[] args)
                  throws ClassNotFoundException, SQLException
          {
              String url  = "jdbc:oracle:thin:@my_server.com:1521:DBSID";
              String user = "my_username";
              String pw   = "my_password";
              Class.forName("oracle.jdbc.driver.OracleDriver");
              Connection conn = DriverManager.getConnection(url, user, pw);
              Statement  st   = conn.createStatement();
              ResultSet  rs   = st.executeQuery("select * from table1");
              while (rs.next())
              {
                  String col1 = rs.getString(1);
                  int    col2 = rs.getInt(2);
              }
              rs.close();
              st.close();
              conn.close();
          }
      }

      You can compile it like any Java application, using any Java compiler.  The java.sql classes are included in the standard runtime library.  

      To run it, you must have access to a JDBC driver.  In this case, you'll need the Oracle JDBC driver, which is available for free download at http://www.oracle.com /technology /software /tech /java /sqlj_jdbc /index.html).  It's a simple Java JAR file (though older versions were JAR files named with a .ZIP extension), so just copy it to your Java classpath.  

      Of course, you'll also need access to a relational database (in this case Oracle), running at the specified host ("my_server.com"), listening on the specified port (1521), and named with the specified database SID ("DBSID").  And it should have a table named "table1".

      This example is pretty simple.  It just selects from a single table and examines the String and int values of the first 2 columns in the resultset.  

      However, you can get fancier, using the typical ODBC syntax to call a procedure or function with input and output "bind variables":

              CallableStatement st = conn.prepareCall
      		("{? = call my_function(?, ?, ?)}");
      	st.registerOutParameter(1, Types.VARCHAR); 
      	st.setInt              (2, 57); 
      	st.setString           (3, "a string value"); 
      	st.registerOutParameter(4, Types.INTEGER); 
              st.execute();
      	String returnVal = st.getString(1);
      	int    outParam  = st.getInt(4);

      You can also:

      1. Call conn.setAutoCommit(false), and explicitly call conn.commit() or conn.rollback().
      2. Prepare statements (for faster repeated execution) via conn.prepareStatement().
      3. Call st.registerOutParameter(n, oracle.jdbc.driver.OracleTypes.CURSOR) to return resultsets as output params or function return values. 
      4. Specify resultSetType values on the call to createStatement(), prepareCall(), or prepareStatement():

        ResultSet.TYPE_FORWARD_ONLY
        ResultSet.TYPE_SCROLL_INSENSITIVE
        ResultSet.TYPE_SCROLL_SENSITIVE

      5. Specify resultSetConcurrency values on the call to createStatement(), prepareCall(), or prepareStatement():

        ResultSet.CONCUR_READ_ONLY
        ResultSet.CONCUR_UPDATABLE

      6. Get connections from a connection pool, instead of creating a new one for each query.
      7. etc.

      Thanks to John Moore for pointing out a typo in this tip!

      --Fred

    7. Javadoc - Generating documentation automatically

      Last Updated: 11/23/2003
      Applies to:  Java 1.0+

      The Java JDK (Java Developer's Kit) from Sun includes a standard tool called "javadoc".  It scans your Java code and automatically produces API documentation as a set of linked Web pages.  To run it against a bunch of Java source files, simply type:

              javadoc *.java

      For a typical set of such documentation, see:

              http://bristle.com/Tips/javadocs/index.html

      For more info, see:

              Javadoc

      --Fred

    8. EJB - Enterprise Java Beans

      Last Updated: 10/13/2000
      Applies to:  Java 1.0+

      Coming soon...

      --Fred

  4. Quick Reference

    1. Operators

      Last Updated: 5/21/2000
      Applies to:  Java 1.0+

      = assignment, shallow copy for objects
         
      == comparison
      Shallow compare for objects.  Use equals() for deep compare.
      != comparison
      Shallow compare for objects.  Use equals() for deep compare.
      <  
      <=  
      >  
      >=  
         
      +, += unary and binary
      -, -= unary and binary
      *, *=  
      /, /=  
      %, %= modulus
         
      ++ prefix and postfix
      -- prefix and postfix
         
      && Logical AND
      Short circuit like C++
      || Logical OR
      Short circuit like C++
      ! Logical NOT
         
      &, &= Bitwise AND
      |, |= Bitwise OR
      ~ Bitwise NOT
      ^, ^= Bitwise XOR
         
      <<, <<= Left shift
      >>, >>= Right arithmetic shift (sign extended)
      >>>, >>>= Right logical shift (zero extended)
         
      ? : Ternary if-then-else
         
      , Used only in for loop

      --Fred

    2. Literals

      Last Updated: 11/13/2000
      Applies to:  Java 1.0+

      123 decimal int (32-bit)
      123.4 decimal double (64-bit)
      0177 octal int (32-bit)
      0x1FF, 0X1FF, 0x1ff, 0X1ff hex int (32-bit)
      123L, 123l long (64-bit)
      123F, 123f float (32-bit)
      123D, 123d double (64-bit)
      1.23e-9 scientific notation

      Thanks to John Haibach for pointing out some additions to the original version of this tip!

      --Fred

    3. Magic Code

      Last Updated: 7/17/2000
      Applies to:  Java 1.0+

      Java executes your code magically (without an apparent call to the code) in the following situations:

      constructor Class constructor called whenever a class is created via new().
      Note, however, that there are no destructors.
      parent constructor Default constructor of parent class called automatically from the constructor of a child class, unless the child constructor explicitly calls super() as the first line of code.
      finalize() finalize() method called by garbage collector before reclaiming the storage used for the class.
      finally clause Statements in the finally clause of a block are run when control passes out of the block.
      toString() toString() method called when a class instance is mentioned in a context that requires a string.

      --Fred

    4. JVM Command Line Options

      Last Updated: 1/27/2006
      Applies to:  Java 1.4.2+

      To see the command line options supported by the Java Virtual Machine (java.exe), type:

          java -?
          java -X

      For Java 1.4.2, the output is of java -? is:

      Usage: java [-options] class [args...]
                 (to execute a class)
         or  java [-options] -jar jarfile [args...]
                 (to execute a jar file)
      
      where options include:
          -client       to select the "client" VM
          -server       to select the "server" VM
          -hotspot      is a synonym for the "client" VM  [deprecated]
                        The default VM is client.
      
          -cp <class search path of directories and zip/jar files>
          -classpath <class search path of directories and zip/jar files>
                        A ; separated list of directories, JAR archives,
                        and ZIP archives to search for class files.
          -D<name>=<value>
                        set a system property
          -verbose[:class|gc|jni]
                        enable verbose output
          -version      print product version and exit
          -version:<value>
                        require the specified version to run
          -showversion  print product version and continue
          -jre-restrict-search | -jre-no-restrict-search
                        include/exclude user private JREs in the version search
          -? -help      print this help message
          -X            print help on non-standard options
          -ea[:<packagename>...|:<classname>]
          -enableassertions[:<packagename>...|:<classname>]
                        enable assertions
          -da[:<packagename>...|:<classname>]
          -disableassertions[:<packagename>...|:<classname>]
                        disable assertions
          -esa | -enablesystemassertions
                        enable system assertions
          -dsa | -disablesystemassertions
                        disable system assertions

      and the output is of java -X is:

          -Xmixed           mixed mode execution (default)
          -Xint             interpreted mode execution only
          -Xbootclasspath:<directories and zip/jar files separated by ;>
                            set search path for bootstrap classes and resources
          -Xbootclasspath/a:<directories and zip/jar files separated by ;>
                            append to end of bootstrap class path
          -Xbootclasspath/p:<directories and zip/jar files separated by ;>
                            prepend in front of bootstrap class path
          -Xnoclassgc       disable class garbage collection
          -Xincgc           enable incremental garbage collection
          -Xloggc:<file>    log GC status to a file with time stamps
          -Xbatch           disable background compilation
          -Xms<size>        set initial Java heap size
          -Xmx<size>        set maximum Java heap size
          -Xss<size>        set java thread stack size
          -Xprof            output cpu profiling data
          -Xrunhprof[:help]|[:<option>=<value>, ...]
                            perform JVMPI heap, cpu, or monitor profiling
          -Xdebug           enable remote debugging
          -Xfuture          enable strictest checks, anticipating future default
          -Xrs              reduce use of OS signals by Java/VM (see documentation)
          -Xcheck:jni       perform additional checks for JNI functions
      
      The -X options are non-standard and subject to change without notice.

      Thanks to Michel van der List for pointing out that there is an incredibly extensive list of options, for various versions of the JVM, at:

          http://blogs.sun.com/roller/resources/watt/jvm-options-list.html

      Thanks also to James Higgins for pointing out that Sun has excellent technical documents on using these options to tune the performance of JVM garbage collection, for various versions of the JVM, at:

          http://java.sun.com/docs/hotspot

      --Fred

  5. Casts

    Last Updated: 6/5/2000
    Applies to:  Java 1.0+

    Casts can be done between any of the primitive types except boolean (byte, char, short, int, long, float, double).  Casting to a wider data type can be done implicitly and preserves the signed value (sign-extending the bit pattern for integral types).   Casting to a narrower date must be done explicitly and discards the high order bits.  For example:

    	int int1 = -1;			// -1 (FFFF FFFF hex)
    	long long1 = (long)int1;	// -1 (sign extended to FFFF FFFF FFFF FFFF)
    	int1 = (int)long1;		// FFFF FFFF (low order bits -- happens to be -1)
    	long1 = 0x300000000L;	 	// 3 0000 0000
    	int1 = (int)long1;		// 0 (low order bits = 0000 0000)
    	long1 = 0x00000000FFFFFFFFL;	// 0000 0000 FFFF FFFF
    	int1 = (int)long1;		// -1 (low order bits = FFFF FFFF)

    Casting from a float or double to an integral type discards the fractional portion of the value.

    --Fred

  6. Overflow

    Last Updated: 6/5/2000
    Applies to:  Java 1.0+

    Java does not treat numeric overfow as an error.  For example:

    	int int1 = 0x7FFFFFFF;
    	System.out.println(int1);	// 2147483647
    	int1 *= 4;
    	System.out.println(int1);	// -4

    --Fred

  7. Containers

    1. Arrays vs. Containers

      Last Updated: 6/25/2000
      Applies to:  Java 1.0+

      Here are some of the differences between arrays and containers:

      1. Fixed size

        Arrays are fixed size.  Containers are dynamic.

      2. Compile-time type checking

        Arrays can be declared to hold items of a specific type and the compiler will check this.   Containers all hold Object, so there is no compile-time checking.

      3. Holding primitive data types

        Arrays can be declared to hold a primitive data type (int, long, float, etc.).   Containers only hold objects (though they can hold the wrapper classes for the primitive data types (Integer, Long, Float, etc.)).

      4. Efficiency

        Arrays are more efficient in both space and time.

      5. Access algorithms

        Containers offer a wider variety of orders (FIFO, LIFO, etc.) and access algorithms (hashing, etc.).  Arrays are simply indexed by integers.

      6. Semantics

        Some containers enforce semantic rules.  For example, a Set represents a mathematical set, where no duplicates are allowed.

      --Fred

    2. Type-Specific Containers

      Last Updated: 7/7/2000
      Applies to:  Java 1.0+

      You can create a type-specific container.  Create a class that contains a member of a standard container type (ArrayList, HashSet, etc).  Offer the standard methods (add, remove, clear, get, size, etc.), but declare the method parameters as the specific type of object you wish to contain.  From each of your methods, call the corresponding method of the standard container.  VB programmers may recognize this technique as a "collection class".

      Note 1:  There is an advantage to encapsulating the standard container like this, rather than inheriting from it.  With inheritance, your type-specific methods would overload (but not hide) the standard methods (which take Object parameters).  Therefore, it would still be possible for the user of your class to add any object to the container.  By encapsulating the standard container, you hide its methods from your user.

      Note 2:  If you add an implements clause to your type-specific container, so that it officially implements one of the standard container interfaces (List, Set, etc.), your users can use your class wherever a standard container class is expected.  However, this forces you to add more methods to your class, specifically the ones that you avoided by not using inheritance -- the ones that take Object as parameters and make it possible for your users to add any object to the container.

      --Fred

    3. Inheriting from Containers

      Last Updated: 7/7/2000
      Applies to:  Java 2+

      When using inheritance to create your own containers, use inherits (implementation inheritance) with the standard abstract classes (AbstractList, AbstractSet, AbstractMap, etc.) rather than using implements (interface inheritance) with the standard interfaces (List, Set, Map, etc.).  This allows you to inherit the implementation of much of the boilerplate code, rather than having to write it all yourself.

      --Fred

    4. Creating hash key classes

      Last Updated: 7/7/2000
      Applies to:  Java 2+

      When using creating a class to be used as a key in a HashMap or HashSet, be sure to override both hashCode() and equals().  Override hashCode() so you can use the "value" of the class (whatever you decide that means) as the hash value, not the address of the class which the default Object.hashCode() method would return.  Override equals() so you can compare the value of the class with other keys, rather than comparing the address via Object.equals().

      --Fred

    5. Java 1.0 Containers vs Java 2 Containers

      Last Updated: 7/7/2000
      Applies to:  Java 1.0+

      Java 1.0 included a standard library of containers (Vector, Stack, HashTable, etc.).   In Java 2, these are still supported, but deprecated in favor of a new container library (ArrayList, HashSet, HashMap, etc.). Here are some notes about the old and new libraries:

      1. Use the following Java 2 containers instead of the corresponding Java 1.0 containers:

        Java 1.0 Java 2
        Vector ArrayList
        Stack LinkedList
        HashTable HashMap
      2. Vector weaknesses:

        1. Final methods

          Some of the Vector methods were final and could not be overridden, making inheritance difficult.

      3. Stack weaknesses:

        1. Inherited from Vector

          Since Stack inherited from Vector, all of the vector methods were available.   Therefore, you could violate the "stack" abstraction, accessing items that were not at the top of the stack.

      --Fred

  8. Scope of Classes

    Last Updated: 6/16/2000
    Applies to:  Java 1.0+

    Java classes in a package can have public or "package" access, but not protected or private.  This makes sense since they are nested inside a package, not another class.  However, you can also nest a class inside another class, in which case you can make it protected or private.  Such a class is called an "inner class".  You can also declare an inner class inside a method or inside an unnamed block of code.  You can also declare an anonymous inner class (a class with no name) in an expression, inheriting from a named class.  An inner class can be static, in which case an instance of it can exist without requiring an instance of the enclosing class.  A static inner class can be nested inside an interface.

    --Fred

  9. Multiple Implementation Inheritance

    Last Updated: 6/25/2000
    Applies to:  Java 1.0+

    Unlike C++, Java doesn't directly support multiple implementation inheritance. However, with a little work, you can accomplish the same effect -- inheriting the implementation of multiple base classes with the ability for the subclass to selectively override methods of each base class.

    Approach 0: The C++ approach.

    The C++ approach (expressed in Java syntax) would look like:

            class Base1
            {
                private String myName = "Base1";
                public void method1a () 
                    { System.out.println ("method1a of " + myName); }
                public void method1b () 
                    { System.out.println ("method1b of " + myName); }
            }
            class Base2
            {
                private String myName = "Base2";
                public void method2a () 
                    { System.out.println ("method2a of " + myName); }
                public void method2b () 
                    { System.out.println ("method2b of " + myName); }
            }
           
            class SubClass extends Base1, Base2  // *** Illegal!
            {
                private String myName = "SubClass";
                public void method1b ()
                    { System.out.println ("overridden method1b of " + myName); }
                public void method2b ()
                    { System.out.println ("overridden method2b of " + myName); }
            } 
           
            public class MI
            {
                static void call1a(Base1 base1) { base1.method1a (); }
                static void call1b(Base1 base1) { base1.method1b (); }
                static void call2a(Base2 base2) { base2.method2a (); }
                static void call2b(Base2 base2) { base2.method2b (); }
                public static void main(String[] args) 
                {
                    SubClass s = new SubClass();
                    call1a(s);
                    call1b(s);
                    call2a(s);
                    call2b(s);
                }
            }

    However, this is not supported in Java. You can't put 2 class names after the keyword "extends".

    Approach 1: Interface Inheritance

    The standard Java approach is to use interfaces for any additional base classes beyond the first one, as:

            class Base1
            {
                private String myName = "Base1";
                public void method1a () 
                    { System.out.println ("method1a of " + myName); }
                public void method1b () 
                    { System.out.println ("method1b of " + myName); }
            }
            interface Base2
            {
                String myName = "Base2";
                public void method2a ();
                public void method2b ();
            }
           
            class SubClass extends Base1 
                           implements Base2
            {
                private String myName = "SubClass";
                public void method1b ()
                    { System.out.println ("overridden method1b of " + myName); }
                public void method2a () 
                    { System.out.println ("required method2a of " + myName); }
                public void method2b () 
                    { System.out.println ("required method2b of " + myName); }
            } 
           
            public class MI
            {
                static void call1a(Base1 base1) { base1.method1a (); }
                static void call1b(Base1 base1) { base1.method1b (); }
                static void call2a(Base2 base2) { base2.method2a (); }
                static void call2b(Base2 base2) { base2.method2b (); }
                public static void main(String[] args) 
                {
                    SubClass s = new SubClass();
                    call1a(s);
                    call1b(s);
                    call2a(s);
                    call2b(s);
                }
            }

    However, this requires SubClass to provide the complete implementation of Base2. All it inherits from Base2 is an interface -- a requirement to implement the methods itself, not an existing implementation of the methods.

    Approach 2: Composition

    Another alternative is to use composition instead of inheritance, as:

            class Base1
            {
                private String myName = "Base1";
                public void method1a () 
                    { System.out.println ("method1a of " + myName); }
                public void method1b () 
                    { System.out.println ("method1b of " + myName); }
            }
            class Base2
            {
                private String myName = "Base2";
                public void method2a () 
                    { System.out.println ("method2a of " + myName); }
                public void method2b () 
                    { System.out.println ("method2b of " + myName); }
            }
           
            class SubClass extends Base1 
            {
                private String myName = "SubClass";
                public void method1b ()
                    { System.out.println ("overridden method1b of " + myName); }
                public Base2 base2 = new Base2();
                public Base2 getBase2() { return base2; }
            } 
           
            public class MI
            {
                static void call1a(Base1 base1) { base1.method1a (); }
                static void call1b(Base1 base1) { base1.method1b (); }
                static void call2a(Base2 base2) { base2.method2a (); }
                static void call2b(Base2 base2) { base2.method2b (); }
                public static void main(String[] args) 
                {
                    SubClass s = new SubClass();
                    call1a(s);
                    call1b(s);
                    call2a(s.getBase2());
                    call2b(s.getBase2());
                }
            }

    This allows SubClass to use the implementation of both base classes. However, it has lost the ability to override the behavior of any of the methods of Base2. The advantage is that it is not required to implement all of the Base2 methods, but the disadvantage is that it is not permitted to implement any of them. It can only offer the default Base2 behavior to its clients.  Also, the code using the subclass must "cast" the subclass to the right type by calling the getBase2 method when using SubClass as a Base2, but not when using it as a Base1.

    Approach 3: Inner Classes

    A better alternative is to use inner classes, as:

            class Base1
            {
                private String myName = "Base1";
                public void method1a () 
                    { System.out.println ("method1a of " + myName); }
                public void method1b () 
                    { System.out.println ("method1b of " + myName); }
            }
            class Base2
            {
                private String myName = "Base2";
                public void method2a () 
                    { System.out.println ("method2a of " + myName); }
                public void method2b () 
                    { System.out.println ("method2b of " + myName); }
            }
            
            class SubClass extends Base1 
            {
                private String myName = "SubClass";
                public void method1b ()
                    { System.out.println ("overridden method1b of " + myName); }
                public class Inner2 extends Base2
                {
                    public void method2b ()
                    {
                        System.out.println ("overridden method2b of " + myName);
                    }
                }
                public Base2 getBase2() { return new Inner2(); }
            } 
            
            public class MI
            {
                static void call1a(Base1 base1) { base1.method1a (); }
                static void call1b(Base1 base1) { base1.method1b (); }
                static void call2a(Base2 base2) { base2.method2a (); }
                static void call2b(Base2 base2) { base2.method2b (); }
                public static void main(String[] args) 
                {
                    SubClass s = new SubClass();
                    call1a(s);
                    call1b(s);
                    call2a(s.getBase2());
                    call2b(s.getBase2());
                }
            }

    This allows SubClass to use the implementation of both base classes, and to selectively override the behavior of any of the methods of either base class. 

    Note:  The code using the subclass must still "cast" the subclass to the right type by calling the getBase2 method.  This seems to be unavoidable.

    Approach 4: Anonymous Inner Classes

    A slightly shorter, but stranger-looking alternative is to make the inner class anonymous, as:

            class Base1
            {
                private String myName = "Base1";
                public void method1a () 
                    { System.out.println ("method1a of " + myName); }
                public void method1b () 
                    { System.out.println ("method1b of " + myName); }
            }
            class Base2
            {
                private String myName = "Base2";
                public void method2a () 
                    { System.out.println ("method2a of " + myName); }
                public void method2b () 
                    { System.out.println ("method2b of " + myName); }
            }
            
            class SubClass extends Base1 
            {
                private String myName = "SubClass";
                public void method1b ()
                    { System.out.println ("overridden method1b of " + myName); }
                public Base2 getBase2() 
                {
                    return new Base2() 
                    {
                        public void method2b ()
                        {
                            System.out.println ("overridden method2b of " + myName);
                        }
                    };
                }
            } 
            
            public class MI
            {
                static void call1a(Base1 base1) { base1.method1a (); }
                static void call1b(Base1 base1) { base1.method1b (); }
                static void call2a(Base2 base2) { base2.method2a (); }
                static void call2b(Base2 base2) { base2.method2b (); }
                public static void main(String[] args) 
                {
                    SubClass s = new SubClass();
                    call1a(s);
                    call1b(s);
                    call2a(s.getBase2());
                    call2b(s.getBase2());
                }
            }

    Here the inner class previous named Inner2 is defined without a name, as part of the return statement. An inner class can be defined within another class, or within any method of another class, or even within any expression in a method of another class. This case defines the inner class, including its override of method2b, within the expression returned by the return statement. No name is given to the inner class. Only its parent (Base2), methods (method2b) and instance variables (none) are specified.

    For more details of this and other techniques using inner classes, see the excellent discussion of inner classes in Chapter 8 "Interfaces and Inner Classes" of [Eckel00], and also the "Choosing Between Lists" section of Chapter 9 "Holding Your Objects", which uses an array of anonymous inner classes as a set of tests in a small benchmark program, and also the "Anonymous inner classes" section of the "A directory lister" section of Chapter 11 "The Java I/O System" which shows how to use an anonymous inner class as a FilenameFilter when iterating over files in a directory.

  10. Exceptions

    1. Declaring Exceptions

      Last Updated: 7/16/2000
      Applies to:  Java 1.0+

      To declare an exception:

          class Exception1 extends Exception
          {
              public Exception1() {}
              public Exception1(String msg) { super(msg); }
          }

      Or, if you don't intend to ever pass a details string as part of the exception:

          class Exception1 extends Exception {}

      --Fred

    2. Catch all exceptions with catch (Throwable t)

      Last Updated: 12/6/1998
      Applies to:  Java 1.0+

      To catch all exceptions, even if you don't know which ones might be thrown, use the syntax:

      	catch (Throwable t)

      This is the Java equivalent of the C++ syntax:

      	catch (...)

      --Fred

    3. Querying Exception Info

      Last Updated: 7/16/2000
      Applies to:  Java 1.0+

      After catching an exception, you can query information about it like any other Java Object via getClass().  You can also use methods of the Throwable class (of which Exception is a subclass).  You can get the string message, if any, thrown with the exception via getMessage().  You can get a string containing the name and the message via toString().  Finally, you can print all this info plus a complete stack trace to the console or a file via printStackTrace().For example:

          try
          {
              sub1();
          }
          catch (Exception e)
          {
              System.out.println ("getName():" + e.getClass().getName());
              System.out.println ("getMessage():" + e.getMessage());
              System.out.println ("toString():" + e.toString());
              System.out.println ("printStackTrace():");
              e.printStackTrace();
          }

      Here, printStackTrace is called with no parameter, so it prints to standard error, but you can also call it with a stream parameter (and thus capture the output in a file or string).  See Propagating and Re-Throwing Exceptions for a more complete sample.

      --Fred

    4. Propagating and Re-Throwing Exceptions

      Last Updated: 7/16/2000
      Applies to:  Java 1.0+

      Once you've caught an exception, you can deal with the problem (correcting it, and re-trying the same operation that originally failed, trying an alternative approach, skipping the operation, etc.), and continue normally.

      If you don't catch an exception, it propagates to the caller, carrying along the detailed message, if any, that was specified at the point where it was thrown, any other instance variables of the exception that you may have declared, and a full stack trace to the point where it was thrown.  See example sub1 below.

      Alternatively, you can catch the exception, take some local corrective action, and then re-throw it without disturbing the error details, stack trace, etc.  See example sub1a below.

      You can even re-throw the same exception with an updated stack trace to show the error as having been originally thrown from your error handler, via fillInStackTrace().   This is useful to hide the details of lower level components used by your component.  See example sub1b below.

      You can go one step further, updating not only the stack trace, but also the detailed message and all instance variables, by allocating a new exception object of the same type and throwing it instead of the one you caught.  See example sub1c below.

      Finally, of course, you can throw an entirely different exception from your exception handler.  Here is a complete sample:

      // Test case to show propagation, handling, re-throwing, and reporting
      // of exceptions.
      
      class Exception1 extends Exception
      {
          public Exception1() {}
          public Exception1(String msg) { super(msg); }
      }
      
      public class Thrower
      {
          //
          // Nested calls that allow the exception to propagate.
          //
          public int sub1() throws Exception1
          {
              return sub2();
          }
          public int sub2() throws Exception1
          {
              return sub3();
          }
          public int sub3() throws Exception1
          {
              throw new Exception1("This is the detail info.");
          }
      
          //
          // Nested calls with one that catches and re-throws the same exception.
          //
          public int sub1a() throws Exception1
          {
              return sub2a();
          }
          public int sub2a() throws Exception1
          {
              try
              {
                  return sub3a();
              }
              catch (Exception1 e)
              {
                  // Take some cleanup action here, but we still want to 
                  // report the original location of the exception.
                  // ...
                  throw e;
              }
          }
          public int sub3a() throws Exception1
          {
              throw new Exception1("This is the detail info.");
          }
      
          //
          // Nested calls with one that catches the exception, updates the 
          // stack trace info, and re-throws it.
          //
          public int sub1b() throws Exception1
          {
              return sub2b();
          }
          public int sub2b() throws Exception1
          {
              try
              {
                  return sub3b();
              }
              catch (Exception1 e)
              {
                  // Take some cleanup action here, then re-throw the 
                  // exception with the original details string, but 
                  // updating the stack info to report this as the original
                  // throw of the exception, hiding the fact that sub3b was 
                  // ever involved.
                  // ...
                  throw (Exception1) e.fillInStackTrace();
              }
          }
          public int sub3b() throws Exception1
          {
              throw new Exception1("This is the detail info.");
          }
      
      
          //
          // Nested calls with one that catches the exception, and throws a 
          // different one of the same type.
          //
          public int sub1c() throws Exception1
          {
              return sub2c();
          }
          public int sub2c() throws Exception1
          {
              try
              {
                  return sub3c();
              }
              catch (Exception1 e)
              {
                  // Take some cleanup action here, then re-throw the 
                  // exception with a new details string, and updating 
                  // the stack info to report this as the original throw 
                  // of the exception, hiding the fact that sub3b was 
                  // ever involved.
                  // ...
                  throw new Exception1("This is different detail info.");
              }
          }
          public int sub3c() throws Exception1
          {
              throw new Exception1("This is the detail info.");
          }
      
      
          public static class Tester
          {
              public static void main(String[] args)
              {
                  Thrower t = new Thrower();
                  System.out.println ("Begin tests of " + 
                                      t.getClass().getName() + "...");
                  //
                  // Prints stack trace as expected.
                  //
                  System.out.println ("\nTest sub1:");
                  try
                  {
                      t.sub1();
                  }
                  catch (Exception e)
                  {
                      System.out.println ("getName():    " + e.getClass().getName());
                      System.out.println ("getMessage(): " + e.getMessage());
                      System.out.println ("toString():   " + e.toString());
                      System.out.println ("printStackTrace():");
                      e.printStackTrace();
                  }
      
                  //
                  // Prints stack trace as expected.  Note that the sub2a line 
                  // number shows the call to Sub3a that originally raised the 
                  // exception, not the line that re-throws it.
                  //
                  System.out.println ("\nTest sub1a:");
                  try
                  {
                      t.sub1a();
                  }
                  catch (Exception e)
                  {
                      System.out.println ("getName():    " + e.getClass().getName());
                      System.out.println ("getMessage(): " + e.getMessage());
                      System.out.println ("toString():   " + e.toString());
                      System.out.println ("printStackTrace():");
                      e.printStackTrace();
                  }
      
                  //
                  // Prints stack trace as expected.  Note that the sub2b line 
                  // number shows the line that re-throws the exception, and that
                  // the call to Sub3b is not mentioned in the stack trace.
                  //
                  System.out.println ("\nTest sub1b:");
                  try
                  {
                      t.sub1b();
                  }
                  catch (Exception e)
                  {
                      System.out.println ("getName():    " + e.getClass().getName());
                      System.out.println ("getMessage(): " + e.getMessage());
                      System.out.println ("toString():   " + e.toString());
                      System.out.println ("printStackTrace():");
                      e.printStackTrace();
                  }
      
                  //
                  // Prints stack trace only as deep as sub2c, where the exception
                  // was caught and a new exception thrown.  Same as above except
                  // that a new details message is provided.
                  //
                  System.out.println ("\nTest sub1c:");
                  try
                  {
                      t.sub1c();
                  }
                  catch (Exception e)
                  {
                      System.out.println ("getName():    " + e.getClass().getName());
                      System.out.println ("getMessage(): " + e.getMessage());
                      System.out.println ("toString():   " + e.toString());
                      System.out.println ("printStackTrace():");
                      e.printStackTrace();
                  }
      
                  System.out.println ("...End tests.");
              }
          }
      
      }
      

      The output is:

      Begin tests of Thrower...
      
      Test sub1:
      getName():    Exception1
      getMessage(): This is the detail info.
      toString():   Exception1: This is the detail info.
      printStackTrace():
      Exception1: This is the detail info.
              at Thrower.sub3(Thrower.java:25)
              at Thrower.sub2(Thrower.java:21)
              at Thrower.sub1(Thrower.java:17)
              at Thrower$Tester.main(Thrower.java:129)
      
      Test sub1a:
      getName():    Exception1
      getMessage(): This is the detail info.
      toString():   Exception1: This is the detail info.
      printStackTrace():
      Exception1: This is the detail info.
              at Thrower.sub3a(Thrower.java:51)
              at Thrower.sub2a(Thrower.java:39)
              at Thrower.sub1a(Thrower.java:33)
              at Thrower$Tester.main(Thrower.java:148)
      
      Test sub1b:
      getName():    Exception1
      getMessage(): This is the detail info.
      toString():   Exception1: This is the detail info.
      printStackTrace():
      Exception1: This is the detail info.
              at Thrower.sub2b(Thrower.java:76)
              at Thrower.sub1b(Thrower.java:60)
              at Thrower$Tester.main(Thrower.java:167)
      
      Test sub1c:
      getName():    Exception1
      getMessage(): This is different detail info.
      toString():   Exception1: This is different detail info.
      printStackTrace():
      Exception1: This is different detail info.
              at Thrower.sub2c(Thrower.java:107)
              at Thrower.sub1c(Thrower.java:91)
              at Thrower$Tester.main(Thrower.java:186)
      ...End tests.

      --Fred

  11. RTTI -- Run-Time Type Identification

    1. Original RTTI

      Last Updated: 7/23/2000
      Applies to:  Java 1.0+

      Java offers several ways to determine the type of an object at run time:

      1. Casting

        You can "upcast" an object to the type of an ancestor class without error.  You can also "downcast" an object from an ancestor class to a descendant class if the actual type of the object is the descendant class (or a descendant of the descendant class).  Any other attempted cast of the object raises a ClassCastException exception, which you can catch.  Thus, you can confirm that an object is really of the desired class as:
        	try
        	{
        	    DesiredClass objDesired = (DesiredClass)objSomeObject;
        	}
        	catch (ClassCastException e)
        	{
        	    // ... deal with error here ...
        	}
      2. getClass().getName()

        For any Java object, you can call the getClass() method to get the Class object associated with the object, and the getName() method of the Class object to get the name of the class as a string.   Then you can compare the string with other such strings, print it, etc.

      3. instanceof

        You can use the instanceof operator to determine whether an object is an instance (or descendant) of a desired class, as:
        	if (objSomeObject instanceof DesiredClass) ...
        

        However, this requires you to hard-code the name of the desired class.

      4. Class.isInstance()

        In Java 1.1, you can use the isInstance() method of the Class object as a more dynamic version of instanceof.  It allows you to determine whether an object is an instance (or descendant) of the same class as another object without hard-coding the name of the class:
        	if (objDesired.getClass().isInstance(objSomeObject) ...

      --Fred

    2. Reflection

      Last Updated: 7/28/2000
      Applies to:  Java 1.1+

      Java 1.1 introduces a feature called "reflection", which greatly extends your ability to interrogate a class at runtime, learning about its properties, methods, etc., creating instances of a class from its name, getting and setting the properties, and calling the methods.  See the "Introspection/Reflection" section of "Differences from C++" above for more details.

      --Fred

  12. Interaction with the Host Environment

    Last Updated: 4/18/2001
    Applies to:  Java 1.0+

    To get/set info in the host environment (operating system), use:

    System.getProperty("java....")
    Info about Java (version, vendor, install directory, CLASSPATH, etc.)
    System.getProperty("os....") Info about the OS (name, version, file separator, line separator, etc.)
    System.getProperty("user.name") User's account name
    System.getProperty("user.home") User's home directory
    System.getProperty("user.dir") User's current working directory
    System.getProperty()
    System.setProperty()
    Boolean.getBoolean()
    Integer.getInteger()
    Long.getLong()
    Environment variables
    System.in
    System.out
    System.err
    System.setIn()
    System.setOut()
    System.setErr()
    Standard input, output, and error streams
    System.exit() Exit, returning status code to the OS
    System.currentTimeMillis() Get current time in milliseconds

    See the documentation for java.lang.System.getProperties() for a complete list of parameter values accepted by System.getProperty()

    --Fred

  13. Web Programming

    1. Reading from a URL

      Last Updated: 3/17/2001
      Applies to:  Java 1.0+

      You can access the contents of any URL via the java.net.URL class. Here is a working example that reads the contents of my links page and writes it to standard output:

      	// Sample program to read HTML file at a URL and write it to
      	// standard output.
      	import java.net.URL;
      	import java.io.InputStream;
      	public class ReadURL
      	{
      	    public static void main(String[] args)
      	        throws java.net.MalformedURLException,
      	               java.io.IOException
      	    {
      	        URL url = new URL("http://www.fred.stluka.com");
      	        InputStream input = url.openStream();
      	        int i;
      	        while ((i = input.read()) != -1)
      	        {
      	             System.out.print((char)i);
      	        }
      	    }
      	}

      --Fred

  14. Efficiency

    1. System.currentTimeMillis -- Simplistic Execution Timing

      Last Updated: 7/1/2000
      Applies to:  Java 1.0+

      It is very easy to do simplistic execution timing in Java.  Simply call System.currentTimeMillis to get the current time in milliseconds, then do the operation to be timed, then call System.currentTimeMillis again and subtract the 2 times.

      --Fred

    2. System.arraycopy -- Copying arrays

      Last Updated: 7/1/2000
      Applies to:  Java 1.0+

      You can efficiently copy some or all of the data from one array to another via System.arraycopy().   Keep in mind however that, for arrays of objects, this is a shallow copy -- it copies only the object references, not the objects themselves.

      --Fred

    3. Arrays.equals -- Comparing arrays

      Last Updated: 7/5/2000
      Applies to:  Java 1.0+

      You can easily compare 2 arrays for equality (but not less than, greater than, etc.) via Arrays.equals().  Unlike System.arraycopy(), which does a shallow copy, this does a deep comparison -- it calls the equals() method of each object rather than just comparing the object references.

      --Fred

  15. Javadoc

    1. Default Javadoc Behavior

      Original Version: 11/23/2003
      Last Updated: 2/9/2008
      Applies to:  Java 1.0+

      Javadoc automatically generates documentation for all of your Java code.  Even if you don't add any Javadoc header comments, the docs include information that can be derived from the Java code itself:

      1. All variables of each class.
      2. All methods of each class.
      3. All parameters of each method.
      4. Name and data type of each parameter.
      5. Data type returned by each method.
      6. All exceptions thrown by each method.
      7. etc.

      However, it includes no information about the purposes or meanings of things (unless you add Javadoc comments).

      In the default layout of the generated documentation:

      1. The left pane always shows the list of classes.
      2. When multiple packages are involved, the top of the left pane shows the list of packages
      3. In the right pane:
        1. The default "Class" view shows the documentation for the selected class. As you scroll through the summary list of the methods, you can click on them to jump to the details.
        2. The "Use" view shows all places where the selected class is used.
        3. The "Tree" view shows the hierarchy of classes.
        4. The "Index" view shows a single alphabetic listing of all classes, methods, instance variables, etc. Useful if you don't remember which class contains a certain method. You can click on names here to jump to the correct place in the Class view.
        5. The "Deprecated" view shows all deprecated Java classes, methods, etc., if any.
        6. The "Help" view shows how to use the Javadocs.

      --Fred

    2. Javadoc Comments

      Original Version:  11/23/2003
      Last Updated: 2/9/2008
      Applies to:  Java 1.0+

      Javadoc also includes specially flagged comments from your Java code in the generated documentation.  

      This makes it very easy to store your detailed documentation as comments in the source files, where future developers can't help but see them, while still being able to offer the same info as an automatically generated, hyperlinked, nicely formatted set of Web pages.

      Special Javadoc comments start with "/**" as:

          /** This is a Javadoc comment.  */

      instead of:

          /* This is a regular Java comment.  */

      Javadoc automatically includes any Javadoc comments that immediately precede a Java class, method, or variable, in the documentation for that class, method or variable.  The first sentence of each comment is automatically used in the summary portion of the docs, and the full block of text is used in the detailed portion.

      You can use Javadoc comments to describe:

      1. The purpose of each class and method.
      2. The meaning of each parameter.
      3. The meaning of the return value.
      4. The conditions under which each exception is thrown.
      5. etc.

      --Fred

    3. Javadoc Tags

      Last Updated: 12/2/2003
      Applies to:  Java 1.0+

      Javadoc recognizes various tags within Javadoc comments.  You can use these tags to add more info to the generated docs:

      @param name description Comments about a specific parameter of a method.
      @return description Comments about the return value of a function.
      @throws name description Comments about a specific exception thrown by a method.
      @version description Version number.
      Ignored if no -version CLI option.
      Handy to use with $Revision$ of most version control systems.
      @author description Author's name.
      Ignored if no -author CLI option.
      Handy to use with $Author$ of most version control systems.
      @since description First version of the software in which a particular class, method, etc. existed.
      @see package.class#member Cross-reference (hyper-link) to another class, method, etc.
      {@link package.class#member label}
      In-line cross-reference (hyper-link) to another class, method, etc.
      Can be used in-line as part of a paragraph, or even as part of the description text of another Javadoc tag.

      These are the tags I use regularly, but there are more.  For a complete list, see:

              http://java.sun.com/j2se/1.4.2/docs/tooldocs/solaris/javadoc.html

      --Fred

    4. Javadoc Command Line Interface

      Last Updated: 11/23/2003
      Applies to:  Java 1.0+

      For the example above, I used the command line options:

      -use Generates a Use tab in the browser page.
      -version Generates a Version field for each class.
      -author Generates an Author field for each class.
      -windowtitle Generates a Version field for each class.
      -d Where to store the Web pages.
      -classpath Where to find Java *.class files imported by the *.java files.

      I didn't use:

      -private Would have generated info about private members as well as public and protected.

      For the full command line syntax, including a complete list of options, type:

          javadoc

      without any command line parameters, or see:

          http://java.sun.com/j2se/1.4.2/docs/tooldocs/solaris/javadoc.html

      --Fred

    5. Javadoc Formatting

      Last Updated: 11/23/2003
      Applies to:  Java 1.0+

      Since javadoc puts the text of your Javadoc comments in a Web page, you can use HTML tags in your Javadoc comments to control the format of the corresponding portions of the generated docs.  Thus, you can add bold, italics, lists, and pre-formatted sections.  You can even add pictures via the IMG tag.

      --Fred

    6. Javadoc Example

      Last Updated: 11/23/2003
      Applies to:  Java 1.0+

      The Javadoc documentation at:

          http://bristle.com/Tips/javadocs/Base64.html

      was generated from source code that contained the following samples of Javadoc comments:
       
      /******************************************************************************
      * This class contains support for Base64 encoding and decoding.
      *<pre>
      *<b>Usage:</b>
      *   - The typical scenario for using this class is:
      *     - To encode a string as Base64:
      *               String strEncoded = Base64.encode(strDecoded);
      *     - To decode a Base64 string:
      *               String strDecoded = Base64.decode(strEncoded);
      *<b>Assumptions:</b>
      *<b>Effects:</b>
      *       - None.
      *<b>Anticipated Changes:</b>
      *<b>Notes:</b>
      *<b>Implementation Notes:</b>
      *<b>Portability Issues:</b>
      *</pre>
      *@version $Revision: 2 $
      *@author  $Author: FStluka $
      *@since   2.6.0
      ******************************************************************************/
      public class Base64
          ...
          /**************************************************************************
          * Return the decoded string value of the specified Base64 encoded string.
          * The specified string is assumed to use the ISO-8859-1 (Latin-1) encoding.
          *@param  strIn          String to be decoded.
          *@return                Decoded string.
          *@throws java.io.UnsupportedEncodingException
          *                       When the incoming string does not use the 
          *                       ISO-8859-1 (Latin-1) encoding.
          *@throws InvalidBase64DigitFound
          *                       When the string to be decoded contains a character
          *                       that is not a valid Base64 digit char.
          *@throws TruncatedBase64EncodingFound
          *                       When the string to be decoded has an invalid 
          *                       length.
          **************************************************************************/
          public static String decode(String strIn)
                  throws java.io.UnsupportedEncodingException
                        ,InvalidBase64DigitFound
                        ,TruncatedBase64EncodingFound

      --Fred

    7. Bristle Java Library Javadocs

      Last Updated: 2/9/2008
      Applies to:  Java 1.0+

      As a larger, more complex example, you can find the javadocs for the entire Bristle Java library at:
          http://bristle.com/opensource/javalib/docs/api/private

      I always add the special Javadoc comments to each Java class and method when I first write it, so the docs are pretty complete at all times.

      Also, I typically add the following higher level design sections to each class file, but leave them empty if I don't have anything worth saying:
          Usage:
          Assumptions:
          Effects:
          Anticipated Changes:
          Notes:
          Implementation Notes:
          Portability Issues:
          Revision History:
      When appropriate, I add similar sections to each method.

      Here are a couple of examples from the Bristle Java library with extensive Usage, Effects, and Anticipated Changes sections, to give you an idea of what I typically put there:
          http://bristle.com/opensource/javalib/docs/api/private/com/bristle/javalib/sql/ConnectionPool.html
          http://bristle.com/opensource/javalib/docs/api/private/com/bristle/javalib/util/GetOpt.html
          http://bristle.com/opensource/javalib/docs/api/private/com/bristle/javalib/xml/XMLUtil.html
          http://bristle.com/opensource/javalib/docs/api/private/com/bristle/javalib/xml/XSLUtil.html
          http://bristle.com/opensource/javalib/docs/api/private/com/bristle/javalib/io/FileTreeIterator.html
          http://bristle.com/opensource/javalib/docs/api/private/com/bristle/javalib/log/Logger.html
          http://bristle.com/opensource/javalib/docs/api/private/com/bristle/javalib/log/LoggerUtil.html
          http://bristle.com/opensource/javalib/docs/api/private/com/bristle/javalib/log/XMLDOMLoggerTarget.html

      --Fred

    8. Overriding Javadoc Behavior

      Last Updated: 11/23/2003
      Applies to:  Java 1.0+

      You can override the default "doclet" that generates the docs in HTML format.  See the -doclet command line option.  This give you complete control over the output format.

      --Fred

  16. JSP - JavaServer Pages

    1. JSP Intro

      Last Updated: 11/30/2006
      Applies to:  JSP 1.2+

      See:

          Getting Started - JSP

      --Fred

    2. JSP Directives

      Original Version: 12/12/2006
      Last Updated: 1/8/2007
      Applies to:  JSP 1.2+

      JSP defines the following directives for use in a JSP file: 

      <%@ include file= %> Include a file before converting page to Java 
      <%@ page autoFlush= buffer= contentType= errorPage= extends= import= info= isErrorPage= isThreadSafe= language= pageEncoding= session= isELIgnored= %> Define page dependent attributes
      <%@ taglib prefix= uri= %> Declare a tag library for use within the page

      and the following directives for use in a custom tag file: 

      <%@ attribute name= required= fragment= rtexprvalue= type= description= %> Defines an attribute of the custom tag 
      <%@ tag display-name= body-content= dynamic-attributes= small-icon= large-icon= description= example= language= import= pageEncoding= isELIgnored= %> Defines properties of the custom tag.  Similar to @page, but for tag files, not JSP files.
      <%@ variable name-given= name-from-attribute= alias= variable-class= declare= scope= description= %> Declares an EL variable exposed by the tag to the calling page.

      For more detail, see:

          Fred's JSP links
          JSP 1.2 Syntax
          JSP 2.0 Syntax

      --Fred

    3. JSP Scripting Elements and Other Syntax

      Original Version: 11/30/2006
      Last Updated: 10/9/2008
      Applies to:  JSP 1.2+

      JSP defines the following scripting elements and other syntax: 

      <%! declaration %> Declare a JSP variable or method.  In the generated Java servlet, it is declared in the servlet class outside of any methods, so it can be an instance variable shared by all threads, a static variable shared by all threads of all instances, or a static or non-static Java method.
      <%= expression %> Evaluate a complete JSP expression adding its value to the generated page.
      <% scriptlet %> Insert a snippet of Java code into the service() method of the generated servlet.  If the snippet contains declarations, they are local to the method, with a separate value for each thread.
      <%-- comment --%> JSP comment.  Does not appear in the generated page.  Can be used to comment out JSP directives, actions, and scripting elements.
      \ Backslash char can be used to "escape" the special meaning of other chars, as:

         \'   \"   \\   %\>   <\%

      ${ expression } EL (expression language) expression.  See JSP/JSTL EL Syntax.
      Note:  Before JSP 1.3, EL expressions could only be used in the values of attributes, not in the bodies of tags or in template text.

      For more detail, see:

          Fred's JSP links
          JSP/JSTL EL Syntax
          JSTL Spec
          JSP 1.2 Syntax
          JSP 2.0 Syntax

      --Fred

    4. JSP and JSTL Actions

      Original Version: 12/12/2006
      Last Updated: 1/29/2008
      Applies to:  JSP 1.2+

      JSP defines the following standard actions:

      <jsp:attribute name= trim= > Define the value of a tag attribute in the body of an XML element instead of in the value of an XML attribute.
      <jsp:body> Explicitly define the body of a custom tag.  Only needed when the tag also contains <jsp:attribute> elements.
      <jsp:doBody var= varReader= scope= > Evaluates the body of the tag used by the calling page to invoke this tag file.  Used in tag files only.
      <jsp:element name= > Dynamically generate an XML element.
      <jsp:fallback> Nested inside <jsp:plugin> to specify text to use for browsers that don't support <embed> or <object> elements. 
      <jsp:forward page= > Forward control to another page, file or servlet
      <jsp:getProperty name= property= > Insert value of bean property into generated page.
      Example:
          <jsp:getProperty name='mybean' property='prop1'>
      Note:  When using JSTL EL, can use <c:out> tag instead:
         
      <c:out value='${mybean.prop1}'>
      Note:  As of JSP 2.0, can use a simple EL expression instead:
         
      ${mybean.prop1}
      See Accessing Properties of Objects in JSP and JSP/JSTL EL for more info.
      <jsp:include page= flush= > Include the generated response of another JSP file, servlet, or static page, in the generated page.
      <jsp:invoke fragment= var= varReader= scope= > Evaluate a fragment defined with <%@attribute fragment='true'%>.
      <jsp:output omit-xml-declaration= doctype-root-element= doctype-public= doctype-system= > Specify the XML declaration or the document type declaration in the request output of a JSP document or a tag file that is in XML syntax.
      <jsp:param name= value= > Nested inside <jsp:forward>, <jsp:include> or <jsp:params> to specify a parameter.
      <jsp:params> Nested inside <jsp:plugin> to enclose <jsp:param> elements for applet parameters.
      <jsp:plugin align= archive= code= codebase= height= hspace= iepluginurl= jreversion= name= nspluginurl= title= type= vspace= width= > Generate <embed> or <object> element for a plugin.
      <jsp:setProperty name= property= param= value= > Set property of bean to specified value or to value of specified request parameter.
      Note:  Can use property="*" to automatically map all request parameters to bean properties with the same name.
      <jsp:text> Explicitly specify template data.  Not usually needed
      <jsp:useBean id= class= scope= type= beanName= > Assign specified JSP variable (id) a reference to an existing or newly created bean of the specified class or beanName treating it as the specified type.

      For more detail, see:

          Fred's JSP links
          JSP 1.2 Syntax
          JSP 2.0 Syntax

      You can also define custom actions.  The JSTL (JSP Standard Tag Library) tags are one commonly used set of custom actions.  These include the following:

      Core tags Formatting tags SQL tags XML tags
      • <c:import>
        • <c:param>
      • <c:redirect>

      • <c:if>
      • <c:choose>
        • <c:when>
        • <c:otherwise>
      •  <c:forEach>
      •  <c:forTokens>
      • <c:catch>

      • <c:set>
      • <c:remove>

      • <c:out>

      • <c:url>
      • <fmt:requestEncoding>

      • <fmt:setLocale>
      • <fmt:timeZone>
      • <fmt:setTimeZone>

      • <fmt:bundle>
      • <fmt:setBundle>

      • <fmt:message>
        • <fmt:param>

      • <fmt:formatNumber>
      • <fmt:parseNumber>
      • <fmt:formatDate>
      • <fmt:parseDate>
      • <sql:transaction>

      • <sql:query>
        • <sql:param>
        • <sql:dateParam>

      • <sql:update>
        • <sql:param>
        • <sql:dateParam>

      • <sql:setDataSource>
      • <xml:parse>

      • <xml:transform>
        • <xml:param>

      • <xml:if>
      • <xml:choose>
        • <xml:when>
        • <xml:otherwise>
      • <xml:forEach>

      • <xml:set>

      • <xml:out>
      JSTL functions
      • boolean contains (String, String)
      • boolean containsIgnoreCase (String, String)
      • boolean endsWith (String, String)
      • String escapeXml (String)
      • int indexOf (String, String)
      • String join (String[], String)
      • int length (Object)
      • String replace (String, String, String)
      • String[] split (String, String)
      • boolean startsWith (String, String)
      • String substring (String, int, int)
      • String substringAfter (String, String)
      • String substringBefore (String, String)
      • String toLowerCase (String)
      • String toUpperCase (String)
      • String trim (String)

      For details, see:

          Fred's JSTL links
          JSTL Spec
          JSTL Tags
          JSTL APIs

      --Fred

    5. JSP/JSTL Implicit Objects

      Original Version: 12/14/2006
      Last Updated: 12/29/2006
      Applies to:  JSP 1.2+

      JSP and the JSP/JSTL EL (Expression Language) define the following implicit variables:

      JSP

      JSP/JSTL EL

       
      pageContext pageContext The JSP PageContext object
        pageScope Map of page-scoped attributes
      request pageContext .request The HttpServletRequest object
      - See example.
        requestScope Map of request-scoped attributes
        cookie Map of request cookies (containing single or first values)
      - Uses HttpServletRequest.getCookies() but discards multiple values for the same name.
      - See example.
      request .getCookies() pageContext .request .cookies Array of request cookies (containing potentially multiple values with the same name)
      - Provides direct access to HttpServletRequest.getCookies().
      - See example.
      request .getParameterNames()

      request .getParameter (name)
      param The 2 JSP methods return an Enumeration of param names, and the String value of the param with the specified name.
      The EL object returns a Map of params.
      - In both cases, if the param has multiple values, this returns only the first value. 
      - Uses ServletRequest.getParameter().
      - See example.
      request .getParameterNames()

      request .getParameterValues (name)
       

      request .getParameterMap()
      paramValues The first 2 JSP methods return an Enumeration of param names, and an array (not an Enumeration) of String values of the param with the specified name.
      The 3rd JSP method and the EL object both return a Map of params.
      - In all cases, the value for each param is an array of potentially multiple String values. 
      - Uses ServletRequest.getParameterValues().
      - See example.
      request .getHeaderNames()

      request .getHeader (name)
      header The 2 JSP methods return an Enumeration of header names, and the String value of the header with the specified name.
      The EL object returns a Map of headers.
      - In both cases, if the header has multiple values, this returns only the first value.
      - Uses ServletRequest.getHeader().
      - See example.
      request .getHeaderNames()

      request .getHeaders (name)
      headerValues The JSP methods return an Enumeration of header names, and an Enumeration (not an array) of potentially multiple String values of the header with the specified name.
      The EL object returns a Map of headers, where each value in the Map is a String array (not an Enumeration) of potentially multiple values of the header.
      - Uses ServletRequest.getHeaders().
      - See example.
      response pageContext .response The ServletResponse object
      session pageContext .session The HttpSession object
        sessionScope Map of session-scoped attributes
      application pageContext .servletContext The ServletContext object
        applicationScope Map of application-scoped attributes
        initParam Map of context initialization params
      - Uses ServletContext.getInitParameter()
      config pageContext .servletConfig The ServletConfig object
      out   The JspWriter object for the page
      exception   The current Exception
      page   The JSP implementation class -- the generated Java class.

      In addition to these implicit variables, JSP and the JSP/JSTL EL have access to a variety of explicit variables, including:

      1. Objects created by JSP pages via the JSP standard action: <jsp:useBean>
      2. Objects created by custom tags via the JSP directive: <%@ variable %>
      3. Objects created by a servlet, bean, or other Java code, that are stored in any of the JSP scopes (page, request, session, or application)

      For more detail, see:

          Fred's JSP links
          Fred's JSTL links
          JSP 2.0 Syntax
          JSTL Spec

      --Fred

    6. JSTL/JSP EL Syntax

      Last Updated: 12/14/2006
      Applies to:  JSP 1.2+

      The JSP/JSTL EL (Expression Language) was originally part of JSTL, but was added to JSP in version 2.0. It defines the following operators: 

      . [] Access a bean property, or Map or List entry, or array element.
      + Add
      - Subtract, and unary negation
      * Multiply
      / div Divide (floating point division, not integer division, in both cases)
      % mod Modulus (remainder)
      == eq Equals
      != ne Not equals
      < lt Less than
      > gt Greater than
      <= le Less than or equal
      >= ge Greater than or equal
      && and Logical and
      || or Logical or
      ! not Logical not
      ? : If then else
      empty Test for empty (null or empty String, Map, List or array)
      () Grouping for precedence

      and the following literal values and syntax:

      null Null value
      true Boolean true
      false Boolean false
      ' " Quote strings with either single or double quote

      For more detail, see:

          Fred's JSTL links
          JSTL Spec

      --Fred

    7. Accessing Properties of Objects in JSP and JSP/JSTL EL

      Original Version:  12/29/2006
      Last Updated: 1/8/2007
      Applies to:  JSP 1.2+

      JSP and the JSP/JSTL EL provide different mechanisms for accessing properties of objects.

      In JSP expressions, you start from objects available to JSP and use the regular Java syntax to access methods of the objects.  Examples:
       

      1
      <%= request.getServerName() %>
      2
      <%= request.isSecure() %>
      3
      <%= (request.getCookies() == null 
                || request.getCookies().length == 0) 
           ? "" 
           : request.getCookies[0].getValue()
      %>

      In JSP/JSTL EL expressions, you start from objects available to the JSP/JSTL EL and use the Java bean syntax to access properties of the objects.  Examples:

      1
      ${pageContext.request.serverName}
      2
      ${pageContext.request.secure}
      3
      ${pageContext.request.cookies[0].value}

      Differences to note in the EL version:

      • Lack of "get" and "is" prefixes and trailing parentheses.  With the EL, you use the syntax of bean properties, not Java methods.
      • Different starting objects.  JSP defines a convenient "request" object, while the EL requires you to access the request property of the "pageContext" object.
      • The EL tolerates errors like null pointer and invalid array index, which you have to check for explicitly in JSP.

      Beware of using the wrong starting object in an EL expression.  It is easy to accidentally use a JSP object name like "request" instead of the EL object name "pageContext.request".  The EL tolerates missing variables, so it silently ignores:
          ${request.serverName}
      when you probably intended:
          ${pageContext.request.serverName}

      Prior to JSP 2.0, EL expressions were only allowed as values of attributes.  Therefore, in older versions of JSP, you may have to wrap each EL expression in the value attribute of a <c:out> tag, as:

      1
      <c:out value="${pageContext.request.serverName}" />
      2
      <c:out value="${pageContext.request.secure}" />
      3
      <c:out value="${pageContext.request.cookies[0].value}" />

      --Fred

    8. JSP/JSTL EL Convenience Objects

      Original Version:  12/29/2006
      Last Updated: 1/8/2007
      Applies to:  JSP 1.2+

      JSTL defines some additional convenience objects that don't exist in JSP.  Instead of writing the following JSP:
       

      1
      <%= (request.getParameter("param_name") == null)
           ? ""
           : request.getParameter("param_name")
      %>
      2
      <%= (request.getHeader("header_name") == null)
           ? ""
           : request.getHeader("header_name")
      %>
      3
      <% Cookie[] cookies = request.getCookies();
         if (cookies == null)
         {
             out.println("");
         }
         else
         {
             for (int i=0; i < cookies.length; i++)
             {
                 if ("cookie_name".equals(cookies[i].getName()))
                 {
                     out.println(cookies[i].getValue());
                     break;
                 }
             }
         }
      %>

      in JSTL, you simply write:

      1
      ${param.param_name}
      2
      ${header.header_name}
      3
      ${cookie.cookie_name.value}

      Notes:

      • The EL "param" and "header" objects are Maps of strings accessed by param and header names (case sensitive).
      • The EL "cookie" object is a Map of Cookie objects (not just strings) accessed by cookie name (case sensitive).  Each Cookie object has a "value" field containing the cookie value.

      Prior to JSP 2.0, EL expressions were only allowed as values of attributes.  Therefore, in older versions of JSP, you may have to wrap each EL expression in the value attribute of a <c:out> tag, as:

      1
      <c:out value="${param.param_name}" />
      2
      <c:out value="${header.header_name}" />
      3
      <c:out value="${cookie.cookie_name.value}" />

      --Fred

    9. Enabling EL Expression Evaluation

      Last Updated: 1/8/2007
      Applies to:  JSP 1.2+

      EL expressions are a very convenient and concise mechanism.  However, they may not be enabled by default.  If you see the expressions themselves being echoed to your JSP page:
          ${pageContext.request.method}
      instead of their values:
          GET
      here are some things to check.

      1.  Are you using a JSP 2.0 container?  

      Prior to JSP 2.0, EL expressions were permitted only in the values of attributes.  In regular text and the bodies of JSP tags, the syntax was ignored, so the expressions were treated as regular text and not evaluated.  In that case, you'll have to use the longer syntax:
          <c:out value="${pageContext.request.method}" />

      2.  Is the isELIgnored flag set to false?

      For backwards compatibility with old JSP pages that may have contained the EL expression syntax, there is a flag called isELIgnored which controls whether EL expressions outside of attribute values are ignored.  

      You can explicitly set this flag via the page directive:
          <%@ page isELIgnored="false" %>
      I recommend doing so for any JSP page that relies on it.

      Otherwise, it may default to true or false, depending on the style of your web.xml file.  It defaults to true (don't evaluate expressions), if web.xml uses the syntax for Java Servlet spec 2.3 or earlier:

      <?xml version="1.0" encoding="ISO-8859-1"?>
      <!DOCTYPE web-app
        PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com//dtd/web-app_2_3.dtd">
      <web-app>
      </web-app>

      It defaults to false (do evaluate expressions), if web.xml uses the syntax for Java Servlet spec 2.4 or later:

      <?xml version="1.0" encoding="ISO-8859-1"?>
      <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                                   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
               version="2.4">
      </web-app>

      Note:  If you experiment with this, switching back and forth between different copies of your web.xml file, beware that the copy commands on Windows do not set the timestamp of the resulting file to the current time.  Instead, they copy the timestamp from the source file.  This is a problem because it keeps the automatic re-loading mechanisms of Tomcat and other Web servers from detecting the change.  On Unix, cp sets the timestamp to the current time, unless you prevent it with the -p option.  On both Unix and Windows, the move and rename commands leave the timestamp untouched because they don't actually operate on the file, only on its parent directory.

      If setting isELIgnored to false causes errors like:

      According to TLD or attribute directive in tag file, attribute value does not accept any expressions

      when you try to specify an EL expression for the value of a c:out tag, as shown above, make sure you are not using the old JSTL 1.0 URI for the "core" tag library, as:

      <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>

      Switch to the JSTL 1.0 URI for the "core_rt" tag library, which does accept request time expressions:

      <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>

      or better yet, switch to the JSTL 1.1 URI, where there is no distinction between "core" and "core_rt".  There is only "core" which does accept request time expressions.

      <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

      If switching to the JSTL 1.1 URI causes the error:

      The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application

      you may have to get the new JSTL 1.1 versions of the jstl.jar and standard.jar files from the Sun web site to replace the 1.0 versions you are using.  You can determine which version you have by examining the text of the c.tld file inside the standard.jar file.  It should say either:

      <description>JSTL 1.0 core library</description>
      <tlib-version>1.0</tlib-version>
      <uri>http://java.sun.com/jstl/core</uri>

      or:

      <description>JSTL 1.1 core library</description>
      <tlib-version>1.1</tlib-version>
      <uri>http://java.sun.com/jsp/jstl/core</uri>

      By the way, if you have some other reason for explicitly using <c:out> be aware that it echoes its value attribute, not the text inside its body.  Thus:

      <c:out value="Show this text">
        Not this text
      </c:out>

      The text inside the body is the default value, to be echoed only if the regular value is null.  The empty string does not count as null, so:

      <c:out value="">
        Shows nothing, not this default text
      </c:out>

      However, you can force the regular value to null with an EL expression, as:

      <c:out value="${null}">
        Shows this default text
      </c:out>

      --Fred

    10. Looping Through Cookies in JSP and JSP/JSTL EL

      Original Version: 12/29/2006
      Last Updated: 1/8/2007
      Applies to:  JSP 1.2+

      JSP and the JSP/JSTL EL provide different mechanisms for writing small snippets of logic to do things like loop through a set of cookies.

      In JSP, you write regular Java code and access the methods of the JSP-defined objects:

      <% Cookie[] cookies = request.getCookies();
         if (cookies != null)
         {
             for (int i=0; i < cookies.length; i++)
             {
                 out.println("<b>" + cookies[i].getName() + "</b>: "
                              + cookies[i].getValue() + "<br/>");
             }
         }
      %>

      In JSTL, you can take advantage of JSTL custom tags like <c:forEach>, and you use EL expressions to access the bean-style properties of the JSTL-defined objects:

      <c:forEach items="${pageContext.request.cookies}" var="c">
        <b>${c.name}</b>: ${c.value}<br>
      </c:forEach>

      Note that JSTL also defines a convenience object "cookie" that is great for accessing a single cookie by name without having to write a loop at all:

      ${cookie.cookie_name.value}

      Therefore, you might choose to loop over "cookie" instead of "pageContext.request.cookies".  However, be aware that, in order to be as convenient as possible for accessing single cookies by name, "cookie" returns a Map of Cookie objects keyed by name, instead of an array of Cookie objects.  This means it cannot store multiple cookies with the same name.  Instead it stores only the first cookie with each name.  If you need to see multiple values for the same cookie name, use "pageContext.request.cookies" which is an array of all cookies, including those with duplicate names.

      Also, because "cookie" returns a Map, "c.value" is a Map entry containing a Cookie, not just a Cookie pulled from an array.  Therefore, you must access the cookie name as "c.key" or "c.value.name", and access the cookie value as "c.value.value":

      <c:forEach items="${cookie}" var="c">
        <b><${c.key}</b>: ${c.value.value}<br> 
      </c:forEach>

      --Fred

    11. Looping Through Parameters in JSP and JSP/JSTL EL

      Last Updated: 1/8/2007
      Applies to:  JSP 1.2+

      JSP and the JSP/JSTL EL provide different mechanisms for writing small snippets of logic to do things like loop through a set of parameters.

      In JSP, you write regular Java code and access the methods of the JSP-defined objects:

      <%@ page import="java.util.Enumeration" %>
      <% for (Enumeration enumNames = request.getParameterNames();
              enumNames.hasMoreElements();
             )
         {
             String strName = (String) enumNames.nextElement();
             out.println("<b>" + strName + "</b>:");
             String[] values = request.getParameterValues(strName);
             for (int i=0; i < values.length; i++)
             {
                 out.println("<br />&nbsp;&nbsp;" + values[i]);
             }
             out.println("<br>");
         }
      %>

      Note:  Unlike for cookies, you don't have to worry about the case of no params because getParameterNames() returns an empty Enumeration, not a null.  This is different from getCookies() which returns a null or an array of values.

      Note:  Despite the fact that getParameterValues() is documented as returning a null when there are no parameters with the specified name, you don't have to worry about a null because only params that exist are returned by getParameterNames(), and all existing params have values that are at least an empty string.

      In JSTL, you can take advantage of JSTL custom tags like <c:forEach>, and you use EL expressions to access the bean-style properties of the JSTL-defined objects:

      <c:forEach items="${paramValues}" var="p">
        <b>${p.key}</b>:
        <c:forEach items="${p.value}" var="value">
          <br />&nbsp;&nbsp;${value}
        </c:forEach>
        <br>
      </c:forEach>

      Note that JSTL also defines a convenience object "param" that is great for accessing a single param by name without having to write a loop at all:

      ${param.param_name}

      Therefore, you might choose to loop over "param" instead of "paramValues".  However, be aware that, in order to be as convenient as possible for accessing single params by name, "param" returns a Map of strings keyed by name, not a Map of string arrays keyed by name.  This means it cannot store multiple string values for the same name.  Instead it stores only the first value for each name.  If you need to see multiple values for the same param name, use "paramValues".

      Using the object "param" in JSTL is equivalent to using request.getParameter() in JSP.  They both use the Java method ServletRequest.getParameter() behind the scenes.  Similarly, using the object "paramValues" in JSTL is equivalent to using request.getParameterValues() in JSP.  They both use the Java method  ServletRequest.getParameterValues() behind the scenes.

      If you don't care about multiple values for the same param, in JSP, you can write:

      <%@ page import="java.util.Enumeration" %>
      <% for (Enumeration enumNames = request.getParameterNames();
              enumNames.hasMoreElements();
             )
         {
             String strName = (String) enumNames.nextElement();
             out.println("<b>" + strName + "</b>: "
                               + request.getParameter(strName)
                               + "<br />");
         }
      %>

      and in JSTL:

      <c:forEach items="${param}" var="p">
        <b>${p.key}</b>: ${p.value}<br>
      </c:forEach>

      Finally, compare the code here with the code in Looping Through Cookies in JSP and JSP/JSTL EL.  Note how similar the JSTL code is for accessing parameters and cookies, despite the fact that the JSP code is so different.  JSTL hides differences that you must be aware of when writing JSP code, especially iterating over an array vs. an Enumeration, and dealing with empty or null collections of values.

      --Fred

    12. Looping Through Headers in JSP and JSP/JSTL EL

      Last Updated: 1/9/2007
      Applies to:  JSP 1.2+

      JSP and the JSP/JSTL EL provide different mechanisms for writing small snippets of logic to do things like loop through a set of headers.

      In JSP, you write regular Java code and access the methods of the JSP-defined objects:

      <%@ page import="java.util.Enumeration" %>
      <% for (Enumeration enumNames = request.getHeaderNames();
              enumNames.hasMoreElements();
             )
         {
             String strName = (String) enumNames.nextElement();
             out.println("<b>" + strName + "</b>:");
             for (Enumeration enumValues = request.getHeaders(strName);
                  enumValues.hasMoreElements();
                 )
             {
                 out.println("<br />&nbsp;&nbsp;"
                             + enumValues.nextElement());
             }
             out.println("<br>");
         }
      %>

      Note:  Unlike for cookies, you don't have to worry about the case of no headers because getHeaderNames() returns an empty Enumeration, not a null.  This is different from getCookies() which returns a null or an array of values.

      Note:  Unlike for params, you don't have to worry about a header with no value because getHeaders() also returns an empty enumeration, not a null.  This is different from getParameterValues() which returns a null or an array of values.

      In JSTL, you can take advantage of JSTL custom tags like <c:forEach>, and you use EL expressions to access the bean-style properties of the JSTL-defined objects:

      <c:forEach items="${headerValues}" var="h">
        <b>${h.key}</b>:
        <c:forEach items="${h.value}" var="value">
          <br />&nbsp;&nbsp;${value}
        </c:forEach>
        <br>
      </c:forEach>

      Note that JSTL also defines a convenience object "header" that is great for accessing a single header by name without having to write a loop at all:

      ${header.header_name}

      Therefore, you might choose to loop over "header" instead of "headerValues".  However, be aware that, in order to be as convenient as possible for accessing single headers by name, "header" returns a Map of strings keyed by name, not a Map of string arrays keyed by name.  This means it cannot store multiple string values for the same name.  Instead it stores only the first value for each name.  If you need to see multiple values for the same header name, use "headerValues".

      Using the object "header" in JSTL is equivalent to using request.getHeader() in JSP.  They both use the Java method ServletRequest.getHeader() behind the scenes.  Using the object "headerValues" in JSTL is effectively equivalent to using request.getHeaders() in JSP.  They both use the Java method  ServletRequest.getHeaders() behind the scenes.  

      Note:  According to the JSTL 1.0 spec, "headerValues" returns an array of strings which it gets by calling ServletRequest.getHeaders(). However, ServletRequest.getHeaders() returns an Enumeration of strings, not an array of strings.  I'm not sure why headerValues would go to the trouble of converting the Enumeration to an array, so this may simply be a mistake in the JSTL spec.  One advantage of JSTL over JSP, however, is that you don't know or care.  You would write exactly the same JSTL code in either case.  

      If you don't care about multiple values for the same header, in JSP, you can write:

      <%@ page import="java.util.Enumeration" %>
      <% for (Enumeration enumNames = request.getHeaderNames();
              enumNames.hasMoreElements();
             )
         {
             String strName = (String) enumNames.nextElement();
             out.println("<b>" + strName + "</b>: "
                               + request.getHeader(strName)
                               + "<br />");
         }
      %>

      and in JSTL:

      <c:forEach items="${header}" var="h">
        <b>${h.key}</b>: ${h.value}<br>
      </c:forEach>

      Finally, compare the code here with the code in both of:
         
      Looping Through Cookies in JSP and JSP/JSTL EL
          Looping Through Parameters in JSP and JSP/JSTL EL
      Note how similar the JSTL code is for accessing headers and cookies, despite the fact that the JSP code is so different.  JSTL hides differences that you must be aware of when writing JSP code, especially iterating over an array vs. an Enumeration, and dealing with empty or null collections of values.

      --Fred

    13. Avoiding "code too large" errors

      Last Updated: 1/29/2008
      Applies to:  JSP 1.2+

      Ever get a "code too large" error from your JSP page?

      Problem:

      The Java JVM spec limits the total bytecode size of any single compiled method to 64K bytes.  See:
              http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#88659
      This is generally not a problem because you never need such a large method.  You can always refactor the code into multiple smaller, better methods.

      However, with JSP, it can be an issue.  Like all code generating frameworks, JSP removes you one level from the underlying code.  Since it is generating Java code for you, you have less control over the total size of that Java code.

      Also, like all JIT (just in time) compilers, JSP has another weakness.  It doesn't compile your code in advance so it can't
      catch all problems in advance.  The JSP code is compiled into Java code only at runtime, so the Java code is compiled into a Java class file (binary) only at runtime.  Therefore, some errors, like the Java "code too large" error, are reported only at runtime.

      So, how to prevent "code too large" errors?

      Solution 1:

      You can break a JSP page into multiple files via the JSP action:

              <jsp:include>

      described at: JSP/JSTL Actions.  This action causes an entirely separate JSP file to be invoked at runtime to generate part of the content of the same HTML page.  The generated Java code is a call to a separate Java method of a separate Java class, so the size of the Java code in the called method doesn't count towards the code size of the calling method.

      Note:  You cannot get the same benefit from the JSP directive:

              <%@include%>

      described at: JSP Directives.  This directive causes the contents of a separate JSP file to be included into the current JSP page at JSP compile time, so its contents become part of the same Java method.

      Solution 2:

      Sometimes it is not convenient to break a JSP page into multiple files.  

      In that case, you need the JSP page to generate multiple smaller Java methods within the same file.  You can accomplish this with any of the JSTL actions that have separate start and end tags and allow content between them.  See the list of JSTL actions at: JSP/JSTL Actions.

      Such actions generate a separate Java method to contain the nested content, and an inline call to that method.  For example, the contents of each JSTL <c:if> action become a separate Java method.  So do the contents of each <c:forEach> action, and each <c:when> and <c:otherwise> action of each <c:choose> action.

      Therefore, the simplest way to generate multiple smaller Java methods within the same JSP file is:

              <c:if test='true'>
                  This stuff becomes a separate Java method.
              </c:if>

      --Fred

  17. Finding JAR Files

    Original Version: 3/13/2012
    Last Updated: 3/17/2012
    Applies to:  Java 1.0+

    So, you're using a program that needs a particular Java class and don't know where to find the class?

    A good starting point, of course, is Google, which will probably lead you to one of these sites to decide which JAR file you need to download and add to your build path:

    But what if you already have a bunch of JARs and just want to know which existing JAR contains the class file?  Or what if you are worried that you have multiple JARs with different versions of the same class, and the wrong one is being found?

    You can use the jar command on each JAR file to list the contents of the JAR file, as:

    % jar -tvf some_jar_file.jar

    but that's really tedious if you have a lot of JAR files.

    Here's a Unix shell script I wrote:

    to search for the specified class name or partial class name, case sensitive or insensitive, in:

    • all of the specified JAR files
    • all of the JAR files on the CLASSPATH
    • all of the JAR files specified by the colon-delimited value of the specified environment variable (not necessarily CLASSPATH)
    • all of the JAR files in an entire directory tree
    • etc.

    It will also search for any file (not necessarily a Java class file) in any Unix "tar archive" (of which a JAR file is one example).  It runs on any Unix, including Linux and Mac OS X.  You can run it on Windows if you install cygwin to get a Unix shell environment:

    Or you can read the code of the shell script and convert it relatively easily to a Windows batch file.  It just finds all the JAR files, lists the contents of each via the jar -tvf command, and searches the output for the desired classname.

    For more on the jar command, type:

    % jar

    to see a summary of the command line options, or:

    % man jar

    to see the full manual page.

    See also:

    • http://java.net/projects/jarscan
      • Similar idea
      • Cons:
        • No case-insensitive search
        • No ability to specify an explicit list of JARs to search
        • No ability to search CLASSPATH or other environment variable
        • Does not show the dates, times, and sizes of the JARs
      • Pros:
        • Can report which class files are in multiple JARs (potential conflicts)
        • Searches ZIP files too, not just JARs
        • Can search the contents of each file in the JAR, not just the names
        • Can be told to search the contents of only manifest files
        • Can report the compiler version used to compile each class file

    • http://ant.apache.org/manual/Tasks/whichresource.html
      • The ant task "whichresource"
      • Searches all specified JARs for a specified class file
      • Sets a property to the full path of the JAR containing the class.
      • The property can be echoed, using in other ant tasks, etc.

    Thanks to:

    • Alex Kutovoy for telling me about findjar.com
    • Michel van der List for encouraging me to add the CLASSPATH option
    • Jeff Lobello for telling me about jarscan
    • Andy Glick for telling me about whichresource

    --Fred

  18. Why Teach Java?

    Original Version: 3/27/2007
    Last Updated: 5/20/2007
    Applies to:  Java 1.0+

    Someone asked me the other day whether Java would be a good language in an introductory programming class, especially as compared with Pascal, C and scripting languages like Perl, Python, etc.  This was my answer.

    One of the first languages I learned (in 1978) was Pascal.   It was a good choice for a teaching language because of its strong type-checking, and good support for data structures.  It enforced good habits, preventing you from doing sloppy things that C and scripting languages would allow.

    Also, the compiler catches lots of simple first-time-programmer errors.  Generally, almost anything you write in older versions of C or in a scripting language will get past the compiler or interpreter with no error messages, and will do something.  However, too often, it doesn't do what you intended, and you are left to puzzle out why not.  Pascal was a good safety net for me, shielding me from my own dumb mistakes and focusing me on the assigned problem.

    Java is even better than Pascal in these regards.  It has very thorough type checking, and a very powerful data structure library, as well as strong facilities for building your own data structures.  Also, it is free, very easy to get started with, and generates its own API docs (javadocs).  

    To see how easy it can be, read my first few articles on Getting Started with Java.  Each article is a bite-sized (usually one or two screens of text) intro to a single Java topic.  Despite their small size, each one is a complete working program, including details of how to download the compiler and other tools (Web servers, etc) that you might need, how to compile and run, etc.  See:
        http://bristle.com/Tips/Java.htm#applications
        http://bristle.com/Tips/Java.htm#applets
        http://bristle.com/Tips/Java.htm#servlets
        http://bristle.com/Tips/Java.htm#jsp_intro
        http://bristle.com/Tips/Java.htm#java_beans
        http://bristle.com/Tips/Java.htm#jdbc
        http://bristle.com/Tips/Java.htm#javadoc_intro

    Don't rule Java out simply because of its power.  It is very easy to get started, and to just use a small subset of the language until you are ready for more.  All of the local high schools and colleges I've contacted in recent years are moving from Pascal, C, and C++ to Java as a teaching language.

    Java runs on absolutely everything.  You write and compile the code once, and then run it on Mac, PC, Linux, PDAs, cash registers, cell phones, whatever.  Have you ever downloaded a large free software component from the Web and had to choose whether you wanted the Windows version, Linux version, Mac version, etc?  That question never comes up with Java.  You just download THE version and run it on whatever.  I've done that successfully with many large complex components like Web servers (Tomcat), XML parsers and XSLT transformation engines (Xalan/Xerces), complete development environments (Eclipse), etc.  Never a problem.  It just works.

    Furthermore, have you been frustrated that you ran a setup program to install a piece of software and suddenly unrelated things stopped working?  You really don't want to suggest that the students download and install any tools that might break their computers and cause them to lose the use of them for other classes.  With Java tools and components, you never run a setup program.  Just download the zip file, unzip it into any folder you like, and run it.  No chance to break anything else on the computer.  If you don't like it, just delete the folder.  No mucking around with registry entries, restore points, backups, etc.

    Speaking of development environments, the students will want a powerful IDE (interactive development environment) in which to edit, compile, and debug their programs.  Eclipse, written by IBM, is free and is the single most powerful IDE I've used in my 25 years of professional programming.  See:
        http://eclipse.org/

    Also, you will want books, and there are a ton of books on Java.  I particularly recommend "Thinking in Java" by Bruce Eckel:
        http://www.mindviewinc.com/
    though perhaps not for introductory students.  The instructor should read it however, and will come away completely convinced of the merits of Java and why it is such a good teaching language.  You can download the entire book for free, but I recommend buying a paper copy also because you'll want it handy to thumb through.

    There are even children's books, like: "Java Programming for Kids, Parents and Grandparents" by Yakov Fain:
        http://www.faratasystems.com/display_page.php?page_id=197
    Again, completely free to download, but your kids will also want the hardcopy.

    Anyhow, there are tons of other Java books, free and otherwise.  Do a Web search at Amazon, or O'Reilly, or walk into any bookstore and count the shelves of books of the various programming languages.

    Another argument for Java is its popularity. For recent trends in programming jobs, see:
        http://www.indeed.com/jobtrends?q=java%2C+c%2B%2B%2C+pascal%2C+c%23%2C+vb%2C+ruby%2C+perl%2C+python%2C+eiffel&l=

    For recent trends in Web searches, see:
        http://www.google.com/trends?q=java%2C+c%2B%2B%2C+pascal%2C+c%23%2C+vb%2C+ruby%2C+perl%2C+python%2C+eiffel

    Why not use Python or Ruby?  Scripting languages like Python and Ruby are great for real world SMALL programming.  They are powerful scripting languages that are good for demos, test harnesses, etc., but don't scale well to large mission-critical applications.  Not what you want to be teaching.  If so, you might as well teach in Perl, C, Javascript, VBScript, etc.  Powerful, but no discipline, so they tend to generate unmaintainable code.

    I hope this doesn't come off as a rant. After 25 years of working in dozens of different languages, and having to put up with the quirks and bugs of so many different environments, it is nice to finally settle on one that "just works".

    --Fred

  19. Easing Into Java

    Original Version: 3/21/2007
    Last Updated: 2/9/2008
    Applies to:  Java 1.0+

    Someone asked me the other day how to get started using Java.  There are so many different tools, libraries, and components that can be used with Java.  Where to start?  Here's my answer:

    Don't rule Java out simply because of its power.  It is very easy to get started, and to use a small subset of the language until you are ready for more.  All of the local high schools and colleges I've contacted in recent years are moving from Pascal, C, and C++ to Java as a teaching language.

    Java is very modular.  Instead of having everything built into one massive monolithic hulk, there are modules you can pick and choose from to do what you need to do, without carrying along all the other baggage.  They all work smoothly together, but you don't necessarily need all of them.

    Don't try to take it all on at once.  Why bother?  Just use what you need.  It's easy to get started, and easy to add more later.  Don't bother to dive into technologies that you haven't yet found a need for.  I don't believe in using technologies just because they exist.  Many of the latest fads you hear about are just "solutions looking for a problem" -- useless!  Java makes it very easy to use what you need and leave the rest behind.

    If someone challenges you, asking why you are not using some particular feature, get them to give you a detailed list of benefits, and decide whether any of them matter to your project.  Again, you will find lots of people trying to sell you solutions for problems you don't have.  Use what you need, and leave the rest.

    Learn Java in the same way that you read this message -- a piece at a time.  Both are written very incrementally, and very modularly.  If you start getting bored, you must have hit a solution that doesn't fit any of your current problems.  Not of interest right now, so skip to the next paragraph, or stop reading entirely.  Don't bother with things you don't need yet.  Just be aware that there is more out there when you need it.

    To see how easy it can be, read the first few articles of the "Getting Started" section of the Java Tips page at my web site.  Each article is a bite-sized (usually one or two screens of text) intro to a single Java topic.  Despite their small size, each one is a complete working program, including details of how to download the compiler and other tools (Web servers, etc) that you might need, how to compile and run, etc.  

    Start with a simple Java "Hello World" program:
        http://bristle.com/Tips/Java.htm#applications

    Then, if you need to run a small program inside a Web browser, instead of as a standalone program, try a simple Java "applet":
        http://bristle.com/Tips/Java.htm#applets

    If you need to run a small program inside a Web server, generating Web pages to be displayed in a browser, use a Java "servlet":
        http://bristle.com/Tips/Java.htm#servlets

    After a while, you may find that it is tedious to wrap all of your HTML in print statements.  So, add JSP pages to the mix.  Use JSP pages to replace those servlets that were mostly generating simple HTML, but continue using servlets for more complex things.  For a concrete example of this, see:
        http://bristle.com/Tips/Java.htm#jsp_intro

    Then, perhaps learn some of the additional power of JSP.  It does not do anything a servlet can't do, but it is often easier.  JSTL is another step in the same direction.  Nothing you couldn't do with a servlet or with JSP, but some things are again much easier.  For JSP and JSTL info, see the series of short articles and summary sheets at:
        http://bristle.com/Tips/Java.htm#jsp_jsp_intro
        http://bristle.com/Tips/Java.htm#jsp_directives
        http://bristle.com/Tips/Java.htm#jsp_scripting_elements
        http://bristle.com/Tips/Java.htm#jsp_and_jstl_actions
        http://bristle.com/Tips/Java.htm#jsp_and_jstl_implicit_objects
        http://bristle.com/Tips/Java.htm#jsp_and_jstl_el_syntax
        http://bristle.com/Tips/Java.htm#accessing_properties_of_objects_in_jsp_and_el
        http://bristle.com/Tips/Java.htm#el_convenience_objects
        http://bristle.com/Tips/Java.htm#enabling_el_expression_evaluation
        http://bristle.com/Tips/Java.htm#looping_through_cookies_in_jsp_and_el
        http://bristle.com/Tips/Java.htm#looping_through_parameters_in_jsp_and_el
        http://bristle.com/Tips/Java.htm#looping_through_headers_in_jsp_and_el
        http://bristle.com/Tips/Java.htm#avoiding_code_too_large_errors 

    If you need to access a relational database, start using the JDBC classes, as described at:
        http://bristle.com/Tips/Java.htm#jdbc

    Along the way, you'll start to hear about Java Beans.  Stop to read the two-pager:
        http://bristle.com/Tips/Java.htm#java_beans
    and learn that you have been writing Java Beans all along.  They are not huge complex things like Microsoft ActiveX objects.  In fact, the following is the complete source code for a trivial JavaBean:

        public class BeanWithNoProperties {}

    They are just as powerful as ActiveX objects, but much simpler, since all of the "discoverability" is already built in to the Java language.  All you have to do is follow a couple of simple conventions about how you name your methods.

    At some point, you'll want to automatically generate your API documentation from your code, producing docs like:
        http://bristle.com/Tips/javadocs/ 

    Want to generate such a set of docs with minimal effort?  The javadoc tool comes for free with the free Java compiler, so it is already installed and ready go on your computer. Just type:
        javadoc *.java
    as described in:
        http://bristle.com/Tips/Java.htm#javadoc_intro

    For a description of the layout and contents of the generated docs, see:
        http://bristle.com/Tips/Java.htm#javadoc_default

    Want more detailed docs, based on the comments in your Java code, not just on your Java code itself?  See:
        http://bristle.com/Tips/Java.htm#javadoc_comments

    Want the docs to contain even more detail about each method (descriptions instead of just names of each parameter, return value and exception)?  See:
        http://bristle.com/Tips/Java.htm#javadoc_tags

    For a complete small example, see:
        http://bristle.com/Tips/Java.htm#javadoc_example

    For a large example, see the Javadocs for the entire Bristle Software Java library:
        http://bristle.com/Tips/Java.htm#javadoc_bristle_java_library_javadocs

    Want more control over which portions of the docs are included or omitted, or the format of the generated pages?  See:
        http://bristle.com/Tips/Java.htm#javadoc_cli
        http://bristle.com/Tips/Java.htm#javadoc_formatting
        http://bristle.com/Tips/Java.htm#javadoc_doclet

    If you:

    1. Are planning a large Web application and want the benefit of a formal Model-View-Controller architecture to separate your user interface from your business logic, or
    2. Find it tedious and clunky to have each JSP page or servlet hardcoded to know the name of the next JSP page or servlet in your workflow, or
    3. Want a way to separate the presentation tier (JSP pages) from the business logic so that human factors people can do one and Java programmers can do the other, or
    4. Are just getting tired of writing lots of tedious repetitive code to check user input fields for errors and show error messages to the user

    you may want to look into the Struts library.  See links to lots of Struts info at my links page:
        http://bristle.com/~fred/#java_struts

    If you want a more object-oriented, less HTML-centric user interface, consider JavaServer Faces (JSF, not just JSP).  See my links at:
        http://bristle.com/~fred/#java_jsf

    If you are writing a lot of JDBC code for database access, you may prefer to use Hibernate:
        http://www.hibernate.org/
    or EJBs (Enterprise JavaBeans):
        http://bristle.com/~fred/#java_ejb

    If you are writing a huge application that has to manage thousands of instances of each object in memory at the same time, and run on multiple Web and application servers in a server farm, that's another reason to look into EJBs.

    If you want a more lightweight architecture, but still want the benefits of an "inversion of control" framework to automatically instantiate your Java Beans, and offering dependency injection, service abstractions, and aspect oriented programming (AOP), you may want to look into the Spring framework:
        http://www.springframework.org/

    If you are writing a time-critical system that must queue some work to be done later, or a distributed system that must queue messages for other systems, you may want to look into JMS (Java Message Service): 
        http://java.sun.com/products/jms/

    Each of these increments is compatible with all of the others.  Mix and match as you like.  Use what you need and leave the rest. 

    --Fred

  20. See Also

    Last Updated: 6/21/2000
    Applies to:  Java 1.0+

    The following are good sources of info about Java:

    1. The official Java docs from Sun:  http://java.sun.com
    2. Fred Stluka's Java links
    3. [Eckel00] -- Eckel, Bruce, Thinking in Java, 2nd edition, May 2000
    4. Hunter, Jason and Willam Crawford. Java Servlet Programming. Sebastopol CA: O'Reilly & Associates, Inc., 1998. ISBN 1-56592-391-X.
    5. Any of the O'Reilly books on Java.

    --Fred

©Copyright 1998-2021, Bristle Software, Inc.  All rights reserved.