[Java]可変長引数とオーバーロード その1

2016年9月26日月曜日

Java

お互いに排他的ではない複数の条件がある場合、従来から用いられてきた方法としては複数のビットフラグを用いる方法がある。

enum.c
#include 

enum Color {
    Color_Red   = 1,
    Color_Green = 2,
    Color_Blue  = 4,
};

int main(void) {
    int yellow = Color_Red | Color_Green;
    printf("yellow : %d\n", yellow);

    int white = Color_Red | Color_Green | Color_Blue;
    printf("white : %d\n", white);
}
$ ./enum
yellow : 3
white : 7

Cなんかだとよく用いられる方法だけど、Javaの場合、enumは整数ではなくオブジェクトであるため、単純にこの操作はできない。
Javaでこの操作をするには以下のクラスを使う。
  • java.util.BitSet
  • java.util.EnumSet
enumのように最初から種類が固定化されていないデータのON/OFFを扱いたい場合はBitSetを使うといいだろう。
実行時に要素数が決まるような場合だね。

BitSample.java
package local;

import java.util.BitSet;

class BitSample {
    public static void main(String ... args) {
        BitSet prime = new BitSet(10);
        prime.set(2);
        prime.set(3);
        prime.set(5);
        prime.set(7);

        System.out.println(prime);
    }
}
$ java local.BitSample
{2, 3, 5, 7}
$ 

enumの複数の組み合わせを取り扱いたい場合はEnumSetを使う。

EnumSample.java
package local;

import java.util.EnumSet;

class EnumSample {
    private static enum Color { Red, Green, Blue }

    public static void main(String ... args) {
        EnumSet yellow = EnumSet.of(Color.Red, Color.Green);
        System.out.println(yellow);

        EnumSet white = EnumSet.allOf(Color.class);
        System.out.println(white);
    }
}
$ java local.EnumSample
[Red, Green]
[Red, Green, Blue]
$ 

。。。で、このEnumSetのofメソッドのオーバーロードがちょっと変わったことになっていた。
要素を1〜5個まで指定できるオーバーロードと可変長引数になっているオーバーロードが存在するのだ。

https://docs.oracle.com/javase/jp/8/docs/api/java/util/EnumSet.html#of-E-E...-
指定された要素が最初に含まれるenumセットを作成します。そのパラメータ・リストが可変引数機能を使用するこのファクトリは、最初に任意の数の要素を含むenumセットを作成するために使用される場合がありますが、可変引数を使用しないオーバーロードより低速に実行される傾向があります。

どうもパフォーマンス上の理由でこうなってるみたい。確かにEnumSetは高速性が売りだからね。 メソッド呼び出しの都度、配列を生成することになるからだとは思うけど、そんなに違うものなのかな。
可変長引数は何度も呼び出されるユーティリティメソッドで使われることも多いと思うので、パフォーマンス要求がシビアな場面では配列引数にした方がいいかもしれない。