5

Recently I created a wrapper to read and write data into a byte array. To do it, I've been using an ArrayList<Byte>, but I was wondering if this is the most efficent way to do it, because:

  • addAll() doesn't work with byte arrays (even using Arrays.asList(), which returns me List<Byte[]>). To fix it I'm just looping and adding a byte at each loop, but I suppose this supposes a lot of function calls and so it has a performance cost.
  • The same happens for getting a byte[] from the ArrayList. I can't cast from Byte[] to byte[], so I have to use a loop for it.
  • I suppose storing Byte instead of byte uses more memory.

I know ByteArrayInputStream and ByteArrayOutputStream could be used for this, but it has some inconvenients:

  • I wanted to implement methods for reading different data types in different byte order (for example, readInt, readLEInt, readUInt, etc), while those classes only can read / write a byte or a byte array. This isn't really a problem because I could fix that in the wrapper. But here comes the second problem.
  • I wanted to be able to write and read at the same time because I'm using this to decompress some files. And so to create a wrapper for it I would need to include both ByteArrayInputStream and ByteArrayOutputStream. I don't know if those could be syncronized in some way or I'd have to write the entire data of one to the other each time I wrote to the wrapper.

And so, here comes my question: would using a ByteBuffer be more efficient? I know you can take integers, floats, etc from it, even being able to change the byte order. What I was wondering is if there is a real performance change between using a ByteBuffer and a ArrayList<Byte>.

AnkeyNigam
  • 2,810
  • 4
  • 15
  • 23
eric.m
  • 1,577
  • 10
  • 20
  • 2
    `ArrayList` doesn't sound like a good idea. – biziclop Jul 16 '15 at 12:15
  • If you need dynamically sized buffer, then look at my comment, use ByteArrayOutputStream, extend it and make use of fileds buf and count, to make some fast reading methods. It has adventage, that it has dynamical size; – Krzysztof Cichocki Jul 16 '15 at 12:34

3 Answers3

3

Definitely ByteBuffer or ByteArrayOutputStream. In your case ByteBuffer seems fine. Inspect the Javadoc, as it has nice methods, For putInt/getInt and such, you might want to set order (of those 4 bytes)

byteBuffer.order(ByteBuffer.LITTLE_ENDIAN);

With files you could use getChannel() or variants and then use a MappedByteBuffer.

A ByteBuffer may wrap a byte array, or allocate.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
1

Keep in mind that every object has overhead associated with it including a bit of memory per object and garbage collection once it goes out of scope.

Using List<Byte> would mean creating / garbage collecting an object per byte which is very wasteful.

lance-java
  • 25,497
  • 4
  • 59
  • 101
1

ByteBuffer is a wrapper class around a byte array, it doesn't have dynamical size like ArrayList, but it consumes less memory per byte and is faster. If you know the size you need, then use ByteBuffer, if you don't, then you could use ByteArrayOutputStream (and maybe wrapped by ObjectOutputStream, it has some methods to write different kinds of data). To read the data you have written to ByteArrayOutputStream you can extend the ByteArrayOutputStream, and then you can access the fields buf[] and count, those fields are protected, so you can access them from extending class, it look like:

public class ByteArrayOutputStream extends OutputStream {

    /**
     * The buffer where data is stored.
     */
    protected byte buf[];
    /**
     * The number of valid bytes in the buffer.
     */
    protected int count;
...
}


public class ReadableBAOS extends ByteArrayOutputStream{
    public byte readByte(int index) {
        if (count<index) {
            throw new IndexOutOfBoundsException();
        }
        return buf[index];
    }
}

so you can make some methods in your extending class to read some bytes from the underlying buffer without the need to make an copy of its content each time like toByteArray() method do.

Krzysztof Cichocki
  • 6,294
  • 1
  • 16
  • 32
  • `ByteBuffer` is not a wrapper class for `byte[]` although you can wrap a `byte[]` with it. If you use `allocateDirect` you'll get native memory instead of a `byte[]`. – Kayaman Jul 16 '15 at 12:41