Charles Overbeck

About some JDK 5 features

I read Steve Shaugnessy’s interesting Learning Delphi blog entry. One of the things he talked about was Delphi’s override keyword for virtual methods.

Well, Java 5 has its own way to enforce that a method be an override. And there are two other small Java 5 features that I am in the habit of commonly using. So even though Java 6 is almost upon us, I figured I’d discuss them a little. I only found out about one of these a few months ago, so I’d gone, what, over a year, without knowing about it. I figure at least one of these will be new to somebody.

The @Override annotation

Java 5 has an @Override annotation to make the compiler enforce that the specified method overrides a method in a base class. I use this all the time. I’ve introduced bugs in the past where I changed a method signature, not realizing that I was breaking things by removing override behavior.

Example:

  public class Foo {
    @Override
    public String toString() {
      return "foo";
    }
  }

If I add a parameter to Foo.toString(), the compiler will generate an error because the new method no longer overrides a method in Object.

In JBuilder 2007, if you override a method through the Source | Override/Implement Methods dialog, the @Override annotation will be generated for you.

StringBuilder

Java 5 introduced a new class, StringBuilder, that you can use to replace StringBuffer. The difference is that StringBuilder’s methods are not synchronized. Since almost all usages of StringBuffer are as local variables (I don’t think I’ve ever seen a field of type StringBuffer), and since StringBuilder has the same methods as StringBuffer, you can usually just replace the declaration and instantiation and not worry about synchronization issues.

Example:

  //Before:
  public String sayHello(String name) {
    StringBuffer sb = new StringBuffer("Hello ");
    sb.append(name);
    return sb.toString();
  }

  //After:
  public String sayHello(String name) {
    StringBuilder sb = new StringBuilder("Hello ");
    sb.append(name);
    return sb.toString();
  }

I went through the JBuilder codebase before we shipped and pretty much did a global search and replace of StringBuffer with StringBuilder. You may not notice a performance difference (especially in the above example!), but it’s still good practice.

Similarly, I never use java.util.Vector either, because most of its methods are synchronized. For local variables, the synchronization just slows you down. And to create thread-safe code, just using Vector is typically not enough:

  if (!vector.contains(myObject)) {
    vector.add(myObject);
  }

In the above case, both the contains() and add() methods are individually thread-safe, but you have no guarantee that myObject won’t get added to the Vector by another thread in between those two statements. So you usually end up needing to have the above code in a synchronize block anyway. I always use one of the other Collections Framework classes.

String.split()

This method is actually new to JDK 1.4, so by itself it doesn’t belong here. But I have started using it a lot in Java 5 because:

  1. I noticed that the StringTokenizer class usage is "discouraged". That’s an interesting term. I don’t think I’ve seen it anywhere before in reference to a Java class. It’s less strict than "deprecated" — "deprecated" generates compiler warnings, while "discouraged", which is neither an annotation nor a JavaDoc tag, does not. At any rate, after I found out that StringTokenizer’s use is discouraged, I changed my code to use
  2. The new foreach construct. The first time I saw that syntax, it looked really funky to me. Now that I’ve gotten used to it, I think it looks great.

Here’s code using both StringTokenizer and split().

  private void parse() {
    String cities = "Watsonville,Santa Cruz,Capitola,Scotts Valley";
    useSplit(cities);
    useStringTokenizer(cities);
  }

  private void useSplit(String cities) {
    for (String city : cities.split(",")) {
      System.out.println(city);
    }
  }

  private void useStringTokenizer(String cities) {
    StringTokenizer stringTokenizer = new StringTokenizer(cities, ",");
    while (stringTokenizer.hasMoreTokens()) {
      System.out.println(stringTokenizer.nextToken());
    }
  }

The useSplit() looks a lot nicer to me, because of the variable city. Yes, we could introduce a variable city in the StringTokenizer code, but that would be another line of code and it still wouldn’t look as sleek as the split() case. And even if you disagree, remember, StringTokenizer use is discouraged!

In JBuilder 2007, if you type "fore" followed by Ctrl+Space, a foreach loop will be generated. It will look for the nearest Iterable or array variable, and use that variable’s type in generating the loop.

Charles

Posted by Charles Overbeck on December 7th, 2006 under Java |



One Response to “About some JDK 5 features”

  1. daniel Says:

    2 observations:

    "@override" capability was always there (in delphi/tp language) since Turbo Pascal 5.0 (the very first Pascal with "objects"). plus, that particular syntactic token sun implemented is "hard coded" and unappealing to any serious programmer (delphi/c++ true architectural background)

    2. actually StringBuilder is not new! has nothing to do with jdk 5 or anything… it was implemented a long time ago, in order to patch the inefficiently approach of using ref-counted read-only/immutable strings

    good coding charles… :-)
    d



Server Response from: blog2.codegear.com