8
\$\begingroup\$

I have this tiny function that expects an int and returns an int with the bytes swapped:

public class Main {
    
    public static void main(String[] args) {
        int cafeBabe = 0xcafebabe;
        System.out.println(Integer.toHexString(cafeBabe));
        System.out.println(Integer.toHexString(byteSwap(cafeBabe)));
        System.out.println(Integer.toHexString(byteSwap(byteSwap(cafeBabe))));
    }
    
    public static int byteSwap(int a) {
        return ((a & 0xff000000) >>> 24) |
               ((a & 0x00ff0000) >>> 8)  |
               ((a & 0x0000ff00) << 8)   |
               ((a & 0x000000ff) << 24);
    }
}

Basically, we are switching between endianess. Now, is there a better/more efficient way of accomplishing the task?

\$\endgroup\$
15
\$\begingroup\$

Historical Note

The very first comment on the OP's question -- long before any answers were posted -- was a question asked by myself, and it very pointedly asked:

Without using Integer.reverseBytes(cafeBabe)?

The question was two-fold:

  1. Point out to the OP that a built-in method exists, and is likely the most optimal way of doing this.
  2. Ask if they are trying to .

That comment/question has been removed. If the OP responded to it, the response has been deleted as well and I never saw it.

This answer is not advocating the OP . The Java JVM / JIT will have implemented the most efficient way of performing the operation, using internal features (such as @HotSpotIntrinsicCandidate) that are not necessarily available to the end-user.

Reinventing the wheel

public static int byteSwap(int a) {
    return ((a & 0xff000000) >>> 24) |
           ((a & 0x00ff0000) >>> 8)  |
           ((a & 0x0000ff00) << 8)   |
           ((a & 0x000000ff) << 24);
}

This function uses 6 distinct constants, 4 AND operations, 4 shifts, and 3 OR operations.

There is no point with the AND operation in ((a & 0xff000000) >>> 24) or in ((a & 0x000000ff) << 24) since the 24 bits which are being masked are immediately shifted out anyway. This removes 2 constants, and 2 AND operations, which reduces the code to:

public static int byteSwap(int a) {
    return (a >>> 24)               |
           ((a & 0x00ff0000) >>> 8) |
           ((a & 0x0000ff00) << 8)  |
           (a << 24);
}

By reworking the order of second operation, we can remove another constant, the 0x00ff0000, and instead reuse the 0xff00 constant. This eliminates the loading of the third bit mask constant, saving additional JVM byte code instructions:

public static int byteSwap(int a) {
    return (a >>> 24)           |
           ((a >>> 8) & 0xff00) |
           ((a & 0xff00) << 8)  |
           (a << 24);
}

This reworked version is very similar to the built-in Integer.reverseBytes() code in the system library:

@HotSpotIntrinsicCandidate
public static int reverseBytes(int i) {
    return (i << 24)            |
           ((i & 0xff00) << 8)  |
           ((i >>> 8) & 0xff00) |
           (i >>> 24);
}

I don't know if the difference in ordering gains any additional speed, but (dollars to donuts) the @HotSpotIntrinsicCandidate annotation probably does - so just use the built-in function.

| improve this answer | |
\$\endgroup\$
  • 3
    \$\begingroup\$ While the masking in (a & 0x000000FF) << 24 has no effect in this case, it sure adds its fair portion to readability. Since OP was asking for a more efficient way I'd at least mention that this kind of optimization is in the most obvious realms of micro optimizations, Also there is a builtin function reverseBytes(int). \$\endgroup\$ – Num Lock Sep 14 at 10:47
6
\$\begingroup\$

I like it, simple to read.


Personally, I prefer to keep operators on the new line, makes it easier to see how the lines belong together:

return ((a & 0xff000000) >>> 24)
     | ((a & 0x00ff0000) >>> 8)
     | ((a & 0x0000ff00) << 8)
     | ((a & 0x000000ff) << 24);

To follow your formatting convention.


You could putt the first and last byte underneath each other, to make the pattern even better visible:

return ((a & 0xff000000) >>> 24)
     | ((a & 0x000000ff) << 24)
     | ((a & 0x00ff0000) >>> 8)
     | ((a & 0x0000ff00) << 8);

That removes the pattern from the masks, but allows to easier deduce how the bytes are being moved.


You could also convert the int to a byte array (for example with the help of a ByteBuffer), and reverse that array before converting it back. But as far as effectiveness goes, I think this should be the one with the least operations, as basically any operation on a byte array would have to do the same thing and more.


As already pointed out, there is already Integer.reverseBytes(int) which is available since 1.5.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ With ByteBuffer you can simply reverse the endianess and then read back the int, no need to do that manually (always look at the methods of a class :) ). \$\endgroup\$ – Maarten Bodewes Sep 14 at 14:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.