ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button
Java NIO

Top Ten New Things You Can Do with NIO

by Ron Hitchens, author of Java NIO
10/02/2002

New I/O? Why do we need a new I/O? What's wrong with the old I/O?

There's nothing wrong with the classes in the java.io package; they work just dandy -- for what they do. But it turns out there are quite a lot of things the traditional Java I/O model can't handle. Things like non-blocking modes, file locks, readiness selection, scatter/gather, and so on. These capabilities are widely available on most serious operating systems today (and a few comical ones, as well). They're not just nice to have; they're essential for building high-volume, scalable, robust applications, especially in the enterprise arena.

NIO brings a host of powerful new capabilities to the Java platform. Despite the fact that "N" stands for "New," NIO is not a replacement for the older I/O classes. It's an alternate approach to modeling I/O services, with less emphasis on the streaming model. NIO concentrates on providing consistent, portable APIs to access all sorts of I/O services with minimum overhead and maximum efficiency. NIO sweeps away many barriers to the adoption of Java where I/O performance is critical, allowing Java to compete on an equal footing with natively compiled languages.

Related Reading

Java NIO
By Ron Hitchens

In this article I'm not going to explain buffers, channels, selectors, and the other denizens of the NIO depths. There just isn't room here to do so properly. My book, Java NIO, does all that. In this space, I'll list some new things you can do with NIO that you couldn't do before in Java. If you need a little context as you go along, visit this page (part of Sun Microsystems' JDK documentation), which gives a brief synopsis and links into the J2SE 1.4 Javadoc.

So, without further ado, in the time-honored tradition of O'Reilly authors flogging their own books by cooking up lame top ten lists: Top Ten New Things You Can Do with NIO That You Couldn't Do Before (TTNTYCDW..., oh never mind).

10: File Locking

File locking is one of those things most programmers don't need very often. But for those of you who do need it, you know you simply can't live without it. Prior to NIO, there was no way, short of resorting to native methods, to set or check for file locks in Java applications. File locking is notoriously OS- (and even filesystem-) specific, so the native route is fraught with peril if you need any sort of portability.

With NIO, file locks are built right into the FileChannel class. It's now easy to create, test, and manage file locks on any platform that supports file locks at the OS level. File locks are generally needed when integrating with non-Java applications, to mediate access to shared data files. In Figures 1 and 2 (borrowed from my book) assume the writer process is a legacy application that can't be replaced. With NIO, new reader applications can be written in Java that use the same locking conventions to seamlessly integrate with the pre-existing, non-Java application.

Readers holding shared lock
Figure 1: Reader processes holding shared locks.

Writer holding exclusive lock
Figure 2: Writer process holding exclusive lock.

File locks are generally not appropriate for intra-JVM coordination between threads; they operate at the file and process levels. The OS doesn't usually differentiate between threads within a process for lock ownership purposes. That means all threads own all locks equally within a JVM. File locks are primarily needed when integrating with non-Java applications, or between distinct JVMs.

You may never need to use file locks, but with NIO, now you have the option. Adding file-based locking to the Java bag of tricks further eliminates barriers to adoption of Java in the enterprise, especially where it's necessary to work and play well with others.

9: Regular Expressions Built into the String Class

Regular expressions (java.util.regex) are part of NIO. I know, they're neither "new" nor "I/O," but a standardized regular expression library was mandated as part of JSR 51, so there you go.

Regular expressions are not new in Java (several add-on packages have been around for quite some time) but now they're built right into the base J2SE distribution. According to Jeffrey E. F. Friedl's recently updated Mastering Regular Expressions book, the regex engine in J2SE 1.4 is the fastest and best of the lot -- good to know.

One nice side effect of having a regular expression engine integrated into the base JDK is that other base classes can make use of it. In J2SE 1.4, the String class has been extended to be regex-aware by adding the following new methods:

package java.lang;

public final class String
implements java.io.Serializable, Comparable, CharSequence
{
   // This is a partial API listing

   public boolean matches (String regex)
   public String [] split (String regex)
   public String [] split (String regex, int limit)
   public String replaceFirst (String regex, String replacement)
   public String replaceAll (String regex, String replacement)
}

These methods are useful because you can invoke them directly on a string you're working with. For example, rather than instantiating Pattern and Matcher objects, invoking methods on them, and checking the result, you can do simple tests like this, which are less error-prone and communicate better:

public static final String VALID_EMAIL_PATTERN =
"([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]"
+ "{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))"
+ "([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)";

...

if (emailAddress.matches (VALID_EMAIL_PATTERN)) {
   addEmailAddress (emailAddress);
} else {
   throw new IllegalArgumentException (emailAddress);
}

The split() method is also handy, especially in cases where you'd normally use the StringTokenizer class. It has two advantages over StringTokenizer; it applies a (potentially sophisticated) regular expression to the target string to break it into tokens and it does the parsing all in one shot. Rather than writing yet another tokenizing loop, you can just do:

String [] tokens = lineBuffer.split ("\\s*,\\s*");

This splits the string lineBuffer (which contains a series of comma-separated values) into substrings and returns those strings in a type-safe array. This regular expression allows zero or more whitespace characters before and/or after each comma. You can also limit the number of times the string is split, in which case the last string in the array will be the remainder of the input string.

Pages: 1, 2, 3, 4

Next Pagearrow