5/31/2006

Blame Iterator

java.util.Enumeration and java.util.Iterator have a prominent place in Java Collection Framework. Personally, I only use them locally inside a method to traverse a collection. I don't use it as a return type or pass in as a parameter. So far so good.

Recently we had to invoke a public method in another module, which happen to return an instance of java.util.Iterator. The hard part is, in certain cases, we need to traverse the data twice, but the default implementation of java.util.Iterator is not rewindable. A workaround is to save the data in a class variable collection during the first pass, so the second pass can operate on the cached data. This hideous idea was quickly dismissed.

We could've requested the other team to return the underlying collection. But it was close to release and they had every reason to turn it down. In addition, they are hard to work with ...

I forgot how we solved it. But the lesson is, don't use java.util.Iterator, or java.util.Enumeration in public API, either as return type, or method parameters. Instead, use the underlying collection interface directly (e.g., java.util.List, java.util.Set, java.util.Queue). More reasons:

  • Iterator is too generic.
    You may view it as its advantage, as it shields the client code from the underlying implementation. Most of the time, I do need to know one thing or two about the underlying data structure. For instance, if it's of type java.util.List, I know it's ordered and can traverse it with index instead of Iterator. If it's of type java.util.Set, I know it contains distinct elements and I would traverse it with Iterator. Interfaces like List and Set already provide us with enough isolation and transparency.

  • Iterator is too restrictive.
    It doesn't rewind or tell you its size. It exposes a very narrow view of the underlying data structure. This interface only has 3 methods: hasNext(), next(), and remove(). I've never used remove(), since removing elements this way is very hard to keep track of.

5/30/2006

Unnecessary Cast in Map

Unnecessary casts clog your code and slow down you applications. They may seem small individually, but if they are inside loops or frequent code paths, they do add up. One common unnecessary cast happens to java.util.Map key:

public static void unnecessaryCast() {

Map map = new HashMap();
map.put("language", "Java");

for(Iterator it = map.keySet().iterator(); it.hasNext();) {
//casting key to String is unnecessary for map lookup
String key = (String) it.next();

//casting to String is unnecessary for println
String val = (String) map.get(key);

System.out.println("key = " + key + ", value = " + val);
}
}
Casting (in red) for the map key is not needed for the purpose of calling java.util.Map.get(key), unless you also need a String type of key later.

Casting (in blue) for the map value is not needed for the purpose of System.out.println(value), unless you also need a String type of value later. JVM will correctly dispatch to String.toString() when you concatenate ", value = " to an java.lang.Object value.

So I would simply change the two lines to:
Object key = it.next();
Object val = map.get(key);

5/28/2006

Our of Memory on Memorial Day

I ran into some java.lang.OutOfMemoryError: Java heap space over this Memorial Day weekend. That's quite a coincidence. Actually, it can happen on any day, especially at night from my experience.

It's also a popular Java job interview question: why are there memory leaks in Java programs? Isn't Java supposed to automatically manage memory and garbage collection? How do you debug and solve it? Number one cause of memory leak is these dying objects are still referenced by other long-living objects. This is a simple program to reproduce java.lang.OutOfMemoryError:

package com.javahowto.test;
import java.util.Map;
import java.util.HashMap;

public class MemoryHog {
public static final Map threadMap = new HashMap();

public static void main(String[] args) {
MemoryHog hog = new MemoryHog();
for(int i = 0; ; i++) {
hog.work(String.valueOf(i));
}
}

private void work(String id) {
Thread thread = new Thread(){
public void run() {
//@TODO: do some work
}
};
System.out.println("Current thread map size: " + threadMap.size());
threadMap.put(id, thread);
thread.start();
}
}
Running with default JVM options (heap size 64m), MemoryHog crashes when the pool size reaches 296,733. Various solutions are available:
  • Application designers will get rid of the pooling, or implement it correctly such that it reuses threads and set pool's initial size, max size, incremental size, and eviction policy. MemoryHog runs happily ever after.

  • Coders will just change the HashMap to java.util.WeakHashMap, and MemoryHog runs happily ever after.

  • Hackers will bump up heap size, with JVM option -Xmx128m. MemoryHog runs happily until the pool size grows to 592,646. Then keep doubling the heap size to make MemoryHog happy.

1-Minute Quiz: Why is Hyphen Illegal in Identifier?

Why is hyphen (-) an illegal char in Java identifier? Why can't we use variable names like first-name, as we do in xml files? The answer to this question is not hard, but the challenge is, can you answer it in 1 minute. I didn't.

  • First, hyphen is the same symbol as the arithmetic operator minus. So for variables like first-name, we don't know if it's a single variable named first-name, or the numeric variable first minus another numeric variable name. Neither does the compiler. So the easiest solution is to disallow -. XML is a markup mark-up language, not programming language, so hyphen is no problem there.

  • Secondly, hyphen is already used in other operators like ->, though it's not in Java yet. If you have an expression like first-result->second, you don't know if it's a pointer operation, or a comparison between first-result- and second. Java has rejected -> from C++, but maybe one day it will take it from PHP.

5/27/2006

Job Trend, Not Google Trend

Wanna know the amount of Java jobs versus .Net jobs, or the growth of AJAX jobs? Google Trend may be able to help you a bit, but the result is not scoped for jobs only. Indeed.com has a bunch of cool tools for these kind of job data-mining.

For example, here is the big jump of AJAX jobs during the past year. I'm a little suspicious about this comparison between Java jobs vs .Net jobs.

The website states that "Indeed.com searches millions of jobs from thousands of job sites. This job trends graph shows the percentage of jobs we find that contain your search terms." Not sure how good their sampling is.

Another highlight is Job Postings Per Capita. I'm surprised to see NYC ranks only 40th, after Kansas City and Columbus, OH, both with much smaller population size.

5/26/2006

Java Certification: Take SCJP and Ignore the Rest.

Sun has provided various Java certifications such as SCJP, SCJD,SCEA,SCWCD, SCBCD, etc. As you move upwards in the certification stack, the marginal utility diminishes quickly.

For an entry-level programmer, preparing for SCJP is a good way to get familiar with language basics. It also proves to potential employers that you are a motivated learner. If I were to choose from a pile of resumes, those with SCJP will certainly stand out. At this stage, they are judged more by knowledge than by experience.

For seasoned developers, their value lies in experience that is hardly testable. They may not know the details about certain API, and may even fail SCJP, but they've accumulated do's and don'ts from various successful and failed projects. They have guts feeling why certain design is better. They can smell it when some code is fishy. Because they know where to locate knowledge quickly, and how to leverage tools (such as IDE, debugger and profiler), they pay less attention to knowledge.

None of these values are easily testable in standardized format, even with some sort of sample design and essay. When applying for architect or lead developer position, certification just becomes irrelevant.

5/25/2006

Still Have Public No-arg Constructors in Util Classes?

If your answer is "No", check again. Even if there is no public no-arg constructor physically in the java file, the compiler will generate one in the class file, the default constructor. You can disable this by adding a private no-arg constructor. This is what I would recommend in every new utility class:

private Util() {
//disable external instantiation
}
By utility class, or helper class, I mean those classes having only static methods and fields, whether they are public or protected. They are much like a kitchen sink. They don't represent any entities in your model, and have no distinct identity. Therefore, they should never be instantiated. By disallowing instantiation, you also save a little memory usage.

These "handy classes full of static functions" are developers' favorite, used in every project. Can you name a project without a utility class? Unfortunately, a lot of them still implicitly allow instantiation. For instance, these classes in JDK:
  • java.util.XMLUtils (package-level class, not public, but still doesn't make sense to allow itself to be instantiated)

  • javax.swing.text.Utilities (public class, everybody in the world can instantiate it)

  • com.sun.corba.se.impl.util.Utility (public JDK internal class, though you should not directly use it)
PS: I should also add this caution: don't add a private no-arg constructor to existing util classes. Doing so will break all the clients that are using this implicit public no-arg constructor. It also makes this util class no longer inheritable, and so none of its subclasses will compile or run. The best you can do is probably add a @Deprecated public no-arg constructor with some sort of warning messages.

Are these classes so-called static classes? Well, there is no such term "static class" in java, and no top-level class can be static. There are only classes with static methods. Of course, an inner class can be static.

5/23/2006

If You Can Learn Only One Annotation

JDK 5 (aka 1.5) introduced annotations along with 6 built-in annotations. For most developers, only 1 is really worth attention: java.lang.Override. I haven't found any need to use the other 5 build-in annotations: Deprecated, Documented, Inherited, Target, RetentionPolicy.

How to use @Override?

Use it whenever a subclass overrides a method in any of its superclasses. For example:

@Override
public boolean equals(Object other) {
throw new UnsupportedOperationException("Not yet implemented");
}
If you incorrectly override the method like @Override public boolean equals(MyType other), Javac will do you a favor by issuing an error: equals method does not override any method in its superclass.

Without the help from @Override, this buggy code will pass compilation and fail randomly at runtime. The equals method in subclass won't be invoked where you think it should be. It was overloading, not overriding equals method in superclass.

When not to use @Override?

Don't use annotations if your apps may need to support JDK 1.4 or earlier. There may be some libraries enabling annotations in pre-5 JDK, but why the extra dependecy for little gain?

Don't use @Override when only implementing a method declared in an interface.

Where to put @Override?

You don't have to place @Override in its own line. In fact, any of the following is good:
  • @Override public void foo()
  • public @Override void foo()
  • public @Override synchronized void foo()
  • public synchronized @Override void foo()

Generating Java Best Seller Book Titles

A slews of books are written for each tech buzz, and their titles are so similar to the point you can reliably predict it. Just for fun, I've written a simple Java class to generate these titles.

import java.util.Arrays;
public class BookTitlesGen {
public static final String[] technologies = new String[]{
"AJAX", "EJB3", "JSF", "Web Services"
};

public static final String[] templates = new String[] {
"XXX in Action", "Professional XXX",
"Effective XXX", "Master XXX",
"XXX Definitive Guide", "Core XXX",
"XXX Cookbook","XXX Bible",
"Head First XXX", "XXX Best Practice",
"A Developer's Guide to XXX",
"XXX Unleashed", "XXX for Dummies",
};

public static void main(String[] args) {
genBookTitles();
}

private static void genBookTitles() {
for(String technology : technologies) {
String banner = "Best Seller Books for " + technology;
char[] line = new char[banner.length()];
Arrays.fill(line, '=');
System.out.println(banner);
System.out.println(line);
for(String template : templates) {
String title = template.replaceAll("XXX", technology);
System.out.println(title);
}
System.out.println("");
}
}
}

Best Seller Books for AJAX
==========================
AJAX in Action
Professional AJAX
Effective AJAX
Master AJAX
AJAX Definitive Guide
Core AJAX
AJAX Cookbook
AJAX Bible
Head First AJAX
AJAX Best Practice
A Developer's Guide to AJAX
AJAX Unleashed
AJAX for Dummies

Best Seller Books for EJB3
==========================
EJB3 in Action
Professional EJB3
Effective EJB3
Master EJB3
EJB3 Definitive Guide
Core EJB3
EJB3 Cookbook
EJB3 Bible
Head First EJB3
EJB3 Best Practice
A Developer's Guide to EJB3
EJB3 Unleashed
EJB3 for Dummies
They are roughly in the order of popularity. To save space, I omitted the output for JSF and Web Services. Can't we have better names?

5/22/2006

EJB3 Quiz from Sun

Questions cover various major changes in EJB3 Simplified API, are tricky questions. If you are familiar with EJB 2.x but new to EJB3, you may be surprised by some answers. So go ahead test your EJB3 knowledge here.

These are some take-away points after I took the quiz:

  • Directly Use Object.equals(Object other) to compare EJB3 session bean references. No more isIdentical(EJBObject other).

  • EJB3 lifecycle methods, interceptor methods, and injection fields/methods can be of any access type: public, protected, private, or default.

  • Use SessionContext.lookup(String name) to lookup EJB and resources, e.g., sctx.lookup("jdbc/defaultDB"); Note the name has no prefix "java:comp/env". This prefix is still required in regular JNDI lookup.

  • A EJB3 session bean can have any number of local and remote business interfaces. But an interface cannot serve as both the remote and local interface for a bean.
Tags: , , , ,

5/21/2006

JAVA_HOME vs java.home

What's the difference between JAVA_HOME and java.home? JAVA_HOME is the JDK install directory, e.g., C:\jdk5. It's meant to be set as an environment variable and referenced in Windows batch files or Unix scripts. I always have it in my Windows Control Panel and .tcsh files,along with other common environment variables. Some Java applications use the name jdk.home for this purpose, which I think is a better name. But JAVA_HOME has been used since the beginning and is now a convention.

java.home is the JRE install directory, e.g., C:\jdk5\jre, or C:\Program Files\Java\jre1.5.0_06. Unlike JAVA_HOME, I never seen java.home as an environment variable. java.home is a build-in Java system property, whose value is the JRE install directory. Since all Java system properties are also exposed as Ant build properties, you can also use ${java.home} in build files.

Would jre.home be a better name? Maybe, but I don't think Sun will change it.

Therefore, java.home is always there inside JVM, whereas JAVA_HOME exists mainly in your shell environment and you may pass it to JVM as a system property. Why do we still need JAVA_HOME? Well, there are good reasons:

  • You can add $JAVA_HOME/bin to the beginning of your PATH, to make sure you always invoke the right java program. On Windows, java.exe is duplicated in several places, for instance %JAVA_HOME%\bin\java.exe, $JAVA_HOME\jre\bin\java.exe, and %SystemRoot%\system32\java.exe. Without have $JAVA_HOME/bin at the beginning of the PATH, a java command will always resolve to %SystemRoot%\system32\java.exe, which may not be what you want. The same problem can also exist in Linux/Solaris.

  • Some Java application runtime needs to use tools/libraries only available in JDK. For example, web containers need tools.jar in JDK to compile JSP pages, and ejb containers also need to invoke javac/rmic tools in JDK. So the build-in system property java.home is not sufficient.

    A Common Mistake with Java SecurityManager.

    I've seen some Java application launcher scripts like this:

    java -Djava.security.policy=security.policy Main

    It works fine but the SecurityManager is not installed, despite the presence of java.security.policy system property. It is unclear whether the author intends to install a SecurityManager or not. The point is, Java security design allows the separation of enabling the SecurityManager and security requirements. Therefore,

    • To run with SecurityManager and default Java security policy, which is $JAVA_HOME/jre/lib/security/java.policy:

      java -Djava.security.manager Main

    • To run with SecurityManager and only your custom security policy (ignoring default java security policy):

      java -Djava.security.manager -Djava.security.policy==security.policy Main

    • To run with SecurityManager and default java security policy first, then your custom security policy:

      java -Djava.security.manager -Djava.security.policy=security.policy Main

    • If you don't want a SecurityManager, then simply leave out java.security.policy to avoid any confusion.

    5/20/2006

    Debug java util MissingResourceException

    java.util.MissingResourceException Can't find bundle for base name, locale...How did I get this exception? The crux of this problem is the requested resource, in most cases, a properties file, is not configured correctly in the classpath. For example, you have a properties file, connection.properties, in the same source directory as Java source files. Javac will compile *.java into *.class in a target directory such as build/classes, which is in your runtime classpath. But connection.properties is not copied into build/classes directory unless you either add a <copy> task after <javac> in the Ant build file, or do so manually.

    How to fix it? Make sure this resource is configured correctly in the classpath through one of the following:

    • Like I said above, copy the resource from source directory to build/classes directory, which is in the classpath.
      • If your code is like ResourceBundle.getBundle("connection"), then after copying you should have build/classes/connection.properties.
      • If your code is like ResourceBundle.getBundle("com.javahowto.test.connection"), then after copying you should have build/classes/com/javahowto/test/connection.properties.
    • Or you can choose package resources into a jar file, say, connection-info.jar, which is included in runtime classpath (not needed in Javac classpath).
      • If your code is like ResourceBundle.getBundle("connection"), then connection-info.jar should contain this entry: connection.properties.
      • If your code is like ResourceBundle.getBundle("com.javahowto.test.connection"), then connection-info.jar should contain this entry: com/javahowto/test/connection.properties.
    • Or you can choose to put the resource in a separate resources directory, include resources directory in runtime classpath. This way you don't have to duplicate the resource in multiple directories/jar. The disadvantage is it's a little inconvenient at development time to have resource in a separate directory than Java code.
      • If your code is like ResourceBundle.getBundle("connection"), then you should have resources/connection.properties.
      • If your code is like ResourceBundle.getBundle("com.javahowto.test.connection"), then you should have resources/com/javahowto/test/connection.properties.

    tags: , , ,

    5/19/2006

    Java Jar File Naming Conventions and Examples.

    util.jar is the worst jar file name I can think of. All I know is it contains some utility/helper classes. But it is unclear if they belong to an application server, or a framework, or any application sub-systems. You will need to ask someone or some docs to know what it is. It's part of the DataDirect JDBC Driver distribution.

    On the other hand, good jar file names are always self-explanatory, for example: struts.jar, jboss-system.jar, commons-pool-1.1.jar

    Some thoughts on jar file naming conventions:

    1. Always use extension ".jar", not ".zip"
      Theoretically, jar files can have any extension or no extension at all. If you specify it in the system classpath, it should be loadable. The problem is with automatic library detection and loading by containers and frameworks. It's expensive to scan all files so some sort of extension restriction is needed. For this reason, J2EE/JavaEE platform spec requires all library jar files use ".jar" extension, such as WEB-INF/lib/mybeans.jar.

    2. Use hyphen (-) instead of underscore (_) as word separator
      First, it's easier to type - than _; secondly, when the file name is underlined (e.g., in a hyperlink), the _ is invisible. Hyphen has been shunned in file names partly because it is an illegal character in java identifier. But this concern is unwarranted.

    3. Append version number if distributed standalone
      because they can be dropped into any applications, which may need specific versions. We don't want users to have to compare file size or extract some META-INF files to know its version. Some examples: hibernate3.jar, commons-logging-1.0.3.jar, and
      log4j-1.2.8.jar
      .

    4. Don't append version number if bundled inside other larger deliverables
      because the enclosing deliverables, such as an application server (e.g., JBoss 4.0.4, jakarta-tomcat-5), a tool(e.g., apache-ant-1.6.5), aleady have the version numbers, thus no version number for jboss.jar, catalina.jar, and ant.jar.
    Tags: ,

    5/18/2006

    The Worst Java Job Interview Questions.

    Why are you looking for a job?

    Strictly speaking, this is not a java question, but it shows up in almost every job interview I've been to. The interviewer is testing the candidate's motivation for a job change. Invariably, the answer will be something like, advancing career and professional development. Of course, the candidate won't tell you he/she is looking for a 15% salary increase to cover the gas price increase, or he doesn't get along with his co-workers, or he didn't get the promotion or bonus, or he was rated Under-Perform in last year's performance review.

    Which OS do you use in your development work, Linux, Windows, or Solaris?

    Java is cross-platform, and I couldn't care less about OS while I'm writing java code. Unless the job is specifically about porting applications to other OS and deploying/distributing applications, I don't see how this is relevant. J2EE, JavaEE and Web applications are all made up of components that are managed by the application server, and thus shielded from the underlying OS.

    Are you familiar with Oracle Database, or DB2?

    Java persistence can now be easily achieved with ORM frameworks such as Hibernate, TopLink. The latest release of EJB 3 and Java Persistence API has standardize the way persistence is done in Java, J2EE, and JavaEE. The goal of these industry efforts is to let Java developers forget database stuff, which should be left to DBA. Even if Java developers in this project need to deal with database directly, I suppose they need to know about database design concepts and SQL, not some Oracle or DB2 stored procedures.


    5/17/2006

    What does rt.jar stand for in Java/JDK/JRE?

    The most likely answer is, rt stands for RunTime. Some tend to think it stands for RooT, since this jar contains all java build-in classes. But I have yet to find any official Sun documents regarding this acronym.

    Whether it stands for RunTime, RooT, or anything else is not important. The question I have is, why would the java creator chose to use such a undescriptive name. Maybe it can make your classpath shorter? But we rarely put rt.jar in system classpath.

    Here are 2 reasons I don't like the name rt.jar:

    • While experienced developers take it for granted, java beginners don't know what it is other than it's a jar. So it's one more questions in beginners' mind.
    • The shorter the name, the easier it is to cause naming conflicts, at least visually. While rt.jar will always reside under $JAVA_HOME/jre/lib, it is possible your applications may have another jar also named rt.jar.
    I know rt.jar will be with us as long as java is, but just for the sake of discussion, how would you name it differently? Maybe java.jar, or java-core.jar?

    PS: What does jar stand for? Jar stands for Java Archive. A jar file usually has file name extension .jar. It contains mainly java class files but any types of files can be included, e.g., XML files, HTML files, properties files, gif/jpg image files, text files, PDF files, and binary files, and so on.

    PS: What is the difference between a jar file and a zip file? Basically, a jar file is the same as a zip file, except that the jar file contains a META-INF directory to store metadata or attributes. The most well-known file is META-INF/MANIFEST.MF. You can customize the content of a MANIFEST.MF when creating a jar file, and if you don't, a default one is generated and included. For example:
    Manifest-Version: 1.0
    Created-By: 1.5.0_06 (Sun Microsystems Inc.)
    It's perfectly fine to have other configuration files and directories under META-INF.
    Tags: , , ,