-1

Suppose we have some binary data byte[] data that only contains Integers. If I wanted to read this data utilizing a DataInputStream, the only approach I can come up with is the following:

DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
try {
    while (true){
        int i = in.readInt();
    }
} catch (EOFException e) {
    // we're done!
} catch (IOException e){
    throw new RuntimeException(e);
}

What bugs me about this is that reaching the end of the stream is expected and it would exceptional only if no exception was thrown, what IMO defeats the purpose of exceptions in the first place.

When using Java NIO's IntBuffer, there's no such problem.

IntBuffer in = ByteBuffer.wrap(data).asIntBuffer();
while (in.hasRemaining()){
    int i = in.get();
}

Coming from C# and being in the process of learning Java I refuse to believe that this is the intended way of doing this.

Moreover, I just came across Java NIO which seems to be "quite new". Using IntBuffer here instead would be my way of procrastinating the matter. Regardless, I wanna know how this is properly done in Java.

Michael Schnerring
  • 3,584
  • 4
  • 23
  • 53

2 Answers2

1

You can't. readInt() can return any integer value, so an out-of-band mechanism is required to signal end of stream, so an exception is thrown. That's how the API was designed. Nothing you can do about it.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Okay, but isn't using exceptions as an out-of-band mechanism quite expensive? Would the better approach be to avoid `DataInputStream` altogether if the same can be accomplished with `IntBuffer` in this case? – Michael Schnerring Dec 04 '17 at 22:18
  • @MichaelSchnerring One exception per stream isn't expensive, unless the stream is astonishingly short. Use whichever suits you best, of course. `DataInputStream` is good for cases where there are all kinds of datatypes. `IntBuffer` may be better for you if there are only integers, and if you don't mind NIO. – user207421 Dec 04 '17 at 22:20
  • or if I read tons of streams, okay. This is slightly offtopic, but what could I possibly dislike about NIO? The only possible drawback I currently see is that only Java 7+ is supported. I just came across NIO, so I did not dive into it the whole matter, yet. – Michael Schnerring Dec 04 '17 at 22:27
  • Well it's more complicated than `java.io`, for example having to use `flip()` and `compact()`, and another learning curve. Nothing wrong with it once you learn it, but its design goals dictated a more complex API. – user207421 Dec 04 '17 at 23:02
  • Its more complex than IO. If you need the complexity of mixed datatypes, etc great. If not why not use a BufferedInputStream(etc)? – Totoro Dec 04 '17 at 23:03
  • @Totoro It *is* I/O, and `java.ioDataInput/OutputStream` manage the 'complexity of mixed datatypes' just as well as NIO, apart from endianness, and more simply. – user207421 Dec 04 '17 at 23:07
1

Since you are coming from .NET, Java's DataInputStream is roughly equivalent to BinaryReader of .NET.

Just like its .NET equivalent, DataInputStream class and its main interface, DataInput, have no provision for determining if a primitive of any given type is available for retrieval at the current position of the stream.

You can gain valuable insight of how the designers of the API expect you to use it by looking at designer's own usage of the API.

For example, look at ObjectInputStream.java source, which is used for object deserialization. The code that reads arrays of various types calls type-specific readXYZ methods of DataInput in a loop. In order to figure out where the primitives end, the code retrieves the number of items (line 1642):

private Object readArray(boolean unshared) throws IOException {
    if (bin.readByte() != TC_ARRAY) {
        throw new InternalError();
    }
    ObjectStreamClass desc = readClassDesc(false);
    int len = bin.readInt();
    ...
    if (ccl == Integer.TYPE) {
        bin.readInts((int[]) array, 0, len);
        ...
    }
    ...
}

Above, bin is a BlockDataInputStream, which is another implementation of DataInput interface. Note how len, the number of items in the array stored by array serialization counterpart, is passed to readInts, which calls readInt in a loop len times (line 2918).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523