ByteBuffer in Java
ByteBuffer is introduced in java.nio since Java 1.4. It provides a way of representing raw structured data such as from a file or from network. It enables fast access of underlying data compared to traditional ways like byte
Prior to Java 1.4, if you want to represent a structured raw data, you need to create a byte and then having a set of checks to delimit the byte array to get the expected tokens.
There are three ways to create a ByteBuffer:
- Wrapping an exiting array by calling ByteBuffer.wrap();
- Creating an empty buffer with capacity by calling ByteBuffer.allocate();
- Creating an direct empty buffer with capacity by calling ByteBuffer.allocateDirect()
ByteBuffer.allocate() will create an underlying array to back the buffer. The memory may not be continuous on the RAM. While ByteBuffer.allocateDirect() will create a continuous memory buffer and make a best effort to perform native I/O operations directly upon it.
When performing data IO on direct buffer, JVM will attempt to avoid copying the buffer's content to (or from) an intermediate buffer before (or after) each invocation of one of the underlying operating system's native I/O operations.
This class provides a set of gets and puts methods to read and write different types of data. For example, getInt(), getChar(), getShort(), putInt(), putChar(), putShort() etc. With these methods, the structural representation of raw data becomes reality. One example :
ByteBuffer buffer = ByteBuffer.allocate(100); buffer.putInt(10); buffer.putChar('c'); buffer.flip(); //RESET THE BUFFER POSITION FOR READ System.out.println("int : "+buffer.getInt()); System.out.println("char : "+buffer.getChar());
Now if we put an integer into the buffer, we can directly call buffer.getInt() to get the integer, there is no need for the developer to handle how the integer is read from the byte array internally.
There are also a set of methods to maintain or set the position of the buffer, it is similar to cursor in a database. These methods include position(), seek(), flip(), reset(), limit() etc. From the above example, to read the data we put in the buffer, the position has been reset to its original position(0), this can be done by calling buffer.flip(). Without this call, when calling buffer.getInt(), we will get a value of 0.
ByteBuffer is frequently used when we need to do fast low level I/O operations. For example, during network communication such as TCP/IP, writing a database (DBMS) or doing encryption/decryption operations.
After changing one line of code, everything doesn't feel good.