ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Five Favorite Features from 5.0

by David Flanagan, author of Java in a Nutshell, 5th Edition
04/20/2005

By now, you've undoubtedly seen more than one online article enumerating the great new language features of Java 5.0: generics, annotations, enumerated types, autoboxing, varargs, the for/in loop, and even static imports. I think these are great features, too, but you've already read about them. So I'll concentrate here on new API features of Java 5.0 that you may not have encountered yet.

What follows, then, are five of my favorite new API features of Java 5.0. I've written about these in Chapter 5 of the fifth edition of Java in a Nutshell, and I've blogged about some of them at my website. Diligent readers who make it to the end of this article will find a bonus sixth feature: new language syntax supported by Java 5.0 but known to very few, and used by even fewer. It's a favorite of mine simply because it is bizarre.

Callable and Future Interfaces

My first favorite feature is drawn from the new java.util.concurrent package. As its name implies, this is a package of utilities for concurrent programming. There is much to explore here, and one of my nominees for First Favorite is the TimeUnit enumerated type. What intrigues me about TimeUnit is that includes useful time-related utilities, which you invoke through an enumerated constant that represents the unit in which you choose to measure time. For example:


  TimeUnit.MILLISECONDS.sleep(200);

TimeUnit doesn't win the prize, however. One of the most powerful features of java.util.concurrent is its task-execution/thread-pooling architecture. The ExecutorService interface provides the ability to execute tasks. The Executors class defines factory methods for obtaining ExecutorService implementations that use thread pools. This is powerful stuff.

My favorite part of this task-execution framework is how it represents the task and the results of executing it: the Callable and Future interfaces. We're all familiar with the Runnable interface and its run() method used to define threads. Callable is like Runnable, except that its method is named call() and this method can return a result or throw an exception, neither of which is possible with Runnable.run().

Callable is a generic type, and is parameterized with the type of its result. A task that computes a BigInteger, for example is a Callable<BigInteger>, and its call() method is declared to return BigInteger. Here is the Callable interface in its three lines of glory:


  public interface Callable<V> {
      V call() throws Exception;
  }

When I want to asynchronously execute a Callable task, I pass it to the submit() method of an ExecutorService. The return value of submit()--and this is the part I love--is a Future object: essentially an IOU for a result some time in the future. When I'm ready to use the result of my task, I simply call the get() method of the Future object. If the task is done executing, then get() returns my result right away. Otherwise, it blocks until the result is ready. If Callable throws an exception, then the get() method wraps that exception in an ExecutionException and throws that. Future also has methods for cancelling and querying the status of task execution, but you'll have to look those up yourself.

Future uses generics, too, and is also parameterized in the type of the result. So if I submit() a Callable<BigInteger> for execution, I get a Future<BigInteger> in return.

Here's a short example:


/**
 * This is a Callable for computing big primes.
 */
public class PrimeSearch implements Callable<BigInteger>
{
    static Random prng = new SecureRandom();
    int n;
    public PrimeSearch(int bitsize) { n = bitsize; }
    public BigInteger call() {
        return BigInteger.probablePrime(n, prng);
    }
}

// Try to compute two primes at the same time
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<BigInteger> p = pool.submit(new PrimeSearch(512));
Future<BigInteger> q = pool.submit(new PrimeSearch(512));

// Multiply the primes to form a composite number
BigInteger product = p.get().multiply(q.get());

Varargs and Autoboxing

I said I wasn't going to talk about the new language features of Java 5.0, and I won't, but I do want to draw attention to new APIs enabled by (or old APIs enhanced with) varargs and autoboxing.

First, of course, is Java 5.0's printf-style text formatting capability, with the java.util.Formatter class and utility methods like String.format(). This kind of text formatting was the use case cited most often to support the addition of varargs and autoboxing to the language. Consider this:


  String s = String.format("%s:%d: %s%n", filename,
                           lineNumber,
  		           exception.getMessage());

There is nothing particularly remarkable about this code. I list it as a favorite simply because varargs and autoboxing make it so much simpler than the alternative:


  String s = String.format("%s:%d: %s%n", new Object[] {
                           filename,
                           new Integer(lineNumber),
  			   exception.getMessage()});

Varargs and autoboxing also have a substantial impact on the usability of the java.lang.reflect API. There is no longer any need for arrays of classes and objects when looking up and invoking methods:


  Method m = c.getMethod("put", Object.class,Object.class);
  m.invoke(map, "key", "value");

If I had to pick a favorite varargs method, though, it would be java.util.Arrays.asList(). This method is a really convenient factory for creating immutable List objects. It takes any number of arguments of the type T and returns them as a List<T>:


  List<Integer> smallPrimes =
     Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19);

Abilities

We talked about Runnable and Callable above, and you undoubtedly already know about the important Comparable, Serializable, and Cloneable interfaces. Java 5.0 adds five important new ability interfaces. The first, of course, is java.lang.Iterable. You probably know that the new for/in loop of Java 5.0 can iterate through arrays and collections. You may not know that it can work with any object that implements the Iterable interface. So, if you want to allow easy iteration of a data structure that is not already a Collection, just implement the Iterable interface. All you have to do is add an iterator() method that returns a java.util.Iterator. Writing the Iterator can be nontrivial, of course.

The code below is a TextFile class that implements Iterable<String> (yes, Iterable is generic) and allows text files to be iterated line by line with the for/in loop. You might use it with code like this:


  TextFile textfile = new TextFile(new File(f), "UTF-8");
  int lineNumber = 0;
  for(String line : textfile)
      System.out.printf("%6d: %s%n", ++lineNumber, line);

Here's the code. Note that the iterator makes no attempt to detect concurrent modifications to the underlying file. If you want to do that yourself, take a look at java.nio.channels.FileLock.


import java.io.*;
import java.util.Iterator;

public class TextFile implements Iterable<String> {
    File f;
    String charsetName;

    public TextFile(File f, String charsetName)
	throws IOException
    {
	this.f = f;
	this.charsetName = charsetName;

	if (!f.exists())
	    throw new FileNotFoundException(f.getPath());
	if (!f.canRead())
	    throw new IOException("Can't read: " +
				  f.getPath());
    }

    public Iterator<String> iterator() {
	try {
	    return new TextFileIterator(f, charsetName);
	}
	catch(IOException e) {
	    throw new IllegalArgumentException(e);
	}
    }


    static class TextFileIterator
	implements Iterator<String>
    {
	BufferedReader in;
	String nextline;
	boolean closed = false;

	public TextFileIterator(File f, String charsetName)
	    throws IOException
	{
	    InputStream fis = new FileInputStream(f);
	    Reader isr =
		new InputStreamReader(fis, charsetName);
	    in = new BufferedReader(isr);
	    getNextLine();
	}

	public boolean hasNext() {
	    return nextline != null;
	}

	public String next() {
	    String returnValue = nextline;
	    getNextLine();
	    return returnValue;
	}

	public void remove() {
	    throw new UnsupportedOperationException();
	}

	void getNextLine() {
	    if (!closed) {
		try { nextline = in.readLine(); }
		catch(IOException e) {
		    throw new IllegalArgumentException(e);
		}
		if (nextline == null) {
		    try { in.close(); }
		    catch(IOException ignored) {}
		    closed = true;
		}
	    }
	}
    }
}

Related Reading

Java in a Nutshell
By David Flanagan

Iterable is by far the most important of the new ability interfaces, but the others are pretty nifty, too. Moving on, then, we come to java.lang.Appendable. An Appendable object is one that can have a character or CharSequence (or a sub-sequence of a CharSequence) appended to it. Implementations include StringBuffer and StringBuilder (if you don't already know about StringBuilder, do look it up), Writer (and subclasses), PrintStream, and java.nio.CharBuffer. Factoring the appendability out of these classes into the Appendable interface makes the new java.util.Formatter class more powerful: it can format text to any Appendable object, including your own implementations. (Exercise for the reader: can you make the TextFile class shown above both Iterable and Appendable?)

The java.lang.Readable interface is the opposite of Appendable: a Readable object can transfer characters into a supplied CharBuffer. java.io.Reader and all of its subclasses are Readable (of course), and so is CharBuffer itself. Just as Appendable was created for the benefit of java.util.Formatter, Readable was created for the benefit of java.util.Scanner. (Scanner was added in Java 5.0, along with Formatter. It is Java's answer to C's scanf() function, but it is not nearly as close an approximation as Formatter is to printf().)

The last two ability interfaces I want to discuss are java.io.Closeable and java.io.Flushable. As their names imply, they are intended to be implemented by any classes that have a close() or a flush() method. Closeable is implemented by all input and output stream classes, RandomAccessFile, and Formatter. Flushable is implemented by output stream classes and Formatter. These interfaces were also defined for the benefit of the Formatter class. Note that Appendable objects (such as StringBuilder) are not always closeable or flushable. By factoring closeability and flushability out into these interfaces, the close() and flush() methods of Formatter are able to determine whether the Appendable object they operate upon needs to be closed or flushed.

(There is a sixth ability interface added in Java 5.0, and it, too, is related to the Formatter class. Classes that want intimate control over how their instances are formatted can implement java.util.Formattable. The API for this interface is awkward, however, and I don't want to talk about it.)

@Override

You've undoubtedly heard about the ability to annotate Java 5.0 types and method with metadata. You may be less familiar with the standards annotation types added to java.lang. My fourth favorite feature is the java.lang.Override annotation. When you write a method that is supposed to override another, annotate it with @Override, and the compiler will check to ensure that you did, in fact, override the method you intended.

If you misspell the method name or get a method argument wrong, then you don't actually override the method you think you are overriding. This can be a tricky bug to catch without @Override. I know because my article about the new API features of Java 1.4 included this bug, and the bug went undetected (or at least unreported) for more than a year. In the article, you can see my mistake at the end of the first page. The article now contains a link to my blog entry, in which I correct the bug and add an @Override declaration to the code!

MatchResult

My final favorite feature of Java 5.0 is java.util.regex.MatchResult. I'd never really been quite satisfied with the Pattern/Matcher API for working with regular expressions. The addition of MatchResult to Java 5.0 goes a long way towards making me happy. When using a non-trivial Pattern, each call to the find() method of a Matcher can generate a lot of state: the start position, end position, and text of the match, as well as the start, end, and text of each sub-expression of the Pattern. Before Java 5.0, you had to get this state from the Matcher by following each call to find() with various calls to start(), end(), and group(), as needed.

In Java 5.0, however, you can just call toMatchResult() to obtain all of the state as a MatchResult object that you can save and examine later. MatchResult has the same start(), end(), and group() methods that Matcher does, and, in fact, Matcher now implements MatchResult.

Here's a useful method that returns MatchResults:


public static List<MatchResult> findAll(Pattern pattern,
					CharSequence text)  {
    List<MatchResult> results =
        new ArrayList<MatchResult>();
    Matcher m = pattern.matcher(text);
    while(m.find()) results.add(m.toMatchResult());
    return results;
}

And here's code that uses that method:

List<MatchResult> results = findAll(pattern, text);
for(MatchResult r : results) {
    System.out.printf("Found '%s' at (%d,%d)%n",
		      r.group(), r.start(), r.end());
}

Hexadecimal Floating Point Literals

I promised that I'd talk about the most obscure new language feature of Java 5.0. Here it is: floating point literals in hexadecimal format!

Here are the bizarre details: a floating-point literal in hexadecimal notation begins with 0X or 0x. This is followed by hexadecimal digits that form the significand of the number. The catch is that these digits may include a decimal point (a hexadecimal point?). After the significand comes the exponent, which is required. Instead of using e or E to introduce the exponent, hexadecimal floating-point literals use p or P. (Think "power" as a mnemonic.) The p or P is followed by the exponent, which must be a decimal number, not a hexadecimal number. And this is a binary exponent, not a decimal exponent. That is, is represents the power of two to which the significand should be raised. Finally, the whole thing can be followed by an f or F to indicate a float literal, or a d or D to indicate a double literal, just as a decimal floating-point literal can.

Here are some examples:


  double x = 0XaP0;    // 10 * 2^0 = 10.0
  double y = 0XfP2D;   // 15 * 2^2 = 60.0
  float z  = 0Xf.aP1F; // (15 + 10/16ths) * 2^1 = 31.25f
  // Print in decimal
  System.out.printf("%f %f %f%n", x, y, z);
  // Print in hex
  System.out.printf("%a %a %a%n", x, y, z);

Why did Sun do this to the language? The release notes for 5.0 say:

To allow precise and predictable specification of particular floating-point values, hexadecimal notation can be used for floating-point literals and for string- to-floating-point conversion methods in Float and Double.

The point is a reasonable one. Decimal fractions such as 0.1 are not precisely representable in floating point format, and if you really need to know exactly what bits are being set in a float or double value, then you really want a hexadecimal literal. For example, the Javadoc for Float.MAX_VALUE points out that the largest float value is 0x1.fffffeP+127f.

If you know and love the IEEE-754 floating point standard, then hexadecimal floating-point literals may be one of your favorite features. I just think they're funny.


In March 2005, O'Reilly Media, Inc., released Java in a Nutshell, 5th Edition.

David Flanagan is the author of a number of O'Reilly books, including Java in a Nutshell, Java Examples in a Nutshell, Java Foundation Classes in a Nutshell, JavaScript: The Definitive Guide, and JavaScript Pocket Reference.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.