| By Jess Garms, Tim Hanson | Article Rating: |
|
| February 6, 2006 11:30 AM EST | Reads: |
32,761 |
Quite a few articles have been written introducing the new language features in JDK 1.5. In this article, we're going to go a little deeper and provide tips on how to effectively use those features.
Introduction
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.
As we mentioned, this is not an introductory article. You should know roughly what the new features are, and we'll talk about some of the interesting, hopefully non-obvious implications and uses. These tips are a somewhat random collection of things we ran into, loosely grouped by language feature.
We'll start with the simplest features and work our way toward the most advanced ones. Generics is an especially rich subject and occupies about half of this article.
For-Each Loop
The new for-each loop provides a simple, consistent syntax for iterating over collections and arrays. There are just a couple of interesting items to mention.
Init Expression
The initialization expression is evaluated only once inside the loop. This means that you can often remove a variable declaration. In this example, we had to create an integer array in order to hold the results of computeNumbers() to prevent reevaluation of that method on each pass through the loop. You can see the bottom code is a little cleaner than the above, and doesn't leak the variable "numbers."
Without For Each:
int sum = 0;
Integer[] numbers = computeNumbers();
for (int i=0; i < numbers.length ; i++)
sum += numbers[i];
With:
int sum = 0;
for ( int number: computeNumbers() )
sum += number;
Limitations
Sometimes you need access to the iterator or index during iteration. Intuitively it seems like the for-each loop should allow this. It doesn't. Take the following example:
for (int i=0; i < numbers.length ; i++) {
if (i != 0) System.out.print(",");
System.out.print(numbers[i]);
}
We want to print out a comma-separated list of the values in the array. We need to know whether we're on the first item in order to know if we should print a comma. With for-each, there's no way to get at this info. We'd need to keep an index ourselves, or a boolean indicating whether or not we're past the first item.
Here's another example:
for (Iterator<Integer> it = n.iterator() ; it.hasNext() ; )
if (it.next() < 0)
it.remove();
In this case, we want to remove the negative items from a collection of integers. In order to do this, we need to call a method on the iterator, but when using for-each, this iterator would be hidden from us. Instead, we need to just use the pre-1.5 method of iterating.
Note, by the way, that Iterator is generic, so the declaration is Iterator<Integer>. A lot of people seem to miss this and use Iterator in its raw form.
Annotations
Annotation processing is a very large topic. We're not going to cover all of the possibilities and pitfalls of it, as we're limiting our article to core language features.
We will, however, discuss the built-in annotations and the limitations of annotation processing in general.
Suppress Warnings
This annotation turns off compiler warnings at a class or method level. Sometimes you know better than the compiler that your code must use a deprecated method, or perform some action that cannot be statically determined to be typesafe, but in fact is.
@SuppressWarnings("deprecation")
public static void selfDestruct() {
Thread.currentThread().stop();
}
This is probably the most useful of the built-in annotations. Unfortunately, javac doesn't support it as of 1.5.0_03. It is supported in 1.6, however, and Sun is working on back-porting it to 1.5.
It is supported in Eclipse 3.1, and possibly other IDEs as well. This allows you to keep your code entirely warning-free. If a warning shows up when compiling, you can be certain that you just added it - helping to keep you aware of possibly unsafe code. With the addition of generics, this is even more desirable.
Deprecated
Unfortunately, this one is a little less useful. It's meant to replace the @deprecated javadoc tag, but since it doesn't have any fields, there's no way to suggest to the user of a deprecated class or method what they should be using as a replacement. Most uses will require both the Javadoc tag and this annotation.
Override
This indicates that the method it annotates should be overriding a method with the same signature in a superclass.
@Override
public int hashCode() {
...
}
Take the above example - if you were to fail to capitalize the "C" in hashCode, you wouldn't get an error at compile time but, at runtime, your method would not be called as you expected. By adding the Override tag, the compiler will complain if it doesn't actually perform an override.
This also helps in the case where the superclass changes. If, say, a new parameter were added to this method and the method itself renamed, the subclass will suddenly fail to compile, as it no longer overrides anything in the super.
Other Annotations
Annotations can be extremely useful in other situations as well. They work best for frameworks like EJB and Web services, when behavior is not directly modified but rather enhanced, especially in the case of adding boiler-plate code.
Annotations cannot be used as a preprocessor. Sun's design specifically precludes modifying the byte code of a class directly because of an annotation. This is so that the results of the language can be properly understood and tools like IDEs can perform deep code analysis and functions like refactoring.
Annotations are not a silver bullet. When first running across them, people are tempted to try all sorts of tricks. Take this next proposal we got from someone:
public class Foo {
@Property
private int bar;
}
The idea here was to automatically create getter and setter methods for the private field "bar." Unfortunately, this is a bad idea for two reasons: (1) it doesn't work, and (2) it makes this code harder to read and deal with.
It can't be done because as we mentioned, Sun specifically precludes modifying the class that an annotation appears in.
Even if it were possible, it's not a good idea because it makes this code harder to understand. Someone looking at this code for the first time will have no idea that this annotation creates methods. Also, if in the future you need to do something inside one of those methods the annotation is useless.
In summary, don't try to use annotations to do what regular code would do.
Published February 6, 2006 Reads 32,761
Copyright © 2006 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
About Jess Garms
Jess Garms works at BEA Systems.
About 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. |
||||
- Performance of Java Compilers: An Empirical Study
- Java Kicks Ruby on Rails in the Butt
- Ulitzer’s Amazing First 30 Days in Public Beta
- 1st Annual Government IT Expo: Call for Papers Deadline July 15
- REA Is Where RIA Becomes the Norm
- Why an Application Grid?
- Will Ulitzer Dominate News Content on The Web? -Gartner
- Clear Toolkit 4: The Road Map
- Profiling Netbeans within Amazon EC2
- Java Persistence on the Grid: Approaches to Integration
- Performance of Java Compilers: An Empirical Study
- Java Kicks Ruby on Rails in the Butt
- Developing Rich Client Applications Using Swing - II
- The Right Time for Real Time Java
- Xpress Suite Adds Automatic Java to iPhone Conversion
- Ulitzer’s Amazing First 30 Days in Public Beta
- Initial Thoughts on IBM Acquisition of Sun Microsystems
- 1st Annual Government IT Expo: Call for Papers Deadline July 15
- Maximizing Java Performance with Bespoke Programming
- REA Is Where RIA Becomes the Norm
- 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
- What's New in Eclipse?
- Creating a Pet Store Application with JavaServer Faces, Spring, and Hibernate






































