| By Jess Garms, Tim Hanson | Article Rating: |
|
| February 6, 2006 11:30 AM EST | Reads: |
33,221 |
Enumerations
Enums are a lot like public static final ints that have been used for many years as enum values. The biggest and most obvious improvement over ints is type safety - you cannot mistakenly use one type of enum in place of another, unlike ints, which all look the same to the compiler. With very few exceptions, you should replace all enum-like int constructs with enum instances.
Enums offer a few additional features as well. There are two utility classes, EnumMap and EnumSet, which are implementations of standard collections optimized specifically for enums. If you know your collection will contain only enums, you should use these specific collections instead of HashMap or HashSet.
For the most part you can do a drop-in replacement of any public static final ints in your code with enums. They're comparable, and can be statically imported so that references to them look identical - even in the case of an inner class (or inner enum). Note that when comparing enums, the order they are declared indicates their ordinal value.
"Hidden" Static Methods
There are two static methods that appear on all enum declarations that you write. They don't appear in the javadoc for java.lang.Enum, as they are static methods on enum subclasses, not on Enum itself.
The first, values(), returns an array of all of the possible values for an enum.
The second, valueOf(), returns an enum for the provided string, which must match the source code declaration exactly.
Methods
This is one of our favorite aspects of enums: they can have methods. In the past you might have some code that performed a switch on a public static final int in order to translate from a database type into a JDBC URL. Now, you can have a method directly on the enum itself, which can clean up code dramatically. Here's an example of how this is done, with an abstract method on the DatabaseType enum and implementations provided in each enum instance:
public enum DatabaseType {
ORACLE {
public String getJdbcUrl() {...}
},
MYSQL {
public String getJdbcUrl() {...}
};
public abstract String getJdbcUrl();
}
Now your enum can provide its utility method directly. For instance:
DatabaseType dbType = ...;
String jdbcURL = dbType.getJdbcUrl();
Previously you would have had to know where the utility method was for getting the url.
Varargs
Varargs can really clean up some ugly code, when used correctly. Here's the canonical example: a log method that takes a variable number of string arguments.
Log.log(String code)
Log.log(String code, String arg)
Log.log(String code, String arg1, String arg2)
Log.log(String code, String[] args)
The interesting item to discuss about varags is the compatibility if you replace the first four examples with a new, vararged one:
Log.log(String code, String... args)
All of them are source compatible. That is, if you recompile all callers of the log() method, you can just replace all four methods directly. If, however, you need backward binary compatibility, you'll need to leave in the first three. Only the final method, taking an array of strings, is equivalent to, and thus can be replaced by, the vararged version.
Casting
You should avoid casting with varargs in cases where you simply expect the caller to know what the types should be. Take this example, where the first item is expected to be a string, and the second an exception:
Log.log(Object... objects) {
String message = (String)objects[0];
if (objects.length > 1) {
Exception e = (Exception)objects[1];
// Do something with the exception
}
}
Instead, your method signature should be like the following, with the string and exception declared separately from the vararg parameter:
Log.log(String message, Exception e, Object... objects) {...}
Don't try to be too clever. Don't use varargs to subvert the type system. If you need strong typing, use it. PrintStream.printf() is one interesting exception to this rule: it provides type information as its first argument so that it can accept those types later.
Covariant Returns
The primary use of covariant returns is to avoid casts when an implementation's return type is known to be more specific than the API's. In this example, we've got a Zoo interface that returns an Animal object. Our implementation returns an AnimalImpl object, but before JDK 1.5 it had to be declared to return an Animal object:
public interface Zoo {
public Animal getAnimal();
}
public class ZooImpl implements Zoo {
public Animal getAnimal(){
return new AnimalImpl();
}
}
The use of covariant returns replaces three anti-patterns:
1. Direct field access. In order to get around the API restriction, some implementations would expose the subclass directly as a field:
ZooImpl._animal
2. An additional form was to perform the downcast in the caller, knowing that the implementation was really this specific subclass:
((AnimalImpl)ZooImpl.getAnimal()).implMethod();
3. The last form I've seen is a special method that avoids the problem by coming up with a different signature entirely:
ZooImpl._getAnimal();
All of these have their problems and limitations. Either they're ugly or expose implementation details that should not be necessary.
With Covariance
The covariant return pattern is cleaner, safer, and easier to maintain. No casts or special methods or fields are required:
public AnimalImpl getAnimal(){
return new AnimalImpl();
}
Using the result:
ZooImpl.getAnimal().implMethod();
Generics
Generics is split into using generics and writing generics. These include both generic types and methods. We're not going to talk about the obvious use of List, Set, and Map. Suffice it to say that generic collections are great and should always be used.
We are going to cover using generic methods and how the compiler infers the types. Usually this will just work for you, but when it doesn't the error messages are fairly inscrutable and you will need to know how to fix the problem.
Published February 6, 2006 Reads 33,221
Copyright © 2006 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Jess Garms
Jess Garms works at BEA Systems.
More Stories By Tim Hanson
Tim Hanson is the Javelin compiler architect at BEA Systems. Tim developed much of BEA's Java compiler - one of the earliest 1.5-compliant implementations. He has written numerous other compilers, including a CORBA/IDL compiler while at IBM, and an XQuery compiler.
![]() |
SYS-CON Brazil News Desk 02/06/06 11:31:53 AM EST | |||
During the beta period for JDK 1.5, we worked on a 1.5 Java compiler for BEA's Java IDE. As we implemented various new features, people would begin exploiting them in new ways, some clever, some clearly candidates for a list of what not to do. The compiler itself used 1.5 features, so we gained direct experience in maintaining 1.5 code as well. |
||||
![]() |
SYS-CON India News Desk 02/06/06 10:49:34 AM EST | |||
During the beta period for JDK 1.5, we worked on a 1.5 Java compiler for BEA's Java IDE. As we implemented various new features, people would begin exploiting them in new ways, some clever, some clearly candidates for a list of what not to do. The compiler itself used 1.5 features, so we gained direct experience in maintaining 1.5 code as well. |
||||
- Kindle 2 vs Nook
- Why IBM’s Server Chief Got Busted
- Is Cloud Computing Like Teenage Sex?
- Industry Experts Discuss the State of Cloud Computing
- Performance Tuning Essentials for Java
- Confessions of a Ulitzer Addict
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- It's the Java vs. C++ Shootout Revisited!
- Cloud Computing Can Revitalize Your Career as Software Developer
- IBM Could "Reinvent" Java: Mills
- Oracle & Cloud Computing: Exclusive Q&A with SVP Richard Sarwal
- A Brief History of Cloud Computing
- Kindle 2 vs Nook
- Cloud CEOs, CTOs & SVPs to Speak at 4th International Cloud Computing Expo
- Why IBM’s Server Chief Got Busted
- Is Cloud Computing Like Teenage Sex?
- Industry Experts Discuss the State of Cloud Computing
- Performance Tuning Essentials for Java
- The Difference Between Web Hosting and Cloud Computing
- Cloud Computing Expo: Exclusive Q&A with Yahoo! SVP Cloud Computing
- Ajax in RichFaces 3.3, JSF 2 and RichFaces 4
- Confessions of a Ulitzer Addict
- My Thoughts on Ulitzer
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- A Cup of AJAX? Nay, Just Regular Java Please
- Java Developer's Journal Exclusive: 2006 "JDJ Editors' Choice" Awards
- The i-Technology Right Stuff
- JavaServer Faces (JSF) vs Struts
- Rich Internet Applications with Adobe Flex 2 and Java
- Java vs C++ "Shootout" Revisited
- Bean-Managed Persistence Using a Proxy List
- Reporting Made Easy with JasperReports and Hibernate
- Creating a Pet Store Application with JavaServer Faces, Spring, and Hibernate
- What's New in Eclipse?
- Why Do 'Cool Kids' Choose Ruby or PHP to Build Websites Instead of Java?
- i-Technology Predictions for 2007: Where's It All Headed?






































