In this tutorial, I will focus on identifying most noticeable differences
which you must know before deciding which one to use in your next project.
Category Archives: Java 7 Features
The
new input/output (NIO)
library was introduced with JDK 1.4. Picking up where original I/O leaves off,
NIO provides high-speed, block-oriented I/O in standard Java code. By defining
classes to hold data, and by processing that data in blocks, NIO takes advantage
of low-level optimizations in a way that the original I/O package could not,
without using native code.
Recalling old IO facility
I/O (input/output)
refers to the interface between a computer and the rest of the world, or
between a single program and the rest of the computer. Individual programs
generally have most of their work done for them. In Java programming, I/O has
until recently been carried out using a stream metaphor. All I/O is viewed as
the movement of single bytes, one at a time, through an object called a Stream.
Stream I/O is used for contacting the outside world. It is also used
internally, for turning objects into bytes and then back into objects.
Introducing NIO
NIO
was created to allow Java programmers to implement high-speed I/O without
having to write custom native code. NIO moves the most time-consuming I/O
activities (namely, filling and draining buffers) back into the operating
system, thus allowing for a great increase in speed.
If above introductions have left you thirsty then don’t worry if you will
feel bettor as we go forward. Let’s start by finding the differences.
Identifying differences between IO and NIO
1) IO streams versus NIO
blocks
The most important distinction between the original I/O library (found in
java.io.*) and NIO has to do with how data is packaged and transmitted. As
previously mentioned, original I/O deals with data in streams, whereas NIO
deals with data in blocks.
A stream-oriented I/O system deals with data one or more bytes at a time. An
input stream produces one byte of data, and an output stream consumes one byte
of data. It is very easy to create filters for streamed data. It is also
relatively simply to chain several filters together so that each one does its
part in what amounts to a single, sophisticated processing mechanism. Important
thing is that bytes are not cached anywhere. Furthermore, you cannot move forth
and back in the data in a stream. If you need to move forth and back in the
data read from a stream, you must cache it in a buffer first.
A block-oriented I/O system deals with data in blocks. Each operation
produces or consumes a block of data in one step. Processing data by the block
can
be much faster than processing it by the (streamed) byte. You can move forth
and back in the buffer as you need to. This gives you a bit more flexibility
during processing. However, you also need to check if the buffer contains all
the data you need in order to fully process it. And, you need to make sure that
when reading more data into the buffer, you do not overwrite data in the buffer
you have not yet processed. But block-oriented I/O lacks some of the elegance
and simplicity of stream-oriented I/O.
Read more: 3 ways to read files
using Java NIO
2) Synchronous vs.
Asynchronous IO
Java IO’s various streams are blocking or synchronous. That means, that when
a thread invokes a read() or write(), that thread is blocked until there is
some data to read, or the data is fully written. The thread will be in blocked
state for this period. This has been cited as a good solid reason for bringing
multi-threading in modern languages.
In asynchronous IO, a thread can request that some data be written to a
channel, but not wait for it to be fully written. The thread can then go on and
do something else in the mean time. Usually these threads spend their idle time
on when not blocked in IO calls, is usually performing IO on other channels in
the meantime. That is, a single thread can now manage multiple channels of
input and output.
Synchronous programs often have to resort to polling, or to the creation of
many, many threads, to deal with lots of connections. With asynchronous I/O,
you can listen for I/O events on an arbitrary number of channels, without
polling and without extra threads.
The central object in asynchronous I/O is called the Selector. A Selector is
where you register your interest in various I/O events, and it is the object
that tells you when those events occur. So, the first thing we need to do is
create a Selector:
1
|
Selector selector = Selector.open();
|
Later on, we will call the register() method on various channel objects, in
order to register our interest in I/O events happening inside those objects.
The first argument to register() is always the Selector.
Read more: How to define Path in
java NIO
3) IO Versus NIO APIs
No prize for guessing that the API calls when using NIO look different than
when using IO. Here in NIO, rather than just read the data byte for byte from
e.g. an InputStream, the data must first be read into a buffer, and then be
processed from thereafter.
Sample code using standard IO
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class WithoutNIOExample
{
public static void main(String[]
args)
{
BufferedReader
br = null;
String
sCurrentLine = null;
try
{
br
= new BufferedReader(
new FileReader("test.txt"));
while ((sCurrentLine
= br.readLine()) != null)
{
System.out.println(sCurrentLine);
}
}
catch (IOException
e)
{
e.printStackTrace();
}
finally
{
try
{
if (br
!= null)
br.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
}
Sample code using NIO
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class ReadFileWithFixedSizeBuffer
{
public static void main(String[]
args) throws IOException
{
RandomAccessFile
aFile = new RandomAccessFile
("test.txt",
"r");
FileChannel
inChannel = aFile.getChannel();
ByteBuffer
buffer = ByteBuffer.allocate(1024);
while(inChannel.read(buffer)
> 0)
{
buffer.flip();
for (int i =
0; i < buffer.limit(); i++)
{
System.out.print((char)
buffer.get());
}
buffer.clear();
// do something with the data and clear/compact it.
}
inChannel.close();
aFile.close();
}
}
NIO allows you to
manage multiple channels using only a single (or fewer) threads, but the cost
is that parsing the data might be somewhat more complicated than when reading
data from a blocking stream using standard IO.
If you need to
manage thousands of open connections simultaneously, which each only send a
little data, for instance a chat server, implementing the server in NIO is
probably an advantage. Similarly, if you need to keep a lot of open connections
to other computers, e.g. in a P2P network, using a single thread to manage all
of your outbound connections might be an advantage.
If you have fewer
connections with very high bandwidth, sending a lot of data at a time, standard
IO server implementation should be your choice.
Automatic resource management with
try-with-resources in java 7
Java 7 has brought
some very good features for lazy java developers.
Try-with-resources
is one of such feature which cuts line of code and also make the code more
robust. In this tutorial, I will discuss things around this feature.
Sections
in this post:
The
old way of resource cleanup (Before java 7)
The
new fancy way with try-with-resources (syntax example)
How
actually it works?
Adding
functionality to custom resources
Final
notes
The old way of resource cleanup (Before java 7)
We have been doing this from long time. e.g. read a file from file system.
Code may look different but flow will be like below example:
public class ResourceManagementBeforeJava7
{
public static void main(String[]
args)
{
BufferedReader
br = null;
try
{
String
sCurrentLine;
br
= new BufferedReader(new
FileReader("C:/temp/test.txt"));
while ((sCurrentLine
= br.readLine()) != null)
{
System.out.println(sCurrentLine);
}
}
catch (IOException
e)
{
e.printStackTrace();
}
finally
{
try
{
if (br
!= null)
br.close();
}
catch (IOException
ex) {
ex.printStackTrace();
}
}
}
}
These types of code are very common in application code base where there is
lots of IO operations.
Code inside try and catch blocks are essentially important and have some
application specific logics. But what about finally block??
Most of the
time, finally blocks are just copy pasted for sake of saving the
resources from corruption, by closing them.
These finally blocks
looks more ugly, when you have 3-4 such
resources to close in single finally block. Don’t you think these
finally blocks are unnecessarily there when we know, we have to close the
resource anyhow without any exceptional case??
Java 7 solves this problem with try-with-resources feature.
The new fancy way with try-with-resources
(syntax example)
Now look at the new way of opening and closing a resource in java 7.
public class ResourceManagementInJava7
{
public static void main(String[]
args)
{
try (BufferedReader
br = new BufferedReader(new
FileReader("C:/temp/test.txt")))
{
String
sCurrentLine;
while ((sCurrentLine
= br.readLine()) != null)
{
System.out.println(sCurrentLine);
}
}
catch (IOException
e)
{
e.printStackTrace();
}
}
}
There are two things to closely watch:
- File resource
(BufferedReader) is opened in try block in special manner (inside small
brackets).
- Finally
block is completely gone.
And last but not the least, code looks pretty and easy to read. It’s good
,right?? But how actually it works??
How actually it works?
In java 7, we have a new super interface
java.lang.AutoCloseable.
This interface have one method:
1
|
void
close() throws Exception;
|
Java docs recommend this interface to be
implemented on any
resource that must be closed when it is no longer needed.
When we open any such AutoCloseable resource in special try-with-resource
block, immediately after finishing the try block,
JVM
calls this close() method on all resources initialized in “try()” block.
For example, BufferedReader has implemented close() method file this:
public void close()
throws IOException {
synchronized (lock)
{
if (in
== null)
return;
in.close();
in
= null;
cb
= null;
}
}
Due to above method definition, any underlying stream or IO resource is
closed when this method is invoked by JVM.
Adding functionality to custom resources
Well, this is a good resource cleanup design. But is it available to JDK
native classes only?? NO. You can use it also to your custom resources.
For example, I have create a custom resource in below code:
public class CustomResource
implements AutoCloseable
{
public void accessResource()
{
System.out.println("Accessing
the resource");
}
@Override
public void close()
throws Exception {
System.out.println("CustomResource
closed automatically");
}
}
|
Now I will use it in my example
code:
public class TryWithCustomResource
{
public static void main(String[]
args)
{
try(CustomResource
cr = new CustomResource())
{
cr.accessResource();
}
catch (Exception
e)
{
e.printStackTrace();
}
}
Putput in console:
Accessing the resource
CustomResource closed
automatically
Output in console
clearly proves that resource was closed down automatically as soon as try block
was finished.
LAST TUCH UP
That’s
all regarding automatic resource management with try-with-resources in java 7.
Let’s note down highlights point by point:
- Before java 7, we had to use
finally blocks to cleanup the resources. Finally blocks were not
mandatory, but resource clean up was to prevent the system from being
corrupt.
- With java 7, no need to
explicit resource cleanup. Its done automatically.
- Automatic resource cleanup done
when initializing resource in try-with-resources block (try(…) {…}).
- Cleanup happens because of new
interface AutoCloseable. Its close method is invoked by JVM as soon as try
block finishes.
- If you want to use this in
custom resources, then implementing AutoCloseable interface is mandatory.
otherwise program will not compile.
- You are not supposed to call
close() method in your code. This should be called automatically bu JVM.
Calling it manually may cause unexpected results.