25

I have a byte array where the data in the array is actually short data. The bytes are ordered in little endian:

3, 1, -48, 0, -15, 0, 36, 1

Which when converted to short values results in:

259, 208, 241, 292

Is there a simple way in Java to convert the byte values to their corresponding short values? I can write a loop that just takes every high byte and shift it by 8 bits and OR it with its low byte, but that has a performance hit.

ᄂ ᄀ
  • 5,669
  • 6
  • 43
  • 57
Johann
  • 27,536
  • 39
  • 165
  • 279
  • 2
    You've given 8 bytes, and then 4 longs... whereas 8 bytes should only result in a *single* long value. Additionally, you haven't said what you expected. Basically your question is very unclear at the moment... – Jon Skeet Feb 12 '13 at 07:20
  • 1
    No, it's not unclear. You have the data from the byte array and what it converts to. Can't be more obvious than that. – Johann Feb 12 '13 at 07:21
  • 9
    Yes, it can. Because it sounds like you're *actually* converting to `short`, not `long`... and you haven't said what you *expect* the results to be. Feel free not to make the question any clearer - but remember that you're the one looking for help, and the better your question, the better that help is likely to be. – Jon Skeet Feb 12 '13 at 07:25
  • 4
    @AndroidDev please, read Jon's messages again, carefully. He really knows what he's saying. – andr Feb 12 '13 at 07:28
  • 3
    @AndroidDev: Let's see exactly what's not clear: 1) Why you're expecting 4 `long` values out of 8 `byte` values, when a `long` has 8 bytes-worth of data; 2) what code you're using to get the *incorrect* values; 3) how you expect negative numbers to be treated; 4) why you're being rude to someone who is trying to help you. – Jon Skeet Feb 12 '13 at 07:34

2 Answers2

58

With java.nio.ByteBuffer you may specify the endianness you want: order().

ByteBuffer have methods to extract data as byte, char, getShort(), getInt(), long, double...

Here's an example how to use it:

ByteBuffer bb = ByteBuffer.wrap(byteArray);
bb.order( ByteOrder.LITTLE_ENDIAN);
while( bb.hasRemaining()) {
   short v = bb.getShort();
   /* Do something with v... */
}
Aubin
  • 14,617
  • 9
  • 61
  • 84
  • 1
    (Just don't expect `getLong()` to convert *two* bytes as per the sample data in the question. You'd want to call `getShort()` for that.) – Jon Skeet Feb 12 '13 at 07:38
  • Actually, I want getShort which gives me the results. Still, your solution is the correct one. – Johann Feb 12 '13 at 07:44
  • 3
    @AndroidDev: You realize that under the hood, this is doing *precisely* the bitwise OR which you claims has a (presumably unacceptable) performance hit, right? – Jon Skeet Feb 12 '13 at 07:58
  • How it does it "under the hood" isn't obvious without looking at the java internal coding. Still any native calls will usually have a higher performance than anything you try to duplicate at a higher level. – Johann Feb 12 '13 at 08:11
  • 2
    @AndroidDev: They're not native. They're written in Java, and Hotspot will JIT your own code in the same way, as far as I'm aware. It's easy enough to look into ByteBuffer, then HeapByteBuffer, then Bits, following the code path. In fact, given the layers of indirection, I suspect if you wrote the code manually it would be *faster* than using ByteBuffer. Did you test it before assuming the performance hit was significant? – Jon Skeet Feb 12 '13 at 08:50
  • 3
    @JonSkeet You're right. The above code is about 6 times slower than just shifting and ORing the bytes. Was rather surprised. – Johann Feb 12 '13 at 14:25
  • @AndroidDev: Well with ByteBuffer, you've got at least one virtual call, and a condition (based on the endianness). If you put it in a loop yourself, you don't need *anything* to be conditional. – Jon Skeet Feb 12 '13 at 14:30
  • @AndroidDev See https://stackoverflow.com/questions/13973035/what-is-the-quantitative-overhead-of-making-a-jni-call If by "native" you invoke something via JNI then you are adding a certain overhead for the function call. If the performance gained by doing the computation in some native piece of code outweighs the overhead, then you are right; but generally it might not be (especially for a lot of small invocations) true that the native computation is always faster (including calling it form the JVM). – scravy Aug 06 '18 at 09:25
2
 /* Try this: */
public static short byteArrayToShortLE(final byte[] b, final int offset) 
{
        short value = 0;
        for (int i = 0; i < 2; i++) 
        {
            value |= (b[i + offset] & 0x000000FF) << (i * 8);
        }            

        return value;
 }

 /* if you prefer... */
 public static int byteArrayToIntLE(final byte[] b, final int offset) 
 {
        int value = 0;

        for (int i = 0; i < 4; i++) 
        {
           value |= ((int)b[i + offset] & 0x000000FF) << (i * 8);
        }

       return value;
 }