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.
Last Updated: 9/5/2000
Applies to: Java 1.0+
Here are some of the differences between Java and C++:
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 |
for (i = 1, j = 1; i < 10; i++, j++) {...}
{ 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; }
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.
MyParent::member1
Java uses the keyword super for this as:
super.member1
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.
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.
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.
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.
class MySubClass : public MyBaseClass { ... } class MySubClass : private MyBaseClass { ... } class MySubClass : protected MyBaseClass { ... }
Java offers only public inheritance. The syntax is:
class MySubClass extends MyBaseClass { ... }
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.
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.
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.
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.
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);
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.
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.
--Fred
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
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
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
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
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:
--Fred
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
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:
- Public constructor exists by default.
- Standard getters and/or setters are defined for zero or more of the properties.
- Internal property values are declared "private" to prevent bypassing the accessor methods.
- Each property may have a getter, a setter, both or neither.
- Getters and setters may compute values instead of mapping directly to internal variables.
- Names of the arguments for getters and setters are irrelevant.
- Setters must return "void".
- Getters must take no arguments.
Common uses of Java beans are:
- 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.
- As simple data objects that are pluggable into a wide variety of frameworks. For example, "backing beans" for JavaServer Faces applications.
- 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:
- 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.- Must support "introspection" which all Java objects do via "reflection", but a bean can choose to explicitly use the BeanInfo class instead.
- Can register with other beans of interest as a "listener" to be informed of "events" that occur to those beans.
- Can support custom "property editors" for use in property sheets of an enclosing application.
For more info, see:
--Fred
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:
- Call conn.setAutoCommit(false), and explicitly call conn.commit() or conn.rollback().
- Prepare statements (for faster repeated execution) via conn.prepareStatement().
- Call st.registerOutParameter(n, oracle.jdbc.driver.OracleTypes.CURSOR) to return resultsets as output params or function return values.
- Specify resultSetType values on the call to createStatement(), prepareCall(), or prepareStatement():
ResultSet.TYPE_FORWARD_ONLY
ResultSet.TYPE_SCROLL_INSENSITIVE
ResultSet.TYPE_SCROLL_SENSITIVE- Specify resultSetConcurrency values on the call to createStatement(), prepareCall(), or prepareStatement():
ResultSet.CONCUR_READ_ONLY
ResultSet.CONCUR_UPDATABLE- Get connections from a connection pool, instead of creating a new one for each query.
- etc.
Thanks to John Moore for pointing out a typo in this tip!
--Fred
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:
--Fred
Last Updated: 10/13/2000
Applies to: Java 1.0+
Coming soon...
--Fred
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
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
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
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
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
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
Last Updated: 6/25/2000
Applies to: Java 1.0+
Here are some of the differences between arrays and containers:
--Fred
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
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
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
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:
Java 1.0 | Java 2 |
Vector | ArrayList |
Stack | LinkedList |
HashTable | HashMap |
--Fred
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
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.
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
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
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
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
Last Updated: 7/23/2000
Applies to: Java 1.0+
Java offers several ways to determine the type of an object at run time:
try { DesiredClass objDesired = (DesiredClass)objSomeObject; } catch (ClassCastException e) { // ... deal with error here ... }
if (objSomeObject instanceof DesiredClass) ...
However, this requires you to hard-code the name
of the desired class.
if (objDesired.getClass().isInstance(objSomeObject) ...
--Fred
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
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
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
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
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
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
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:
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:
--Fred
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:
--Fred
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
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
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
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
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
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
Last Updated: 11/30/2006
Applies to: JSP 1.2+
See:
--Fred
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
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
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 |
|
|
|
|
JSTL functions | |||
|
For details, see:
Fred's JSTL links
JSTL Spec
JSTL
Tags
JSTL
APIs
--Fred
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:
- Objects created by JSP pages via the JSP standard action: <jsp:useBean>
- Objects created by custom tags via the JSP directive: <%@ variable %>
- 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
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
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:
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
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:
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
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
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
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
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 /> " + 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 /> ${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
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 /> " + 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 /> ${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:
--Fred
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
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:
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:
Thanks to:
--Fred
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
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:
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
Last Updated: 6/21/2000
Applies to: Java 1.0+
The following are good sources of info about Java:
--Fred
©Copyright 1998-2021, Bristle Software, Inc. All rights reserved.