19 Dec 2014, 12:18

Java の Map で byte 配列をキーにするときの注意点

はじめに

Java で HashMap のキーに byte[] 配列を利用したら, key を put しても containsKey で key がないよといわれてしまった.

static void testbyteMap () {
    Map<byte[], Integer> map = new HashMap<byte[], Integer>();
    byte[] key = {1,2,3};
    byte[] key2 = {4,5,6};
    byte[] key3 = {1,2,3};

    map.put (key,1);
    map.put (key2,2);

    System.out.println (map.containsKey (key));
    System.out.println (map.containsKey (key2));
    System.out.println (map.containsKey (key3));
}

結果

true
true
false

調査

どうも配列を入れても, うまく検出できないようだ.

同一オブジェクトだと, 大丈夫だが, 値が同じでも違うオブジェクトだとだめ.

static void testIntMap () {
    Map<int[], Integer> map = new HashMap<int[], Integer>();
    int[] key = {1,2,3};
    int[] key2 = {4,5,6};;
    int[] key3 = {1,2,3};;

    map.put (key,1);
    map.put (key2,2);

    System.out.println (map.containsKey (key));
    System.out.println (map.containsKey (key2));
    System.out.println (map.containsKey (key3));
}

解決策

原因は, byte[] が 大小比較できないから.

Stack Overflow によると

  • byte[] を String に変換
  • byte[] をを List<Byte>に変換
  • equals と hashmap を実装した ラッパーデータ型を作成

String 変換を試す

一番お手軽なのは, String 変換か?

static void testStringMap () throws UnsupportedEncodingException {
    Map<String, Integer> map = new HashMap<String, Integer>();
    byte[] key = {1,2,3};
    byte[] key2 = {4,5,6};
    byte[] key3 = {1,2,3};

    String keyStr = new String (key, "UTF-8");
    String keyStr2 = new String (key2, "UTF-8");
    String keyStr3 = new String (key3, "UTF-8");        

    map.put (keyStr,1);
    map.put (keyStr2,2);

    System.out.println (map.containsKey (keyStr));
    System.out.println (map.containsKey (keyStr2));
    System.out.println (map.containsKey (keyStr3));
}

static void testStringMap2 () throws UnsupportedEncodingException {
    Map<String, Integer> map = new HashMap<String, Integer>();
    byte[] key = {1,2,3};
    byte[] key2 = {4,5,6};
    byte[] key3 = {1,2,3};

    String keyStr = Arrays.toString (key);
    String keyStr2 = Arrays.toString (key2);
    String keyStr3 = Arrays.toString (key3);        

    map.put (keyStr,1);
    map.put (keyStr2,2);

    System.out.println (map.containsKey (keyStr));
    System.out.println (map.containsKey (keyStr2));
    System.out.println (map.containsKey (keyStr3));
}

結果

これで OK.

true
true
true

Special Thanks