読者です 読者をやめる 読者になる 読者になる

ビット演算には ByteBuffer が便利

Java

モダンでハイソでナウでヤングな Java プログラマの皆様はビット演算なんてものはもはや古代語の如く古めかしく、その上メンテ性が悪いので敬遠されることもしばしばですが、それでも稀にビット演算が必要になる場合が出てきます。

あまり使わないせいか久しぶりに触るとちょっと悩むことがあるので、さくっとメモしておきます。

int to bytes

まず int から byte[] への変換。int は 32 bit なので、8bit の byte 4 つ分になります。

public static byte[] int2bytes_(int value) {
    byte[] bytes = new byte[4];
    bytes[0] = (byte) (value >> 24);
    bytes[1] = (byte) (value >> 16);
    bytes[2] = (byte) (value >> 8);
    bytes[3] = (byte) value;
    return bytes;
}

Google Guava 使うと一撃で変換可能。

public static byte[] int2bytes(int value) {
    return Ints.toByteArray(value);
}


ByteBuffer というクラスを使うとこれも簡単に byte[] を得ることができます。

public static byte[] int2bytes(int value) {
    ByteBuffer buffer = ByteBuffer.allocate(4);
    buffer.putInt(value);
    return buffer.array();
}

上記3つ、いずれも同じ結果を返します。

bytes to int

では逆に byte[] から int へ。
素直にビット演算書くとこうなります。

public static int bytes2int(byte[] bytes) {
    int value = 0;
    value |= (bytes[0] & 0xFF);
    value <<= 8;
    value |= (bytes[1] & 0xFF);
    value <<= 8;
    value |= (bytes[2] & 0xFF);
    value <<= 8;
    value |= (bytes[3] & 0xFF);
    return value;
}

Google Guava 使うとこんな感じにさくっと書けます。

public static int bytes2int(byte[] bytes) {
    return Ints.fromByteArray(bytes);
}

ByteBuffer 版も良い感じに。

public static int bytes2int(byte[] bytes) {
    return ByteBuffer.wrap(bytes).getInt();
}

ints to bytes

さて、上記で int から byte へ、byte から int への変換を見てきました。
単一の int を変換する場合には上記コードで十分でしょう。
でも現実的には複数の int を byte[] へ、またはその逆をすることが多いです。

ではそのコードも比べてみましょう。

純粋なビット演算。元の int2bytes を使うとこんな感じになります。

public static byte[] ints2bytes(int[] ints) {
    byte[] result = new byte[ints.length * 4];
    for (int i = 0; i < ints.length; i++) {
        byte[] bytes = int2bytes(ints[i]);
        result[i * 4 + 0] = bytes[0];
        result[i * 4 + 1] = bytes[1];
        result[i * 4 + 2] = bytes[2];
        result[i * 4 + 3] = bytes[3];
    }
    return result;
}

でも ByteBuffer 使えば楽ちんです。すべての int を putInt して、buffer.array() するだけ。

public static byte[] ints2bytes(int[] ints) {
    ByteBuffer buffer = ByteBuffer.allocate(ints.length * 4);
    for (int i : ints) {
        buffer.putInt(i);
    }
    return buffer.array();
}

bytes to ints

逆に bytes から ints への変換。これも ByteBuffer 使えば楽ちんなのです。
bytes.length / 4 の長さの int 配列を用意して、asIntBuffer().get するだけ。

public static int[] bytes2ints(byte[] bytes) {
    ByteBuffer buffer = ByteBuffer.wrap(bytes);
    int[] ints = new int[bytes.length / 4];
    buffer.asIntBuffer().get(ints);
    return ints;
}

まとめ

Java でビット演算使う時は Google Guava もしくは ByteBuffer 使うと楽になるでしょう。

この本は超絶技巧的なビット演算が多数載っているので頭の体操になりまくります。

ハッカーのたのしみ―本物のプログラマはいかにして問題を解くか

ハッカーのたのしみ―本物のプログラマはいかにして問題を解くか

  • 作者: ジュニア,ヘンリー・S.ウォーレン,Jr.,Henry S. Warren,滝沢徹,鈴木貢,赤池英夫,葛毅,藤波順久
  • 出版社/メーカー: エスアイビーアクセス
  • 発売日: 2015/01
  • メディア: 単行本
  • この商品を含むブログを見る