Top Ten New Things You Can Do with NIO

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.

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.

Figure 1: Reader processes holding shared locks.

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:

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:

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.