EnumSetのガイド
1. 前書き
このチュートリアルでは、java.utilパッケージのEnumSetコレクションを調べて、その特性について説明します。
最初にコレクションの主な機能を示し、その後、その利点を理解するためにクラスの内部を確認します。
最後に、それが提供する主な操作について説明し、いくつかの基本的な例を実装します。
2. EnumSetとは
An EnumSet is a specialized Set collection to work with enum classes。 Setインターフェースを実装し、AbstractSetから拡張します。
AbstractSetおよびAbstractCollectionは、SetおよびCollectionインターフェースのほぼすべてのメソッドの実装を提供しますが、EnumSetはそれらのほとんどをオーバーライドします。
EnumSetを使用する場合は、いくつかの重要な点を考慮する必要があります。
-
It can contain only enum valuesおよびすべての値は同じenumに属している必要があります
-
It doesn’t allow to add null values、そうしようとしてNullPointerExceptionをスローします
-
It’s not thread-safeなので、必要に応じて外部で同期する必要があります
-
要素は、enumで宣言された順序に従って格納されます。
-
コピーで機能するIt uses a fail-safe iterator。したがって、コレクションを反復処理するときにコレクションが変更されても、ConcurrentModificationExceptionはスローされません。
3. EnumSetを使用する理由
経験則として、EnumSet should always be preferred over any other Set implementation when we are storing enum values.
次のセクションでは、このコレクションが他のコレクションよりも優れている理由を説明します。 そのために、クラスの内部を簡単に示して理解を深めます。
3.1. 実装の詳細
EnumSetはpublicabstractクラスであり、インスタンスの作成を可能にする複数の静的ファクトリメソッドが含まれています。 JDKは、2つの異なる実装を提供します–package-privateであり、ビットベクトルによってサポートされています。
-
RegularEnumSetおよび
-
JumboEnumSet
RegularEnumSet uses a single long to represent the bit vector.long要素の各ビットは、enumの値を表します。 列挙型のi番目の値はi番目のビットに格納されるため、値が存在するかどうかを簡単に知ることができます。 Since long is a 64-bit data type, this implementation can store up to 64 elements.
一方、JumboEnumSet uses an array of long elements as a bit vector.This lets this implementation store more than 64 elements.は、RegularEnumSetとほとんど同じように機能しますが、値が格納されている配列インデックスを見つけるためにいくつかの追加の計算を行います。
当然のことながら、配列の最初の長い要素は、enumの64個の最初の値を格納し、2番目の要素は次の64個というように格納します。
EnumSetファクトリメソッドは、enumの要素の数に応じて、ある実装または別の実装のインスタンスを作成します。
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
コレクションに格納される要素の数ではなく、enumクラスのサイズのみが考慮されることに注意してください。
3.2. EnumSetを使用する利点
上記で説明したEnumSetの実装により、all the methods in an EnumSet are implemented using arithmetic bitwise operations.これらの計算は非常に高速であるため、すべての基本的な操作は一定の時間で実行されます。
EnumSetをHashSetなどの他のSet実装と比較すると、値は予測可能な順序で格納され、計算ごとに1ビットのみを調べる必要があるため、通常は最初の実装の方が高速です。 HashSetとは異なり、適切なバケットを見つけるためにhashcodeを計算する必要はありません。
さらに、ビットベクトルの性質により、EnumSetは非常にコンパクトで効率的です。 したがって、使用するメモリが少なくなり、すべての利点が得られます。
4. 主な操作
EnumSetのメソッドの大部分は、インスタンスを作成するメソッドを除いて、他のSetと同じように機能します。
次のセクションでは、すべての作成方法を詳細に示し、残りの方法について簡単に説明します。
この例では、Colorenumを使用します。
public enum Color {
RED, YELLOW, GREEN, BLUE, BLACK, WHITE
}
4.1. 創造方法
The most simple methods to create an EnumSet are allOf() and noneOf().このようにして、Color列挙型のすべての要素を含むEnumSetを簡単に作成できます。
EnumSet.allOf(Color.class);
同様に、noneOf()を使用して反対のことを行い、Colorの空のコレクションを作成できます。
EnumSet.noneOf(Color.class);
If we want to create an EnumSet with a subset of the enum elements we can use the overloaded of() methods。 最大5つの異なるパラメータの固定数を持つメソッドと、varargsを使用するメソッドを区別することが重要です。
Javadocは、配列の作成により、varargsバージョンのパフォーマンスが他のバージョンよりも遅くなる可能性があると述べています。 したがって、最初に5つ以上の要素を追加する必要がある場合にのみ使用する必要があります。
enumのサブセットを作成する別の方法は、range()メソッドを使用することです。
EnumSet.range(Color.YELLOW, Color.BLUE);
上記の例では、EnumSetにはYellowからBlue.までのすべての要素が含まれています。これらはenumで定義された順序に従います。
[YELLOW, GREEN, BLUE]
指定された最初と最後の要素の両方が含まれていることに注意してください。
Another useful factory method is the complementOf() that allows us to exclude the elements passed as parameters。 黒と白を除くすべてのColor要素を使用してEnumSetを作成しましょう。
EnumSet.complementOf(EnumSet.of(Color.BLACK, Color.WHITE));
このコレクションを印刷すると、他のすべての要素が含まれていることがわかります。
[RED, YELLOW, GREEN, BLUE]
最後に、we can create an EnumSet by copying all the elements from another EnumSet:
EnumSet.copyOf(EnumSet.of(Color.BLACK, Color.WHITE));
内部的には、cloneメソッドを呼び出します。
さらに、we can also copy all the elements from any Collection that contains enum elements。 これを使用して、リストのすべての要素をコピーしましょう。
List colorsList = new ArrayList<>();
colorsList.add(Color.RED);
EnumSet listCopy = EnumSet.copyOf(colorsList);
この場合、listCopyには赤色のみが含まれます。
4.2. その他の事業
残りの操作は、他のSetの実装とまったく同じように機能し、使用方法に違いはありません。
したがって、空のEnumSetを簡単に作成し、いくつかの要素を追加できます。
EnumSet set = EnumSet.noneOf(Color.class);
set.add(Color.RED);
set.add(Color.YELLOW)
コレクションに特定の要素が含まれているかどうかを確認します。
set.contains(Color.RED);
要素を反復処理します。
set.forEach(System.out::println);
または、単純に要素を削除します。
set.remove(Color.RED);
もちろん、これは、Setがサポートする他のすべての操作の中でも特に重要です。
5. 結論
この記事では、EnumSetの主な機能、その内部実装、およびそれを使用することでどのようにメリットが得られるかを示しました。
また、提供される主な方法についても説明し、それらの使用方法を示すためにいくつかの例を実装しました。
いつものように、例の完全なソースコードはover on GitHubで入手できます。