Tips 'N Tricks
EnumSyntax can provide a solution for integer-based enums
It seems like J2SE (Java 2 Platform, Standard Edition) 1.4 supplies
EnumSyntax as a generic base class for enumeration types. It implements
readResolve() so you don't have to and implements
Cloneable. This seems like a good base for application specific enums—I don't know why Sun Microsystems stuck it in the print package instead of
EnumSyntaxis an abstract base class providing the common implementation of all 'typesafe enumeration' objects." (From javax.print.attribute.EnumSyntax.)
Andrew, Thank you for bringing the
EnumSyntax class to my attention. Yes, it is an obscure package, one that I haven't had the pleasure of visiting. As you point out, the
EnumSyntax class looks useful for integer-based typesafe constants, however, using the
EnumSyntax class does mean you must provide integer values for each field in the subclass, something that can be prone to duplicates occurring due to cut and paste or programming errors. With non-value-based constants, these types of errors cannot occur. Ultimately, it comes down to what developers want out of a typesafe enum/constant—if they don't need to use the underlying integer or string then a non-value-based constant (like my first
NumberConstant example) will do. On the other hand, as you say, the
EnumSyntax class can provide a simple solution for integer-based enums. Philip Bishop
Another approach: Keep a field semantically equivalent to the type
I'm a big fan of the typesafe enumeration too; I have been since my C++ days.
One thing I like to do is keep in the class a field semantically equivalent to the type I'm trying to describe. In your
NumberConstants example, it could be an integer, other times a string. This field is initialized with the constructor.
Then, if you override
compareTo(), you have a class that deals well with serialization. Unless I'm working with primitives, I try to avoid comparisons using the
== operator at all costs.
Gareth, I generally agree that the technique you describe is a good solution to the serialization problem and also allows the enums to be used with collections. However, cases exist where you might simply want to use a typesafe enum in a distributed system and not bother overriding
hashcode(), and so on—this is why I came up with the
AbstractConstant class. In fact,
AbstractConstant emerged while I was working with Jini and JavaSpaces, which have different serialization semantics. In
Entry classes, each field is serialized separately, instead of the whole object. Initially I used value-based enums (along the lines you describe) so that the
Entry objects containing enums could be matchable, but this became tedious. So I tried to come up with a simple and reusable solution—hence the birth of
AbstractConstant. Philip Bishop
Can you mix getBundle() with getResource()?
I learned that
a.package.name.SomeClassName.class.getResource("name.properties") is better than
SomeClassName.class.getClassLoader().getResource("a/package/name/name.properties") because you eliminate duplicate code.
I wonder if this can be applied to load resource bundles. As far as I know, you have to use
ResourceBundle.getBundle("a/package/name/name",locale) to load the
"a/package/name/name.properties" resource bundle, but this method suffers from the same drawback.
Dieter, I can say that
ResourceBundle does not provide package-relative lookup like
Class.getResource(). Technically, it is possible even though
getBundle() is a static method, but Sun Microsystems simply did not implement it like that. Unfortunately, Java does not have API uniformity in this area. Also,
getBundle() uses dots for package name delimiters, not slashes, so the code will actually read
ResourceBundle.getBundle("a.package.name.name",locale). This different naming convention is another reason why
getBundle() cannot be mixed easily with
getResource() if the resource names come from system properties, other property files, and so on. Vladimir Roubtsov
How do you accurately profile small code segments with repeatable results?
At the end of your article, you comment that the CPU time measured by your method is wall-clock time as opposed to true CPU usage. In your experience, how repeatable are the results from this method (What is the average variance due to OS noise?)?
We are trying to find a way to do performance analysis on some automatically generated test code (basic asserts and precondition checking) to see how much it affects the runtime. Theoretically, that will be a small number sometimes—on the order of a few microseconds. I have some other options available, such as looping the test code repeatedly to consume enough time for the JVMPI (JVM Profiler Interface) to notice, but that still leaves me with an inaccuracy of plus or minus one microsecond.
Given your experience, what would you say is the most accurate way to profile small Java code segments with repeatable results?
Joseph, I must point out that if a Java code segment is short enough, even a solution like the one in my article becomes inadequate, due to the unavoidable native method call overhead (which has been mounting with increasing JDK versions). The only workable approach that remains is to have direct JVM support implemented with little overhead—basically, something like JVMPI, with high resolution timing or direct counting of byte code/native instructions. That approach is within the abilities of an individual or a small team of developers, especially if it is done once for a research project. However, the same approach would prove time-consuming for a commercial software company, especially since it would require staying in sync with Java releases. As an example, groups within IBM that used an IBM JVM specially instrumented to measure RMI (remote method invocation) overhead have published performance reports. Those reports used a custom-instrumented Java 1.1 JVM and were never reproduced with later JVMs. In general, this approach is hard to follow for any commercial company that does not build their own JVMs. In my experience, the results based on measuring wall-clock time have been quite reproducible. Of course, I would usually try to have my machine just run the JVM process and nothing else (and have the JVM run just the code being profiled in a single thread, if possible). This differs from your situation, where you probably measure overhead under normal execution circumstances. Another factor that affects wall-clock time measurements is garbage collection activity. Sometimes, a measured data point will be outlaying, as much as by several orders of magnitude. Even though such data points could be relatively rare, the extreme degree to which they differ from normal data points can noticeably affect the statistical average. Because of that, I developed a habit of collecting many data points and using, say, a 90 percent percentile as my final value and not relying on the traditional average. In the end, because of the unpredictable nature of garbage collection interference, I prefer to use an API that provides true CPU usage data. For your project, your approach seems the best, given the requirements. You might want to consider taking Sun Microsystems' public sources for the HotSpot 1.4 JVM and rebuilding them with a high-resolution timer in their JVMPI implementation. Vladimir Roubtsov
What about other JNI libraries?
You wrote a good and useful article, but if you're going to propose a JNI (Java Native Interface) library to accomplish something, it's useful to have a Linux (maybe even a Solaris) JNI library also.
I've had a need for what you describe, and you hit the nail on the head. But, for a platform-neutral programming language, some more JNI libraries should be provided.
Mark, I understand your remark; however, an implicit message in the article was for Java programmers not to shy away from a little native coding if that is what it takes to solve a Java-related programming problem. In my JavaWorld articles that use JNI, the amount of native code is limited to just a few lines of C code. The intent is to encourage people to port the idea to their platform of choice. Turning that sample code into a well-polished library would require maintaining it in a source control revision system with builds for every popular platform. I happen to know that on Solaris you would use
gethrtime() to gain access to a similar high-resolution CPU counter. Vladimir