---
title: Enum 徹底入門
tags:  #java  
author: [hirotaka kono](https://www.docswell.com/user/hk_it7)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/LE3WV9WDE5.jpg?width=480
description: JJUG CCC 2026 Spring / こうの（虎の穴ラボ） @hk_it7 登壇資料
published: May 30, 26
canonical: https://www.docswell.com/s/hk_it7/Z8NMQ1-2026-05-30-075434
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/LE3WV9WDE5.jpg)

Enum 徹底入門
Javaの「クラス」としての Enum を使い倒す
JJUG CCC 2026 Spring / こうの（虎の穴ラボ）


# Page. 2

![Page Image](https://bcdn.docswell.com/page/8EDK8GK27G.jpg)

リンク
Twitter 実況補助ツール
サンプルコード &amp; スライド HTML
https://h-kono-it.github.io/conference-tweet-helper/
https://github.com/h-kono-it/jjug_ccc_2026_spring-enum
実況補助ツールは今すぐ、手元で見たい方は右の QR からどうぞ
2


# Page. 3

![Page Image](https://bcdn.docswell.com/page/V7PK83KLJ8.jpg)

早速ですが…「定数」の管理、どうしてる？
public class OrderService {
public static final int STATUS_PENDING
= 0;
public static final int STATUS_PROCESSING = 1;
public static final int STATUS_COMPLETED
= 2;
public static final int STATUS_FAILED
= 3;
public void process(int status) {
if (status == STATUS_PENDING) {
// ...
}
}
}
シンプルに見えるが、落とし穴がある
3


# Page. 4

![Page Image](https://bcdn.docswell.com/page/2JVVN4V6JQ.jpg)

どんな問題が起きる？
// 定数を「使ってくれる」保証がない
service.process(STATUS_PENDING);
// ◯ お行儀の良い呼び出し
service.process(0);
// ✗ 直書きされても止められない
service.process(999);
// ✗ 範囲外の値もコンパイルは通る
// String 版も同じ
service.process(&quot;pedning&quot;);
// ✗ typo がすり抜ける
service.process(&quot;PENDING&quot;);
// ✗ 大文字小文字のゆれも通る
強制力がない — 「定数を使う」のは規約頼み。直書きを防げない
範囲外の値を常に考慮 — テストで「不正値が来たら」のケースが付きまとう
意図が伝わらない — 引数の /
だけでは何を渡すべきか分からない
int
String
これを「型」で解決するのが Enum。今日はその活用術を詳しく話します！
4


# Page. 5

![Page Image](https://bcdn.docswell.com/page/5EGLK1L2JL.jpg)

今日話すこと
1. なぜ Enum か？ — 動機とメリット
2. Enum の仕組み — JLS とコンパイル後の姿
3. プロパティと振る舞いを持つ Enum
4. Enum と DB — ORM マッピング
5. Enum の活用パターン — EnumSet/EnumMap・状態遷移・Singleton
6. Enum の進化 — switch 式
7. Enum vs Sealed Class — パターンマッチングとの相性
5


# Page. 6

![Page Image](https://bcdn.docswell.com/page/4JQYNDY97P.jpg)

Enumの「端的で強力な」メリット
enum OrderStatus {
PENDING, PROCESSING, COMPLETED, FAILED
}
public void process(OrderStatus status) { ... }
// 有効な値しか渡せない
service.process(OrderStatus.PENDING);
// ✓ IDE が補完してくれる
service.process(999);
// ✗ コンパイルエラー
service.process(&quot;pedning&quot;);
// ✗ コンパイルエラー
定数の意味・有効な範囲が 型として明示 される
6


# Page. 7

![Page Image](https://bcdn.docswell.com/page/K74WGZZRE1.jpg)

型で実装を制限し、仕様を明確にする
// シグネチャだけで「渡せる値」が伝わる
void sendNotification(NotificationType type, Priority priority);
order.setStatus( /* ここで補完 */ )
// → IDE も Copilot / Claude も OrderStatus の定数一覧を提示
メソッドシグネチャを見るだけで 何を渡せるか が分かる
IDE 補完で有効な値の一覧が即座に出る／AI も型情報を読んで生成 する
AI が生成したコードも コンパイラが検証 してくれる
選択肢を増やしたときの対処漏れも検出できる（後述の switch 網羅性）
意図をコードに込めるほど、人間も AI も読みやすいコードになる
7


# Page. 8

![Page Image](https://bcdn.docswell.com/page/LJ1YDRRVEG.jpg)

Enum の仕組み
JLS の定義とコンパイル後の姿
8


# Page. 9

![Page Image](https://bcdn.docswell.com/page/GJWGY11372.jpg)

Enum の仕組み（JLS の定義）
Java の Enum は 特殊なクラス
が自動的に付与される（明示的には書けない）
各定数は
なシングルトンインスタンス
コンストラクタは暗黙的に
/
はコンパイラが自動生成
extends Enum&lt;T&gt;
static final
private
values()
valueOf()
Season s = Season.SPRING;
s.name()
// → &quot;SPRING&quot;
Season.values()
// → Season[] 全定数の配列
Season.valueOf(&quot;AUTUMN&quot;)
// → Season.AUTUMN
9


# Page. 10

![Page Image](https://bcdn.docswell.com/page/4EZLXPPG73.jpg)

コンパイル後の姿
// javac が生成するイメージ
public final class Season extends Enum&lt;Season&gt; {
public static final Season SPRING = new Season(&quot;SPRING&quot;, 0);
public static final Season SUMMER = new Season(&quot;SUMMER&quot;, 1);
// AUTUMN, WINTER も同様...
private Season(String name, int ordinal) {
super(name, ordinal);
}
// values(), valueOf() も自動生成される
}
クラスは
→ 継承不可
各定数はシングルトン → での比較が安全
final
==
10


# Page. 11

![Page Image](https://bcdn.docswell.com/page/Y76W4MMQ7V.jpg)

プロパティと振る舞いを持つ Enum
11


# Page. 12

![Page Image](https://bcdn.docswell.com/page/G75MQZZ274.jpg)

フィールドを持つ Enum
public enum Status {
PENDING(&quot;pending&quot;,
&quot;処理待ち&quot;),
PROCESSING(&quot;processing&quot;, &quot;処理中&quot;),
COMPLETED(&quot;completed&quot;, &quot;完了&quot;),
FAILED(&quot;failed&quot;,
&quot;失敗&quot;);
private final String code;
private final String label;
Status(String code, String label) {
this.code
= code;
this.label = label;
}
public String getCode()
{ return code; }
public String getLabel() { return label; }
}
コンストラクタは暗黙的に
private
。フィールドは
final
にするのが慣習。
12


# Page. 13

![Page Image](https://bcdn.docswell.com/page/9J29PRR1ER.jpg)

static ファクトリメソッド
// DB の値（code 文字列）から Enum を逆引き
public static Status fromCode(String code) {
return Arrays.stream(values())
.filter(s -&gt; s.code.equals(code))
.findFirst()
.orElseThrow(() -&gt;
new IllegalArgumentException(&quot;不正なコード: &quot; + code));
}
// 見つからない場合は Optional で返す版
public static Optional&lt;Status&gt; findByCode(String code) {
return Arrays.stream(values())
.filter(s -&gt; s.code.equals(code))
.findFirst();
}
valueOf()
は定数名での逆引き。コード値での逆引きは自前で実装する。
13


# Page. 14

![Page Image](https://bcdn.docswell.com/page/DEY45DD4JM.jpg)

振る舞いのポリモーフィズム（抽象メソッド）
public enum Operation {
ADD {
@Override
public double apply(double x, double y) { return x + y; }
},
SUBTRACT {
@Override
public double apply(double x, double y) { return x - y; }
};
// MULTIPLY, DIVIDE も同様...
public abstract double apply(double x, double y);
}
// 使う側は switch 不要
double result = Operation.ADD.apply(3.0, 4.0);
// → 7.0
Strategy パターン を Enum の中にコンパクトに閉じ込められる
14


# Page. 15

![Page Image](https://bcdn.docswell.com/page/VJNYN66678.jpg)

Lambda フィールド（よりコンパクトに）
public enum Operation {
ADD(&quot;+&quot;,
(x, y) -&gt; x + y),
SUBTRACT(&quot;-&quot;, (x, y) -&gt; x - y),
MULTIPLY(&quot;*&quot;, (x, y) -&gt; x * y),
DIVIDE(&quot;/&quot;,
(x, y) -&gt; x / y),
POWER(&quot;^&quot;,
Math::pow);
// メソッド参照も OK
private final String symbol;
private final BiFunction&lt;Double, Double, Double&gt; fn;
Operation(String symbol, BiFunction&lt;Double, Double, Double&gt; fn) {
this.symbol = symbol; this.fn = fn;
}
public double apply(double x, double y) { return fn.apply(x, y); }
}
抽象メソッド版より 定義がコンパクト。定数クラス体が不要になる。
15


# Page. 16

![Page Image](https://bcdn.docswell.com/page/YE9PRLLRJ3.jpg)

Enum と DB
ORM マッピングのベストプラクティス
16


# Page. 17

![Page Image](https://bcdn.docswell.com/page/GE8DWXXGED.jpg)

@Enumerated
@Enumerated
だけだと足りない理由
は JPA 標準の Enum カラム マッピング指定。
ORDINAL
と
STRING
の2択。
// ORDINAL — 宣言順の番号（0, 1, 2...）をそのまま保存
@Enumerated(EnumType.ORDINAL)
private Status status;
// → 定数の追加・並び替えで既存データが壊れる
// STRING — 定数名（&quot;PENDING&quot;, &quot;COMPLETED&quot;...）をそのまま保存
@Enumerated(EnumType.STRING)
private Status status;
// → 定数をリネームすると既存データとズレる
Java のコード と DB が密結合 =&gt; Java 側を修正しづらくなる
コード表現と データ管理を分離する ために、Enum 自身にコード値を持たせる
17


# Page. 18

![Page Image](https://bcdn.docswell.com/page/LELMN88X7R.jpg)

DBにはコード値を持たせる
enum Status {
PENDING(&quot;pending&quot;), COMPLETED(&quot;completed&quot;), FAILED(&quot;failed&quot;);
private final String code;
Status(String code) { this.code = code; }
public String getCode() { return code; }
public static Status fromCode(String code) {
return Arrays.stream(values())
.filter(s -&gt; s.code.equals(code))
.findFirst().orElseThrow();
}
}
Java の定数名（
PENDING
）と DB の値（
&quot;pending&quot;
）を 切り離す
18


# Page. 19

![Page Image](https://bcdn.docswell.com/page/4JMYX663JW.jpg)

Converter で橋渡し（JPA）
Spring Data JPA / Hibernate で使える
MyBatis の場合は
で同様のことができる
定数のリネームが DB に影響しない
AttributeConverter
TypeHandler
@Converter(autoApply = true)
class StatusConverter
implements AttributeConverter&lt;Status, String&gt; {
@Override
public String convertToDatabaseColumn(Status s) {
return s.getCode();
// Java → DB
}
@Override
public Status convertToEntityAttribute(String code) {
return Status.fromCode(code); // DB → Java
}
}
19


# Page. 20

![Page Image](https://bcdn.docswell.com/page/PJR9NPPR79.jpg)

Enum の活用パターン
EnumSet / EnumMap・状態遷移・Singleton
20


# Page. 21

![Page Image](https://bcdn.docswell.com/page/PEXQN33YJX.jpg)

集合と判定に便利な EnumSet
enum Permission { READ, WRITE, DELETE, ADMIN }
EnumSet&lt;Permission&gt; userPerms = EnumSet.of(Permission.READ, Permission.WRITE);
EnumSet&lt;Permission&gt; allPerms
= EnumSet.allOf(Permission.class);
EnumSet&lt;Permission&gt; restricted = EnumSet.complementOf(userPerms); // [DELETE, ADMIN]
EnumSet&lt;Day&gt; weekdays = EnumSet.range(Day.MON, Day.FRI);
// 範囲指定
boolean canDelete = userPerms.contains(Permission.DELETE);
// false
内部実装は ビットベクター →
/
/
/
権限・フラグの集合 に便利
of
allOf
complementOf
より高速・省メモリ
など生成 API が豊富
HashSet
range
21


# Page. 22

![Page Image](https://bcdn.docswell.com/page/3EK9NYY4ED.jpg)

集計に便利な EnumMap
// 注文ステータス別の件数を集計
EnumMap&lt;OrderStatus, Integer&gt; count = new EnumMap&lt;&gt;(OrderStatus.class);
for (OrderStatus s : OrderStatus.values()) count.put(s, 0);
// 全キーを 0 で初期化
orders.forEach(o -&gt; count.merge(o.getStatus(), 1, Integer::sum));
count.forEach((status, n) -&gt; System.out.printf(&quot;%-12s: %d件%n&quot;, status, n));
// PENDING
: 12件
// PROCESSING
:
// COMPLETED
: 47件
// FAILED
:
3件
0件
← 0 件のステータスも漏れなく出る
全キーを事前初期化 できるので「0件」も含めて確実にレポートできる
順序は Enum の宣言順 で安定 → 表・グラフの並びがブレない
内部は 配列 実装 →
より高速・省メモリ
HashMap
ダッシュボード・帳票・メトリクス集計で刺さる
22


# Page. 23

![Page Image](https://bcdn.docswell.com/page/L73WV99D75.jpg)

ステートマシンを Enum で表現
public enum DocumentState {
DRAFT
{ public Set&lt;DocumentState&gt; nextStates() { return Set.of(REVIEWING, CANCELLED); } },
REVIEWING { public Set&lt;DocumentState&gt; nextStates() { return Set.of(APPROVED, REJECTED, DRAFT); } },
APPROVED
{ public Set&lt;DocumentState&gt; nextStates() { return Set.of(PUBLISHED, CANCELLED); } },
PUBLISHED { public Set&lt;DocumentState&gt; nextStates() { return Set.of(ARCHIVED); } },
ARCHIVED
{ public Set&lt;DocumentState&gt; nextStates() { return Set.of(); } };
// 終端
public abstract Set&lt;DocumentState&gt; nextStates();
public DocumentState transitionTo(DocumentState next) {
if (!nextStates().contains(next))
throw new IllegalStateException(this + &quot; → &quot; + next + &quot; は許可されていない&quot;);
return next;
}
}
状態と遷移ルールが Enum 1つに閉じる — 仕様書のようなコード
23


# Page. 24

![Page Image](https://bcdn.docswell.com/page/87DK8GG2JG.jpg)

Enum で Singleton（Effective Java Item 3）
public enum AppConfig {
INSTANCE;
// ← これだけで Singleton 完成
private int requestCount = 0;
public void handleRequest(String msg) { requestCount++; /* ... */ }
public int getRequestCount() { return requestCount; }
}
// 使う側
AppConfig.INSTANCE.handleRequest(&quot;hello&quot;);
クラスロード時に1回だけ初期化 → スレッドセーフ
シリアライズ しても同一インスタンスが保たれる
リフレクション攻撃 にも強い
Effective Java 推奨。
private static final
+ ロックを書く必要なし
24


# Page. 25

![Page Image](https://bcdn.docswell.com/page/VJPK833LE8.jpg)

Enum の進化
switch 式の網羅性
25


# Page. 26

![Page Image](https://bcdn.docswell.com/page/2EVVN446EQ.jpg)

switch 式の網羅性チェック（Java 14+）
String label = switch (status) {
case PENDING
-&gt; &quot;処理待ち&quot;;
case PROCESSING -&gt; &quot;処理中&quot;;
case COMPLETED
-&gt; &quot;完了&quot;;
case FAILED
-&gt; &quot;失敗&quot;;
// 全ケース網羅 → default 不要！
};
新しい定数を追加するとコンパイルエラーになる
error: the switch expression does not cover all possible input values
対処漏れをゼロに。
26


# Page. 27

![Page Image](https://bcdn.docswell.com/page/57GLK112EL.jpg)

Enum vs Sealed Class
それぞれの使いどき
27


# Page. 28

![Page Image](https://bcdn.docswell.com/page/4EQYNDD9JP.jpg)

Enum vs Sealed Class
Enum
Sealed Class / Interface
インスタンス数 コンパイル時確定（固定） 実行時に複数作れる
データの形
全定数で同じ型のフィールド サブクラスごとに異なる構造
switch 網羅性 ✓（Java 14+）
✓（Java 21+）
シリアライズ 自動的に安全
要実装
使いどき
値の種類・状態が固定
形が異なるデータ
// Enum が向く：「状態の種類」
enum OrderStatus { PENDING, SHIPPED, DELIVERED, CANCELLED }
// Sealed が向く：「形が違うデータ」
sealed interface Shape
permits Circle, Rectangle, Triangle {}
28


# Page. 29

![Page Image](https://bcdn.docswell.com/page/KJ4WGZGR71.jpg)

Sealed × パターンマッチング（Java 21+）
sealed interface Shape permits Circle, Rectangle, Triangle {}
record Circle(double r) implements Shape {}
record Rectangle(double w, double h) implements Shape {}
record Triangle(double a, double b, double c) implements Shape {}
static double area(Shape shape) {
return switch (shape) {
case Circle c
-&gt; Math.PI * c.r() * c.r();
case Rectangle r -&gt; r.w() * r.h();
case Triangle t
-&gt; heron(t.a(), t.b(), t.c());
// sealed なので全ケース網羅 → default 不要！
};
}
型パターン で各サブクラスのフィールドにそのままアクセスできる
Enum の switch 網羅性が 「形の違うデータ」にまで拡張 されたイメージ
Enum を sealed interface の実装にも混ぜられる（特殊な単一定数など）
29


# Page. 30

![Page Image](https://bcdn.docswell.com/page/LE1YDRDV7G.jpg)

今日のまとめ！
1. Enum は「クラス」— フィールドと振る舞いを持たせろ
コード値・ラベル・ロジックを Enum 1つに閉じ込める。Strategy も状態遷移もここで完結す
る。
2. DB と Enum の間には Converter を挟め
は使わない。Java の定数名と DB の値を切り離し、リネームの自由を確保する。
3. switch 式の網羅性で「対処漏れ」をコンパイル時に検出
を書かない勇気。定数追加 → 全 switch がコンパイルエラーで教えてくれる。
@Enumerated
default
Enum を「なんとなく」使う段階を卒業して、Java の型システムを最大限に活かしましょう！
30


# Page. 31

![Page Image](https://bcdn.docswell.com/page/GEWGY1Y3J2.jpg)

ありがとうございました
名前: こうの
所属: 虎の穴ラボ テックリード
Twitter: @hk_it7
31


# Page. 32

![Page Image](https://bcdn.docswell.com/page/47ZLXPXGJ3.jpg)

サンプルコード &amp; リンク
サンプルコード
Twitter 実況補助ツール
https://github.com/h-kono-it/jjug_ccc_2026_spring-enum
https://h-kono-it.github.io/conference-tweet-helper/
32


# Page. 33

![Page Image](https://bcdn.docswell.com/page/YJ6W4M4QJV.jpg)

付録：用語集
当日は口頭で補足した用語のまとめ
33


# Page. 34

![Page Image](https://bcdn.docswell.com/page/GJ5MQZQ2J4.jpg)

用語集（言語仕様・機能）
メソッドシグネチャ — メソッドの「名前・引数の型」の組み合わせ。戻り値の型はシグネチャ
に含まれない（JLS の定義）。
のような宣言部
分のこと。
JLS（Java Language Specification） — Java の言語仕様を定めた公式文書。Enum の動
作もここで規定されている。
switch 式（switch expression） — Java 14 で導入。 構文で値を返せる。switch 文
（statement）は値を返さず、
が必要だった。
Sealed Class / Interface — Java 17 で導入。
で実装・継承できるクラスを明示的
に制限できる。Java 21 以降のパターンマッチングと組み合わせると網羅性チェックが効く。
網羅性チェック（Exhaustiveness Check） — switch 式で全ケースが処理されているかをコ
ンパイラが検証する仕組み。Enum・Sealed Class で有効になる。
List&lt;Order&gt; findByStatus(OrderStatus status)
-&gt;
break
permits
34


# Page. 35

![Page Image](https://bcdn.docswell.com/page/LE3WV9V1E5.jpg)

用語集（設計パターン・ORM）
シングルトン（Singleton） — JVM 内にインスタンスが1つだけ存在することを保証するパタ
ーン。Enum の各定数はすべてシングルトン。
Strategy パターン — 処理のアルゴリズムを切り替え可能にするデザインパターン。Enum の
抽象メソッドや Lambda フィールドで実現できる。
ポリモーフィズム（Polymorphism） — 同じ型・インターフェースで異なる振る舞いを実現す
る OOP の概念。Enum の抽象メソッドや interface 実装で活用できる。
AttributeConverter — JPA（Spring Data JPA / Hibernate）で型変換を定義するインター
フェース。Enum DB カラムの変換に使う。
TypeHandler — MyBatis で型変換を定義する仕組み。JPA の AttributeConverter に相当す
る役割。
35


