0Pricing
Java Academy · レッスン

EnumSet

enum に対する高速な集合操作です。

「EnumSet」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

EnumSet とは

EnumSetは、列挙型専用の特殊な Set 実装です。

内部ではビットベクトルを使用し、各定数を1つのビットに対応付けます。そのため、列挙型の HashSet と比べて非常に高速で、メモリ効率にも優れています。

import java.util.EnumSet;
import java.util.Set;

public class Main {
    enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }
    public static void main(String[] args) {
        Set<Day> weekend = EnumSet.of(Day.SAT, Day.SUN);
        System.out.println(weekend);
    }
}

of による作成

ファクトリーメソッドの EnumSet.of(...)は、指定した定数からセットを作成します。1個から5個までの要素用のオーバーロードに加え、varargs 版もあります。

import java.util.EnumSet;

public class Main {
    enum Perm { READ, WRITE, EXECUTE }
    public static void main(String[] args) {
        EnumSet<Perm> perms = EnumSet.of(Perm.READ, Perm.WRITE);
        System.out.println(perms);
    }
}

allOf と noneOf

ほかにも、次の2つのファクトリーメソッドがあります。

  • allOf(Type.class)は、すべての定数を含むセットを作成します。
  • noneOf(Type.class)は、後から要素を追加できる空のセットを作成します。
import java.util.EnumSet;

public class Main {
    enum Color { RED, GREEN, BLUE }
    public static void main(String[] args) {
        EnumSet<Color> all = EnumSet.allOf(Color.class);
        EnumSet<Color> none = EnumSet.noneOf(Color.class);
        none.add(Color.RED);
        System.out.println("all: " + all);
        System.out.println("built: " + none);
    }
}

連続した定数に対する range

EnumSet.range(from, to)は、2つの端点の間にあるすべての定数を、両端を含めて宣言順に追加します。

import java.util.EnumSet;

public class Main {
    enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }
    public static void main(String[] args) {
        EnumSet<Day> workdays = EnumSet.range(Day.MON, Day.FRI);
        System.out.println(workdays);
    }
}

complementOf

EnumSet.complementOf(set)は、指定したセットに含まれないすべての定数からなるセットを返します。

選択内容を反転する高速な方法です。

import java.util.EnumSet;

public class Main {
    enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }
    public static void main(String[] args) {
        EnumSet<Day> work = EnumSet.range(Day.MON, Day.FRI);
        EnumSet<Day> rest = EnumSet.complementOf(work);
        System.out.println(rest);
    }
}

セット演算

EnumSet は通常の Set なので、addAll、retainAll、removeAllを使って和集合、積集合、差集合を求められます。

内部では、これらの処理がビット演算として非常に高速に実行されます。

import java.util.EnumSet;

public class Main {
    enum Tag { A, B, C, D }
    public static void main(String[] args) {
        EnumSet<Tag> x = EnumSet.of(Tag.A, Tag.B, Tag.C);
        EnumSet<Tag> y = EnumSet.of(Tag.B, Tag.C, Tag.D);
        EnumSet<Tag> inter = EnumSet.copyOf(x);
        inter.retainAll(y);
        System.out.println("intersection: " + inter);
    }
}

メンバーシップの確認

containsは1ビットを確認するだけなので、定数時間で非常に高速に実行されます。

import java.util.EnumSet;

public class Main {
    enum Feature { DARK_MODE, BETA, ANALYTICS }
    public static void main(String[] args) {
        EnumSet<Feature> enabled = EnumSet.of(Feature.DARK_MODE, Feature.BETA);
        System.out.println(enabled.contains(Feature.BETA));
        System.out.println(enabled.contains(Feature.ANALYTICS));
    }
}

フラグの代替としての EnumSet

EnumSet が登場する前は、プログラマーは READ | WRITEのようなint ビットフラグを使っていました。EnumSet は、これを型安全で読みやすい形に置き換えます。

手動マスク処理に伴う間違いやすさを避けながら、ビットフィールドの性能を得られます。

import java.util.EnumSet;
import java.util.Set;

public class Main {
    enum Style { BOLD, ITALIC, UNDERLINE }
    static void render(Set<Style> styles) {
        System.out.println("Applying: " + styles);
    }
    public static void main(String[] args) {
        render(EnumSet.of(Style.BOLD, Style.UNDERLINE));
    }
}

宣言順での反復

EnumSet は、定数の自然順序、つまり宣言順で反復します。

HashSet とは異なり、予測可能で安定した順序になります。

import java.util.EnumSet;

public class Main {
    enum Phase { ALPHA, BETA, RC, GA }
    public static void main(String[] args) {
        EnumSet<Phase> set = EnumSet.of(Phase.GA, Phase.ALPHA, Phase.RC);
        for (Phase p : set) System.out.println(p);
    }
}

copyOf による防御的コピー

EnumSet.copyOf(collection)は、列挙型の値のコレクションから EnumSet を作成します。安全なコピーを作成したり、List を変換したりする場合に使います。

import java.util.EnumSet;
import java.util.List;

public class Main {
    enum Role { ADMIN, EDITOR, VIEWER }
    public static void main(String[] args) {
        List<Role> source = List.of(Role.EDITOR, Role.VIEWER);
        EnumSet<Role> roles = EnumSet.copyOf(source);
        System.out.println(roles);
    }
}

高速な理由

定数が64個以下の列挙型では、EnumSet はビットベクトルとして単一の longを使用します。各操作は、マシン命令1〜2個で実行されます。

列挙型のセットには、常に HashSet<MyEnum>より EnumSet を優先してください。

import java.util.EnumSet;

public class Main {
    enum Bit { B0, B1, B2, B3 }
    public static void main(String[] args) {
        EnumSet<Bit> s = EnumSet.of(Bit.B0, Bit.B2);
        // contains is a single bit-and under the hood
        System.out.println(s.contains(Bit.B2));
    }
}

クイックチェック

EnumSet についての知識を確認しましょう。

まとめ

EnumSet について学びました。

  • 列挙型用のビットベクトル Setであり、非常に高速でコンパクトです。
  • ファクトリーメソッドには、of、allOf、noneOf、range、complementOf、copyOfがあります。
  • 宣言順で反復します。
  • int ビットフラグを型安全に置き換えられます。

次は、対応するマップ型の EnumMap です。

import java.util.EnumSet;

public class Main {
    enum X { A, B }
    public static void main(String[] args) {
        System.out.println("EnumSet recap: " + EnumSet.allOf(X.class));
    }
}

よくある質問

「EnumSet」レッスンは無料ですか?

はい。「EnumSet」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「EnumSet」で何を学びますか?

enum に対する高速な集合操作です。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「EnumSet」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. フィールドとメソッドを持つ enum
  2. enum の抽象メソッド
  3. EnumSet
  4. EnumMap
← Java Academyに戻る