SlideShare a Scribd company logo
1 of 22
Effective Java 輪読会
Item 32-34
開発部 陳映融 2014/2/5
第6章 enumとアノテーション
項目30 int 定数の代わりに enum を使用する
項目31 序数の代わりにインスタンスフィールドを使用する





項目32 ビットフィールドの代わりに EnumSet を使用する
項目33 序数インデックスの代わりに EnumMap を使用する
項目34 拡張可能な enum をインタフェースで模倣する






項目35 命名パターンよりアノテーションを選ぶ
項目36 常に Override アノテーションを使用する
項目37 型を定義するためにマーカーインタフェースを使用する






2
Item 32
ビットフィールドの代わりに EnumSet を使用する
集合での列挙型の要素の使用
例えば、文字のスタイルを表現する時



従来の方法だと int enum パターンを使用



// ビットフィールド列挙定数 - 廃れている!
public class Text {
public static final int STYLE_BOLD
public static final int STYLE_ITALIC
public static final int STYLE_UNDERLINE
public static final int STYLE_STRIKETHROUGH

=
=
=
=

1
1
1
1

<<
<<
<<
<<

0;
1;
2;
3;

//
//
//
//

1
2
4
8

// パラメータは、0 個以上の STYLE_ 定数のビット
public void applyStyles(int styles) { ... }
}

今頃の Java では EnumSet を使用するべき



// EnumSet - ビットフィールドの最新の置換
public class Text {
public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }
// どんな Set でも渡せるが、 EnumSet が明らかに最善
public void applyStyles(Set<Style> styles) { ... }
}

4
従来の方法の場合
int enum パターン使用





ビット演算で集合操作を効率よく行うことができる
text.applyStyles(STYLE_BOLD | STYLE_ITALIC);




共通集合(要素存在確認): A & B





和集合(要素追加): A | B
要素削除: A & (~B)

要素数が多くなると、数値の解釈が困難


例えば最大 26 個の要素を持つ集合を定義すると

public static final int ELEM_A = 1 << 0;
// 1
public static final int ELEM_B = 1 << 1;
// 2
...
public static final int ELEM_Z = 1 << 25; // 2^25 = 33554432 (!)
...
private int elemSet = 0;
...
System.out.println(Integer.toBinaryString(elemSet)); // こんなの出されても分からないよ...>_<

5
従来の方法の場合
int enum パターン使用(続き)





型安全ではない
// 枠線設定用定数
public static final int UPPER_BORDER
= 1 << 4; // 16
...
text.applyStyles(STYLE_BOLD | UPPER_BORDER); // 関係のない枠線定数を入れても文句を言ってくれない...



集合内の要素をイテレートするのは大変
// 定数に対応する情報も自前で管理しなければいけない
private static final String STYLE_NAME[] =
{ "BOLD", "ITALIC", "UNDERLINE", "STRIKETHROUGHT" };
...
// 要素をイテレートして、対応するスタイル名を出力
for (int offset = 0; offset < 4; offset++) {
if ((this.styles & 1 << offset) != 0) {
System.out.printf(“%s ”, STYLE_NAME[offset]);
}
}



6

要素数が int や long 型のビット数を超えるとさらに大変…
新しい方法の場合
EnumSet 使用







型安全、可読性向上
要素数が 64 個以下なら、一つの long で表現される
class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
/**
* Bit vector representation of this set. The 2^k bit indicates the
* presence of universe[k] in this set.
*/
private long elements = 0L;





集合操作はビット演算で実装される

要素数が 65 を超えた場合、 long の配列で表現される
class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {
/**
* Bit vector representation of this set. The ith bit of the jth
* element of this array represents the presence of universe[64*j +i]
* in this set.
*/
private long elements[];



7

要素数が多くても重労働にならない
まとめ


列挙型が集合内で使用されるだけでは、ビットフィールドで表現する理由
にならない



EnumSet はビットフィールドの簡潔性とパフォーマンスと、enum 型の多く
の利点を持っている


項目30 「int 定数の代わりに enum を使用する」 を参照

EnumSet の短所は、不変な EnumSet を生成できない





8

Java7 でも Collections.unmodifiableSet でラップすることになる
Item 33
序数インデックスの代わりに EnumMap を使用する
序数で配列インデックス?(1)


料理のハーブを表すクラス Herb
public class Herb {
public enum Type { ANNUAL, PERENNIAL, BIENNIAL }
private final String name;
private final Type type;
...
}
...
Herb[] garden = ...;



// 庭園にあるハーブ

庭園内の植物で、種類ごとのハーブのセットを作りたい


10

ならば、種類をハーブのセットのインデックスにすればいいじゃない?
実際作ってみる…


セットの配列と ordinal() を使用したインデックスで作ると
// 配列をインデックスするのに ordinal() を使用 – これはやってはいけない!
Set<Herb>[] herbsByType = // Type.ordinal() でインデックスされる
(Set<Herb>[]) new Set[Type.values().length]; // 配列はジェネリックスと互換性がない、警告が出る
for (int i = 0; i < herbsByType.length; i++)
herbsByType[i] = new HashSet<>();
// 配列アクセス時に正しいインデックス値を入れないと ArrayIndexOutOfBoundException をスローしてしまう
for (Herb h : garden)
herbsByType[h.type().ordinal()].add(h);



enum をキーにして EnumMap で作ると
// データを enum と関連付けるために EnumMap を使用
EnumMap<Type, Set<Herb>> herbsByType =
new EnumMap<>(Type.class); // 実行時ジェネリック型情報はキー型の Class オブジェクトで提供
for (Type t : Type.values())
herbsByType.put(t, new HashSet<Herb>());
for (Herb h : garden)
herbsByType.get(h.type()).add(h);

11

// インデックスの境界に気にする必要ないほか、キーの型チェックもある
序数で配列インデックス?(2)


物質の相を表す enum 型クラス Phase
// 配列の配列をインデックスするのに ordinal() を使用 – これはやってはいけない
public enum Phase {
SOLID, LIQUID, GAS;
public enum Transition {
MELT, FREEZE, BOIL, CONDENSE, SUBLIME, DEPOSIT;
// src の序数で行が、dst の序数で列がインデックスされる
private static final Transition[][] TRANSITIONS = { // 転移表に誤りがあると大変!
{null,
MELT,
SUBLIME},
// 間違えると、 ArrayIndexOutOfBoundException や
{FREEZE, null,
BOIL},
// NullPointerException が出るかもしれないし、
{DEPOSIT, CONDENSE, null}
// 何も出ないでそのまま見逃してしまうかもしれない (!!)
};
public static Transition from(Phase src, Phase dst) {
return TRANSITIONS[src.ordinal()][dst.ordinal()];
}

}
}



洗練されているように見えるが…
遷移表の検証が困難、項目の追加・削除でバグを織り込みやすい
⇒ 配列で実装される「状態転移表」のメンテナンス性は総じて低い


12
EnumMap で作ってみる
public enum Phase {
SOLID, LIQUID, GAS;
public enum Transition {
// 相転移の転移元と転移先の相を定数固有データとして定義
MELT(SOLID,LIQUID), FREEZE(LIQUID,SOLID),
BOIL(LIQUID,GAS),
CONDENSE(GAS,LIQUID),
SUBLIME(SOLID,GAS), DEPOSIT(GAS,SOLID);
private final Phase src;
private final Phase dst;
Transition(Phase src, Phase dst) {
this.src = src;
this.dst = dst;
}
// 相転移マップを初期化
private static final Map<Phase, Map<Phase, Transition>> m = new EnumMap<>(Phase.class);
static {
for (Phase p : Phase.values())
m.put(p, new EnumMap<Phase, Transition>(Phase.class));
for (Transition t : Transition.values())
m.get(t.src).put(t.dst, t);
}
public static Transition from(Phase src, Phase dst) {
return m.get(src).get(dst);
}

}
}

13
enum 値を追加する場合の比較





相: PLASMA 追加
相転移: IONIZE(GASPLASMA), DEIONIZE(PLASMAGAS) 追加
配列インデックスに ordinal() 使用時
public enum Transition {
MELT, FREEZE, BOIL, CONDENSE, SUBLIME, DEPOSIT, IONIZE, DEIONIZE;
private static final Transition[][] TRANSITIONS = {
{null,
MELT,
SUBLIME, null},
{FREEZE, null,
BOIL,
null},
{DEPOSIT, CONDENSE, null,
IONIZE},
{null,
null,
DEIONIZE, null}
}; // 実際の修正場所 PLASMA の序数に依存、間違えると今までの動作もおかしくなる
...
}



EnumMap 使用時
public enum Transition {
MELT(SOLID,LIQUID), FREEZE(LIQUID,SOLID),
BOIL(LIQUID,GAS),
CONDENSE(GAS,LIQUID),
SUBLIME(SOLID,GAS), DEPOSIT(GAS,SOLID),
IONIZE(GAS,PLASMA), DEIONIZE(PLASMA,GAS);
...
}

14

// それぞれの値の情報が独立して、干渉し合わない
// この一行追加で十分
まとめ


配列をインデックスするために序数を使用することが適切であることは
めったにない



代わりに EnumMap を使用する



多次元の関係を表示する場合は EnumMap<...,EnumMap<...>> を使
用する

15
Item 34
拡張可能な enum をインタフェースで模倣する
enum 型の拡張性について


ほとんど場合は、enum 型の拡張性は間違った考え


もし拡張できたとすると


拡張された型の要素が基底型の要素であり



基底型の要素は拡張された型の要素ではない

⇒ 混乱を生じることに


拡張可能な列挙型を使う場面




オペレーションコード
何らかの操作を表す要素を持つ列挙型
API が提供する操作の集合の拡張

⇒ enum が任意のインタフェースを実装できる事実を利用して達成する

17
項目30 の Operation 型の場合


定数固有メソッド実装を持つ enum 型
public enum Operation {
PLUS("+")
{ public
MINUS("-") { public
TIMES("*") { public
DEVIDE("/") { public

double
double
double
double

apply(double
apply(double
apply(double
apply(double

x,
x,
x,
x,

double
double
double
double

y)
y)
y)
y)

{
{
{
{

return
return
return
return

x
x
x
x

+
*
/

y;
y;
y;
y;

}
}
}
}

},
},
},
};

private final String symbol;
Operation(String symbol) { this.symbol = symbol; }
@Override public String toString() { return symbol; }
abstract double apply(double x, double y);

// 模倣するためにインタフェースとして抽出

}



操作を模倣するために抽出されたインタフェース定義
public interface Operation {
double apply(double x, double y);
}

18
enum 型によるインタフェース実装


基本 enum 型
public enum BasicOperation implements Operation
PLUS("+")
{ public double apply(double x,
MINUS("-") { public double apply(double x,
TIMES("*") { public double apply(double x,
DEVIDE("/") { public double apply(double x,

{
double
double
double
double

y)
y)
y)
y)

{
{
{
{

return
return
return
return

x
x
x
x

+
*
/

y;
y;
y;
y;

}
}
}
}

},
},
},
};

private final String symbol;
BasicOperation(String symbol) { this.symbol = symbol; }
@Override public String toString() { return symbol; }
}



模倣された拡張 enum 型
public enum ExtendedOperation implements Operation {
EXP("^")
{ public double apply(double x, double y) { return Math.pow(x, y); } },
REMAINDER("%") { public double apply(double x, double y) { return x % y; } };
private final String symbol;
ExtendedOperation(String symbol) { this.symbol = symbol; }
@Override public String toString() { return symbol; }
}

19
拡張 enum 型の使用


インタフェースが期待された場所、拡張 enum 型も使用可能


境界型トークン使用(項目29)
private static <T extends Enum<T> & Operation> void test(Class<T> opSet, double x, double y) {
for (T op : opSet.getEnumConstants())
System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));
}





パラメータ opSet の宣言は、その Class オブジェクトが enum でかつ
Operation のサブタイプであることを保証

境界ワイルドカード型使用(項目28)
private static void test(Collection<? extends Operation> opSet, double x, double y) {
for (Operation op : opSet)
System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));
}



この場合、パラメータ opSet の要素は Operation のサブタイプであることが要求
されるが、要素が enum でなくてもよい



その代わり、操作の実装に EnumSet と EnumMap は使用できない

⇒ 複数の実装型を組み合わせる必要がなければ、境界型トークンが良さそう
20
インタフェースで模倣する手法の欠点


一つの enum 型が他の enum 型から実装を継承できない


Operation 型の場合は操作に関連付けられた記号の保存と取り出しのロジック
が重複
public enum BasicOperation implements Operation {
...
private final String symbol;
BasicOperation(String symbol) { this.symbol = symbol; }
@Override public String toString() { return symbol; }
}
public enum ExtendedOperation implements Operation {
...
private final String symbol;
ExtendedOperation(String symbol) { this.symbol = symbol; }
@Override public String toString() { return symbol; }
}



21

// 実装を継承できないのでコードが重複
// 実装を継承できないのでコードが重複

重複するコード量が大きい場合、ヘルパークラスや static なヘルパーメソッドで
カプセル化できる
まとめ


拡張可能な enum 型を書くことできないが



基本の enum 型に伴うインタフェースを書いて、そのインタフェースをそ
の基本の enum 型に実装させることで模倣できる



クライアントがそのインタフェースを実装して独自の enum を作れる



API がインタフェースで書かれたとしたら、基本の enum 型を使用する
場所でもそれらの enum 型を使用できる

22

More Related Content

What's hot

OpenFOAM+のCo-simulation機能とFMUの試作
OpenFOAM+のCo-simulation機能とFMUの試作OpenFOAM+のCo-simulation機能とFMUの試作
OpenFOAM+のCo-simulation機能とFMUの試作Amane Tanaka
 
Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料時響 逢坂
 
マスターオブゴールーチンアンドチャネル スタートGo #1
マスターオブゴールーチンアンドチャネル   スタートGo #1マスターオブゴールーチンアンドチャネル   スタートGo #1
マスターオブゴールーチンアンドチャネル スタートGo #1Takuya Ueda
 
C++によるソート入門
C++によるソート入門C++によるソート入門
C++によるソート入門AimingStudy
 
Processingによるプログラミング入門 第2回
Processingによるプログラミング入門 第2回Processingによるプログラミング入門 第2回
Processingによるプログラミング入門 第2回Ryo Suzuki
 
Processingによるプログラミング入門 第4回
Processingによるプログラミング入門 第4回Processingによるプログラミング入門 第4回
Processingによるプログラミング入門 第4回Ryo Suzuki
 
About chtMultiRegionFoam
About chtMultiRegionFoam About chtMultiRegionFoam
About chtMultiRegionFoam 守淑 田村
 
C++でHello worldを書いてみた
C++でHello worldを書いてみたC++でHello worldを書いてみた
C++でHello worldを書いてみたfirewood
 
すごいH 第12章モノイド
すごいH 第12章モノイドすごいH 第12章モノイド
すごいH 第12章モノイドShinta Hatatani
 
モナドがいっぱい!
モナドがいっぱい!モナドがいっぱい!
モナドがいっぱい!Kenta Sato
 
Van laarhoven lens
Van laarhoven lensVan laarhoven lens
Van laarhoven lensNaoki Aoyama
 
F#とC#で見る関数志向プログラミング
F#とC#で見る関数志向プログラミングF#とC#で見る関数志向プログラミング
F#とC#で見る関数志向プログラミングsatoshimurakumo
 
Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本Kota Mizushima
 
SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介MITSUNARI Shigeo
 
エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7Tetsuya Morimoto
 

What's hot (18)

OpenFOAM+のCo-simulation機能とFMUの試作
OpenFOAM+のCo-simulation機能とFMUの試作OpenFOAM+のCo-simulation機能とFMUの試作
OpenFOAM+のCo-simulation機能とFMUの試作
 
Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料
 
マスターオブゴールーチンアンドチャネル スタートGo #1
マスターオブゴールーチンアンドチャネル   スタートGo #1マスターオブゴールーチンアンドチャネル   スタートGo #1
マスターオブゴールーチンアンドチャネル スタートGo #1
 
C++によるソート入門
C++によるソート入門C++によるソート入門
C++によるソート入門
 
Processingによるプログラミング入門 第2回
Processingによるプログラミング入門 第2回Processingによるプログラミング入門 第2回
Processingによるプログラミング入門 第2回
 
Processingによるプログラミング入門 第4回
Processingによるプログラミング入門 第4回Processingによるプログラミング入門 第4回
Processingによるプログラミング入門 第4回
 
About chtMultiRegionFoam
About chtMultiRegionFoam About chtMultiRegionFoam
About chtMultiRegionFoam
 
C++でHello worldを書いてみた
C++でHello worldを書いてみたC++でHello worldを書いてみた
C++でHello worldを書いてみた
 
すごいH 第12章モノイド
すごいH 第12章モノイドすごいH 第12章モノイド
すごいH 第12章モノイド
 
モナドがいっぱい!
モナドがいっぱい!モナドがいっぱい!
モナドがいっぱい!
 
Van laarhoven lens
Van laarhoven lensVan laarhoven lens
Van laarhoven lens
 
F#とC#で見る関数志向プログラミング
F#とC#で見る関数志向プログラミングF#とC#で見る関数志向プログラミング
F#とC#で見る関数志向プログラミング
 
Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本
 
SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介
 
エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7
 
Bluespec @waseda(PDF)
Bluespec @waseda(PDF)Bluespec @waseda(PDF)
Bluespec @waseda(PDF)
 
Ssaw08 1111
Ssaw08 1111Ssaw08 1111
Ssaw08 1111
 
CLR/H No.35-2
CLR/H No.35-2CLR/H No.35-2
CLR/H No.35-2
 

Similar to Effective java 輪読会 第6章 項目32-34

Node.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラーNode.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラーmganeko
 
OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-
OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-
OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-Fumiya Nozaki
 
constexpr idioms
constexpr idiomsconstexpr idioms
constexpr idiomsfimbul
 
SMCTC ライブラリの使用方法
SMCTC ライブラリの使用方法SMCTC ライブラリの使用方法
SMCTC ライブラリの使用方法Satoshi Minakuchi
 
Effective java 勉強会
Effective java 勉強会Effective java 勉強会
Effective java 勉強会Takinami Kei
 
Template method #dezapatan
Template method #dezapatanTemplate method #dezapatan
Template method #dezapatankuidaoring
 
Implementation patterns
Implementation patternsImplementation patterns
Implementation patternsTatsuya Maki
 
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-Kazunari Hara
 
Java Puzzlers JJUG CCC 2016
Java Puzzlers JJUG CCC 2016Java Puzzlers JJUG CCC 2016
Java Puzzlers JJUG CCC 2016Yoshio Terada
 
PostgreSQL - C言語によるユーザ定義関数の作り方
PostgreSQL - C言語によるユーザ定義関数の作り方PostgreSQL - C言語によるユーザ定義関数の作り方
PostgreSQL - C言語によるユーザ定義関数の作り方Satoshi Nagayasu
 
Swift 3.0 の新機能 - 追加・変更まわりだけ、ざっくり紹介 2 #devsap
Swift 3.0 の新機能 - 追加・変更まわりだけ、ざっくり紹介 2 #devsapSwift 3.0 の新機能 - 追加・変更まわりだけ、ざっくり紹介 2 #devsap
Swift 3.0 の新機能 - 追加・変更まわりだけ、ざっくり紹介 2 #devsapTomohiro Kumagai
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 TipsTakaaki Suzuki
 
60分で体験する Stream / Lambda
 ハンズオン
60分で体験する Stream / Lambda
 ハンズオン60分で体験する Stream / Lambda
 ハンズオン
60分で体験する Stream / Lambda
 ハンズオンHiroto Yamakawa
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)啓 小笠原
 
Replace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JPReplace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JPAkira Takahashi
 
ji-5. 繰り返し計算
ji-5. 繰り返し計算ji-5. 繰り返し計算
ji-5. 繰り返し計算kunihikokaneko1
 
Java8 Lambda chapter5
Java8 Lambda chapter5Java8 Lambda chapter5
Java8 Lambda chapter5Takinami Kei
 

Similar to Effective java 輪読会 第6章 項目32-34 (20)

Node.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラーNode.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
 
OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-
OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-
OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-
 
Enshu8
Enshu8Enshu8
Enshu8
 
constexpr idioms
constexpr idiomsconstexpr idioms
constexpr idioms
 
Sml#探検隊
Sml#探検隊Sml#探検隊
Sml#探検隊
 
SMCTC ライブラリの使用方法
SMCTC ライブラリの使用方法SMCTC ライブラリの使用方法
SMCTC ライブラリの使用方法
 
Effective java 勉強会
Effective java 勉強会Effective java 勉強会
Effective java 勉強会
 
Template method #dezapatan
Template method #dezapatanTemplate method #dezapatan
Template method #dezapatan
 
Implementation patterns
Implementation patternsImplementation patterns
Implementation patterns
 
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-
 
Java Puzzlers JJUG CCC 2016
Java Puzzlers JJUG CCC 2016Java Puzzlers JJUG CCC 2016
Java Puzzlers JJUG CCC 2016
 
Boost Fusion Library
Boost Fusion LibraryBoost Fusion Library
Boost Fusion Library
 
PostgreSQL - C言語によるユーザ定義関数の作り方
PostgreSQL - C言語によるユーザ定義関数の作り方PostgreSQL - C言語によるユーザ定義関数の作り方
PostgreSQL - C言語によるユーザ定義関数の作り方
 
Swift 3.0 の新機能 - 追加・変更まわりだけ、ざっくり紹介 2 #devsap
Swift 3.0 の新機能 - 追加・変更まわりだけ、ざっくり紹介 2 #devsapSwift 3.0 の新機能 - 追加・変更まわりだけ、ざっくり紹介 2 #devsap
Swift 3.0 の新機能 - 追加・変更まわりだけ、ざっくり紹介 2 #devsap
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips
 
60分で体験する Stream / Lambda
 ハンズオン
60分で体験する Stream / Lambda
 ハンズオン60分で体験する Stream / Lambda
 ハンズオン
60分で体験する Stream / Lambda
 ハンズオン
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)
 
Replace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JPReplace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JP
 
ji-5. 繰り返し計算
ji-5. 繰り返し計算ji-5. 繰り返し計算
ji-5. 繰り返し計算
 
Java8 Lambda chapter5
Java8 Lambda chapter5Java8 Lambda chapter5
Java8 Lambda chapter5
 

More from Appresso Engineering Team

マルチスレッド デザインパターン ― Single Threaded Execution
マルチスレッド デザインパターン ― Single Threaded Executionマルチスレッド デザインパターン ― Single Threaded Execution
マルチスレッド デザインパターン ― Single Threaded ExecutionAppresso Engineering Team
 
JavaScript 勉強会 ― 変数・演算子・文
JavaScript 勉強会 ― 変数・演算子・文JavaScript 勉強会 ― 変数・演算子・文
JavaScript 勉強会 ― 変数・演算子・文Appresso Engineering Team
 
Effective Java 輪読会 第7章 項目43-44
Effective Java 輪読会 第7章 項目43-44Effective Java 輪読会 第7章 項目43-44
Effective Java 輪読会 第7章 項目43-44Appresso Engineering Team
 
Effective Java 輪読会 第7章 項目41-42
Effective Java 輪読会 第7章 項目41-42Effective Java 輪読会 第7章 項目41-42
Effective Java 輪読会 第7章 項目41-42Appresso Engineering Team
 
Effective Java 輪読会 第7章 項目38-40
Effective Java 輪読会 第7章 項目38-40Effective Java 輪読会 第7章 項目38-40
Effective Java 輪読会 第7章 項目38-40Appresso Engineering Team
 

More from Appresso Engineering Team (20)

20150302 java8 第一回_ラムダ式(1)
20150302 java8 第一回_ラムダ式(1)20150302 java8 第一回_ラムダ式(1)
20150302 java8 第一回_ラムダ式(1)
 
Effective Java 輪読会 項目77-78
Effective Java 輪読会 項目77-78Effective Java 輪読会 項目77-78
Effective Java 輪読会 項目77-78
 
Effective Java 輪読会 項目74-75
Effective Java 輪読会 項目74-75Effective Java 輪読会 項目74-75
Effective Java 輪読会 項目74-75
 
マルチスレッド デザインパターン ― Single Threaded Execution
マルチスレッド デザインパターン ― Single Threaded Executionマルチスレッド デザインパターン ― Single Threaded Execution
マルチスレッド デザインパターン ― Single Threaded Execution
 
JavaScript 勉強会 ― 変数・演算子・文
JavaScript 勉強会 ― 変数・演算子・文JavaScript 勉強会 ― 変数・演算子・文
JavaScript 勉強会 ― 変数・演算子・文
 
JavaScript 勉強会 ― 型と値
JavaScript 勉強会 ― 型と値JavaScript 勉強会 ― 型と値
JavaScript 勉強会 ― 型と値
 
Effective Java 輪読会 項目69-70追加
Effective Java 輪読会 項目69-70追加Effective Java 輪読会 項目69-70追加
Effective Java 輪読会 項目69-70追加
 
Effective Java 輪読会 項目69-70
Effective Java 輪読会 項目69-70Effective Java 輪読会 項目69-70
Effective Java 輪読会 項目69-70
 
Effective Java 輪読会 項目66-68
Effective Java 輪読会 項目66-68Effective Java 輪読会 項目66-68
Effective Java 輪読会 項目66-68
 
Effective Java 輪読会 項目71-73
Effective Java 輪読会 項目71-73Effective Java 輪読会 項目71-73
Effective Java 輪読会 項目71-73
 
Java Day Tokyo 2014 まとめ (chen)
Java Day Tokyo 2014 まとめ (chen)Java Day Tokyo 2014 まとめ (chen)
Java Day Tokyo 2014 まとめ (chen)
 
Effective Java 輪読会 項目63-65
Effective Java 輪読会 項目63-65Effective Java 輪読会 項目63-65
Effective Java 輪読会 項目63-65
 
Effective Java 輪読会 項目60-62
Effective Java 輪読会 項目60-62Effective Java 輪読会 項目60-62
Effective Java 輪読会 項目60-62
 
Effective java 輪読会 項目57-59
Effective java 輪読会 項目57-59Effective java 輪読会 項目57-59
Effective java 輪読会 項目57-59
 
Effective Java 輪読会 項目49-52
Effective Java 輪読会 項目49-52Effective Java 輪読会 項目49-52
Effective Java 輪読会 項目49-52
 
Effective Java 輪読会 項目45-48
Effective Java 輪読会 項目45-48Effective Java 輪読会 項目45-48
Effective Java 輪読会 項目45-48
 
Effective Java 輪読会 項目53-56
Effective Java 輪読会 項目53-56Effective Java 輪読会 項目53-56
Effective Java 輪読会 項目53-56
 
Effective Java 輪読会 第7章 項目43-44
Effective Java 輪読会 第7章 項目43-44Effective Java 輪読会 第7章 項目43-44
Effective Java 輪読会 第7章 項目43-44
 
Effective Java 輪読会 第7章 項目41-42
Effective Java 輪読会 第7章 項目41-42Effective Java 輪読会 第7章 項目41-42
Effective Java 輪読会 第7章 項目41-42
 
Effective Java 輪読会 第7章 項目38-40
Effective Java 輪読会 第7章 項目38-40Effective Java 輪読会 第7章 項目38-40
Effective Java 輪読会 第7章 項目38-40
 

Recently uploaded

Hyperledger Fabricコミュニティ活動体験& Hyperledger Fabric最新状況ご紹介
Hyperledger Fabricコミュニティ活動体験& Hyperledger Fabric最新状況ご紹介Hyperledger Fabricコミュニティ活動体験& Hyperledger Fabric最新状況ご紹介
Hyperledger Fabricコミュニティ活動体験& Hyperledger Fabric最新状況ご紹介Hyperleger Tokyo Meetup
 
クラウド時代におけるSREとUPWARDの取組ーUPWARD株式会社 CTO門畑
クラウド時代におけるSREとUPWARDの取組ーUPWARD株式会社 CTO門畑クラウド時代におけるSREとUPWARDの取組ーUPWARD株式会社 CTO門畑
クラウド時代におけるSREとUPWARDの取組ーUPWARD株式会社 CTO門畑Akihiro Kadohata
 
MPAなWebフレームワーク、Astroの紹介 (その1) 2024/05/17の勉強会で発表されたものです。
MPAなWebフレームワーク、Astroの紹介 (その1) 2024/05/17の勉強会で発表されたものです。MPAなWebフレームワーク、Astroの紹介 (その1) 2024/05/17の勉強会で発表されたものです。
MPAなWebフレームワーク、Astroの紹介 (その1) 2024/05/17の勉強会で発表されたものです。iPride Co., Ltd.
 
2024年5月17日 先駆的科学計算フォーラム2024 機械学習を用いた新たなゲーム体験の創出の応用
2024年5月17日 先駆的科学計算フォーラム2024 機械学習を用いた新たなゲーム体験の創出の応用2024年5月17日 先駆的科学計算フォーラム2024 機械学習を用いた新たなゲーム体験の創出の応用
2024年5月17日 先駆的科学計算フォーラム2024 機械学習を用いた新たなゲーム体験の創出の応用KLab Inc. / Tech
 
ネットワーク可視化 振る舞い検知(NDR)ご紹介_キンドリル202405.pdf
ネットワーク可視化 振る舞い検知(NDR)ご紹介_キンドリル202405.pdfネットワーク可視化 振る舞い検知(NDR)ご紹介_キンドリル202405.pdf
ネットワーク可視化 振る舞い検知(NDR)ご紹介_キンドリル202405.pdfTakayuki Nakayama
 
部内勉強会(IT用語ざっくり学習) 実施日:2024年5月17日(金) 対象者:営業部社員
部内勉強会(IT用語ざっくり学習) 実施日:2024年5月17日(金) 対象者:営業部社員部内勉強会(IT用語ざっくり学習) 実施日:2024年5月17日(金) 対象者:営業部社員
部内勉強会(IT用語ざっくり学習) 実施日:2024年5月17日(金) 対象者:営業部社員Sadaomi Nishi
 
Keywordmap overview material/CINC.co.ltd
Keywordmap overview material/CINC.co.ltdKeywordmap overview material/CINC.co.ltd
Keywordmap overview material/CINC.co.ltdkokinagano2
 
論文紹介:ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation
論文紹介:ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation論文紹介:ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation
論文紹介:ViTPose: Simple Vision Transformer Baselines for Human Pose EstimationToru Tamaki
 
Intranet Development v1.0 (TSG LIVE! 12 LT )
Intranet Development v1.0 (TSG LIVE! 12 LT )Intranet Development v1.0 (TSG LIVE! 12 LT )
Intranet Development v1.0 (TSG LIVE! 12 LT )iwashiira2ctf
 
ロボットマニピュレーションの作業・動作計画 / rosjp_planning_for_robotic_manipulation_20240521
ロボットマニピュレーションの作業・動作計画 / rosjp_planning_for_robotic_manipulation_20240521ロボットマニピュレーションの作業・動作計画 / rosjp_planning_for_robotic_manipulation_20240521
ロボットマニピュレーションの作業・動作計画 / rosjp_planning_for_robotic_manipulation_20240521Satoshi Makita
 
研究紹介スライド: オフライン強化学習に基づくロボティックスワームの制御器の設計
研究紹介スライド: オフライン強化学習に基づくロボティックスワームの制御器の設計研究紹介スライド: オフライン強化学習に基づくロボティックスワームの制御器の設計
研究紹介スライド: オフライン強化学習に基づくロボティックスワームの制御器の設計atsushi061452
 
20240523_IoTLT_vol111_kitazaki_v1___.pdf
20240523_IoTLT_vol111_kitazaki_v1___.pdf20240523_IoTLT_vol111_kitazaki_v1___.pdf
20240523_IoTLT_vol111_kitazaki_v1___.pdfAyachika Kitazaki
 
Amazon Cognitoで実装するパスキー (Security-JAWS【第33回】 勉強会)
Amazon Cognitoで実装するパスキー (Security-JAWS【第33回】 勉強会)Amazon Cognitoで実装するパスキー (Security-JAWS【第33回】 勉強会)
Amazon Cognitoで実装するパスキー (Security-JAWS【第33回】 勉強会)keikoitakurag
 
情報を表現するときのポイント
情報を表現するときのポイント情報を表現するときのポイント
情報を表現するときのポイントonozaty
 
5/22 第23回 Customer系エンジニア座談会のスライド 公開用 西口瑛一
5/22 第23回 Customer系エンジニア座談会のスライド 公開用 西口瑛一5/22 第23回 Customer系エンジニア座談会のスライド 公開用 西口瑛一
5/22 第23回 Customer系エンジニア座談会のスライド 公開用 西口瑛一瑛一 西口
 
LoRaWAN無位置ロープ型水漏れセンサー WL03A-LB/LSカタログ ファイル
LoRaWAN無位置ロープ型水漏れセンサー WL03A-LB/LSカタログ ファイルLoRaWAN無位置ロープ型水漏れセンサー WL03A-LB/LSカタログ ファイル
LoRaWAN無位置ロープ型水漏れセンサー WL03A-LB/LSカタログ ファイルCRI Japan, Inc.
 

Recently uploaded (16)

Hyperledger Fabricコミュニティ活動体験& Hyperledger Fabric最新状況ご紹介
Hyperledger Fabricコミュニティ活動体験& Hyperledger Fabric最新状況ご紹介Hyperledger Fabricコミュニティ活動体験& Hyperledger Fabric最新状況ご紹介
Hyperledger Fabricコミュニティ活動体験& Hyperledger Fabric最新状況ご紹介
 
クラウド時代におけるSREとUPWARDの取組ーUPWARD株式会社 CTO門畑
クラウド時代におけるSREとUPWARDの取組ーUPWARD株式会社 CTO門畑クラウド時代におけるSREとUPWARDの取組ーUPWARD株式会社 CTO門畑
クラウド時代におけるSREとUPWARDの取組ーUPWARD株式会社 CTO門畑
 
MPAなWebフレームワーク、Astroの紹介 (その1) 2024/05/17の勉強会で発表されたものです。
MPAなWebフレームワーク、Astroの紹介 (その1) 2024/05/17の勉強会で発表されたものです。MPAなWebフレームワーク、Astroの紹介 (その1) 2024/05/17の勉強会で発表されたものです。
MPAなWebフレームワーク、Astroの紹介 (その1) 2024/05/17の勉強会で発表されたものです。
 
2024年5月17日 先駆的科学計算フォーラム2024 機械学習を用いた新たなゲーム体験の創出の応用
2024年5月17日 先駆的科学計算フォーラム2024 機械学習を用いた新たなゲーム体験の創出の応用2024年5月17日 先駆的科学計算フォーラム2024 機械学習を用いた新たなゲーム体験の創出の応用
2024年5月17日 先駆的科学計算フォーラム2024 機械学習を用いた新たなゲーム体験の創出の応用
 
ネットワーク可視化 振る舞い検知(NDR)ご紹介_キンドリル202405.pdf
ネットワーク可視化 振る舞い検知(NDR)ご紹介_キンドリル202405.pdfネットワーク可視化 振る舞い検知(NDR)ご紹介_キンドリル202405.pdf
ネットワーク可視化 振る舞い検知(NDR)ご紹介_キンドリル202405.pdf
 
部内勉強会(IT用語ざっくり学習) 実施日:2024年5月17日(金) 対象者:営業部社員
部内勉強会(IT用語ざっくり学習) 実施日:2024年5月17日(金) 対象者:営業部社員部内勉強会(IT用語ざっくり学習) 実施日:2024年5月17日(金) 対象者:営業部社員
部内勉強会(IT用語ざっくり学習) 実施日:2024年5月17日(金) 対象者:営業部社員
 
Keywordmap overview material/CINC.co.ltd
Keywordmap overview material/CINC.co.ltdKeywordmap overview material/CINC.co.ltd
Keywordmap overview material/CINC.co.ltd
 
論文紹介:ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation
論文紹介:ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation論文紹介:ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation
論文紹介:ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation
 
Intranet Development v1.0 (TSG LIVE! 12 LT )
Intranet Development v1.0 (TSG LIVE! 12 LT )Intranet Development v1.0 (TSG LIVE! 12 LT )
Intranet Development v1.0 (TSG LIVE! 12 LT )
 
ロボットマニピュレーションの作業・動作計画 / rosjp_planning_for_robotic_manipulation_20240521
ロボットマニピュレーションの作業・動作計画 / rosjp_planning_for_robotic_manipulation_20240521ロボットマニピュレーションの作業・動作計画 / rosjp_planning_for_robotic_manipulation_20240521
ロボットマニピュレーションの作業・動作計画 / rosjp_planning_for_robotic_manipulation_20240521
 
研究紹介スライド: オフライン強化学習に基づくロボティックスワームの制御器の設計
研究紹介スライド: オフライン強化学習に基づくロボティックスワームの制御器の設計研究紹介スライド: オフライン強化学習に基づくロボティックスワームの制御器の設計
研究紹介スライド: オフライン強化学習に基づくロボティックスワームの制御器の設計
 
20240523_IoTLT_vol111_kitazaki_v1___.pdf
20240523_IoTLT_vol111_kitazaki_v1___.pdf20240523_IoTLT_vol111_kitazaki_v1___.pdf
20240523_IoTLT_vol111_kitazaki_v1___.pdf
 
Amazon Cognitoで実装するパスキー (Security-JAWS【第33回】 勉強会)
Amazon Cognitoで実装するパスキー (Security-JAWS【第33回】 勉強会)Amazon Cognitoで実装するパスキー (Security-JAWS【第33回】 勉強会)
Amazon Cognitoで実装するパスキー (Security-JAWS【第33回】 勉強会)
 
情報を表現するときのポイント
情報を表現するときのポイント情報を表現するときのポイント
情報を表現するときのポイント
 
5/22 第23回 Customer系エンジニア座談会のスライド 公開用 西口瑛一
5/22 第23回 Customer系エンジニア座談会のスライド 公開用 西口瑛一5/22 第23回 Customer系エンジニア座談会のスライド 公開用 西口瑛一
5/22 第23回 Customer系エンジニア座談会のスライド 公開用 西口瑛一
 
LoRaWAN無位置ロープ型水漏れセンサー WL03A-LB/LSカタログ ファイル
LoRaWAN無位置ロープ型水漏れセンサー WL03A-LB/LSカタログ ファイルLoRaWAN無位置ロープ型水漏れセンサー WL03A-LB/LSカタログ ファイル
LoRaWAN無位置ロープ型水漏れセンサー WL03A-LB/LSカタログ ファイル
 

Effective java 輪読会 第6章 項目32-34

  • 1. Effective Java 輪読会 Item 32-34 開発部 陳映融 2014/2/5
  • 2. 第6章 enumとアノテーション 項目30 int 定数の代わりに enum を使用する 項目31 序数の代わりにインスタンスフィールドを使用する   項目32 ビットフィールドの代わりに EnumSet を使用する 項目33 序数インデックスの代わりに EnumMap を使用する 項目34 拡張可能な enum をインタフェースで模倣する    項目35 命名パターンよりアノテーションを選ぶ 項目36 常に Override アノテーションを使用する 項目37 型を定義するためにマーカーインタフェースを使用する    2
  • 4. 集合での列挙型の要素の使用 例えば、文字のスタイルを表現する時  従来の方法だと int enum パターンを使用  // ビットフィールド列挙定数 - 廃れている! public class Text { public static final int STYLE_BOLD public static final int STYLE_ITALIC public static final int STYLE_UNDERLINE public static final int STYLE_STRIKETHROUGH = = = = 1 1 1 1 << << << << 0; 1; 2; 3; // // // // 1 2 4 8 // パラメータは、0 個以上の STYLE_ 定数のビット public void applyStyles(int styles) { ... } } 今頃の Java では EnumSet を使用するべき  // EnumSet - ビットフィールドの最新の置換 public class Text { public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH } // どんな Set でも渡せるが、 EnumSet が明らかに最善 public void applyStyles(Set<Style> styles) { ... } } 4
  • 5. 従来の方法の場合 int enum パターン使用   ビット演算で集合操作を効率よく行うことができる text.applyStyles(STYLE_BOLD | STYLE_ITALIC);   共通集合(要素存在確認): A & B   和集合(要素追加): A | B 要素削除: A & (~B) 要素数が多くなると、数値の解釈が困難  例えば最大 26 個の要素を持つ集合を定義すると public static final int ELEM_A = 1 << 0; // 1 public static final int ELEM_B = 1 << 1; // 2 ... public static final int ELEM_Z = 1 << 25; // 2^25 = 33554432 (!) ... private int elemSet = 0; ... System.out.println(Integer.toBinaryString(elemSet)); // こんなの出されても分からないよ...>_< 5
  • 6. 従来の方法の場合 int enum パターン使用(続き)   型安全ではない // 枠線設定用定数 public static final int UPPER_BORDER = 1 << 4; // 16 ... text.applyStyles(STYLE_BOLD | UPPER_BORDER); // 関係のない枠線定数を入れても文句を言ってくれない...  集合内の要素をイテレートするのは大変 // 定数に対応する情報も自前で管理しなければいけない private static final String STYLE_NAME[] = { "BOLD", "ITALIC", "UNDERLINE", "STRIKETHROUGHT" }; ... // 要素をイテレートして、対応するスタイル名を出力 for (int offset = 0; offset < 4; offset++) { if ((this.styles & 1 << offset) != 0) { System.out.printf(“%s ”, STYLE_NAME[offset]); } }  6 要素数が int や long 型のビット数を超えるとさらに大変…
  • 7. 新しい方法の場合 EnumSet 使用    型安全、可読性向上 要素数が 64 個以下なら、一つの long で表現される class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> { /** * Bit vector representation of this set. The 2^k bit indicates the * presence of universe[k] in this set. */ private long elements = 0L;   集合操作はビット演算で実装される 要素数が 65 を超えた場合、 long の配列で表現される class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> { /** * Bit vector representation of this set. The ith bit of the jth * element of this array represents the presence of universe[64*j +i] * in this set. */ private long elements[];  7 要素数が多くても重労働にならない
  • 8. まとめ  列挙型が集合内で使用されるだけでは、ビットフィールドで表現する理由 にならない  EnumSet はビットフィールドの簡潔性とパフォーマンスと、enum 型の多く の利点を持っている  項目30 「int 定数の代わりに enum を使用する」 を参照 EnumSet の短所は、不変な EnumSet を生成できない   8 Java7 でも Collections.unmodifiableSet でラップすることになる
  • 10. 序数で配列インデックス?(1)  料理のハーブを表すクラス Herb public class Herb { public enum Type { ANNUAL, PERENNIAL, BIENNIAL } private final String name; private final Type type; ... } ... Herb[] garden = ...;  // 庭園にあるハーブ 庭園内の植物で、種類ごとのハーブのセットを作りたい  10 ならば、種類をハーブのセットのインデックスにすればいいじゃない?
  • 11. 実際作ってみる…  セットの配列と ordinal() を使用したインデックスで作ると // 配列をインデックスするのに ordinal() を使用 – これはやってはいけない! Set<Herb>[] herbsByType = // Type.ordinal() でインデックスされる (Set<Herb>[]) new Set[Type.values().length]; // 配列はジェネリックスと互換性がない、警告が出る for (int i = 0; i < herbsByType.length; i++) herbsByType[i] = new HashSet<>(); // 配列アクセス時に正しいインデックス値を入れないと ArrayIndexOutOfBoundException をスローしてしまう for (Herb h : garden) herbsByType[h.type().ordinal()].add(h);  enum をキーにして EnumMap で作ると // データを enum と関連付けるために EnumMap を使用 EnumMap<Type, Set<Herb>> herbsByType = new EnumMap<>(Type.class); // 実行時ジェネリック型情報はキー型の Class オブジェクトで提供 for (Type t : Type.values()) herbsByType.put(t, new HashSet<Herb>()); for (Herb h : garden) herbsByType.get(h.type()).add(h); 11 // インデックスの境界に気にする必要ないほか、キーの型チェックもある
  • 12. 序数で配列インデックス?(2)  物質の相を表す enum 型クラス Phase // 配列の配列をインデックスするのに ordinal() を使用 – これはやってはいけない public enum Phase { SOLID, LIQUID, GAS; public enum Transition { MELT, FREEZE, BOIL, CONDENSE, SUBLIME, DEPOSIT; // src の序数で行が、dst の序数で列がインデックスされる private static final Transition[][] TRANSITIONS = { // 転移表に誤りがあると大変! {null, MELT, SUBLIME}, // 間違えると、 ArrayIndexOutOfBoundException や {FREEZE, null, BOIL}, // NullPointerException が出るかもしれないし、 {DEPOSIT, CONDENSE, null} // 何も出ないでそのまま見逃してしまうかもしれない (!!) }; public static Transition from(Phase src, Phase dst) { return TRANSITIONS[src.ordinal()][dst.ordinal()]; } } }  洗練されているように見えるが… 遷移表の検証が困難、項目の追加・削除でバグを織り込みやすい ⇒ 配列で実装される「状態転移表」のメンテナンス性は総じて低い  12
  • 13. EnumMap で作ってみる public enum Phase { SOLID, LIQUID, GAS; public enum Transition { // 相転移の転移元と転移先の相を定数固有データとして定義 MELT(SOLID,LIQUID), FREEZE(LIQUID,SOLID), BOIL(LIQUID,GAS), CONDENSE(GAS,LIQUID), SUBLIME(SOLID,GAS), DEPOSIT(GAS,SOLID); private final Phase src; private final Phase dst; Transition(Phase src, Phase dst) { this.src = src; this.dst = dst; } // 相転移マップを初期化 private static final Map<Phase, Map<Phase, Transition>> m = new EnumMap<>(Phase.class); static { for (Phase p : Phase.values()) m.put(p, new EnumMap<Phase, Transition>(Phase.class)); for (Transition t : Transition.values()) m.get(t.src).put(t.dst, t); } public static Transition from(Phase src, Phase dst) { return m.get(src).get(dst); } } } 13
  • 14. enum 値を追加する場合の比較    相: PLASMA 追加 相転移: IONIZE(GASPLASMA), DEIONIZE(PLASMAGAS) 追加 配列インデックスに ordinal() 使用時 public enum Transition { MELT, FREEZE, BOIL, CONDENSE, SUBLIME, DEPOSIT, IONIZE, DEIONIZE; private static final Transition[][] TRANSITIONS = { {null, MELT, SUBLIME, null}, {FREEZE, null, BOIL, null}, {DEPOSIT, CONDENSE, null, IONIZE}, {null, null, DEIONIZE, null} }; // 実際の修正場所 PLASMA の序数に依存、間違えると今までの動作もおかしくなる ... }  EnumMap 使用時 public enum Transition { MELT(SOLID,LIQUID), FREEZE(LIQUID,SOLID), BOIL(LIQUID,GAS), CONDENSE(GAS,LIQUID), SUBLIME(SOLID,GAS), DEPOSIT(GAS,SOLID), IONIZE(GAS,PLASMA), DEIONIZE(PLASMA,GAS); ... } 14 // それぞれの値の情報が独立して、干渉し合わない // この一行追加で十分
  • 16. Item 34 拡張可能な enum をインタフェースで模倣する
  • 17. enum 型の拡張性について  ほとんど場合は、enum 型の拡張性は間違った考え  もし拡張できたとすると  拡張された型の要素が基底型の要素であり  基底型の要素は拡張された型の要素ではない ⇒ 混乱を生じることに  拡張可能な列挙型を使う場面    オペレーションコード 何らかの操作を表す要素を持つ列挙型 API が提供する操作の集合の拡張 ⇒ enum が任意のインタフェースを実装できる事実を利用して達成する 17
  • 18. 項目30 の Operation 型の場合  定数固有メソッド実装を持つ enum 型 public enum Operation { PLUS("+") { public MINUS("-") { public TIMES("*") { public DEVIDE("/") { public double double double double apply(double apply(double apply(double apply(double x, x, x, x, double double double double y) y) y) y) { { { { return return return return x x x x + * / y; y; y; y; } } } } }, }, }, }; private final String symbol; Operation(String symbol) { this.symbol = symbol; } @Override public String toString() { return symbol; } abstract double apply(double x, double y); // 模倣するためにインタフェースとして抽出 }  操作を模倣するために抽出されたインタフェース定義 public interface Operation { double apply(double x, double y); } 18
  • 19. enum 型によるインタフェース実装  基本 enum 型 public enum BasicOperation implements Operation PLUS("+") { public double apply(double x, MINUS("-") { public double apply(double x, TIMES("*") { public double apply(double x, DEVIDE("/") { public double apply(double x, { double double double double y) y) y) y) { { { { return return return return x x x x + * / y; y; y; y; } } } } }, }, }, }; private final String symbol; BasicOperation(String symbol) { this.symbol = symbol; } @Override public String toString() { return symbol; } }  模倣された拡張 enum 型 public enum ExtendedOperation implements Operation { EXP("^") { public double apply(double x, double y) { return Math.pow(x, y); } }, REMAINDER("%") { public double apply(double x, double y) { return x % y; } }; private final String symbol; ExtendedOperation(String symbol) { this.symbol = symbol; } @Override public String toString() { return symbol; } } 19
  • 20. 拡張 enum 型の使用  インタフェースが期待された場所、拡張 enum 型も使用可能  境界型トークン使用(項目29) private static <T extends Enum<T> & Operation> void test(Class<T> opSet, double x, double y) { for (T op : opSet.getEnumConstants()) System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y)); }   パラメータ opSet の宣言は、その Class オブジェクトが enum でかつ Operation のサブタイプであることを保証 境界ワイルドカード型使用(項目28) private static void test(Collection<? extends Operation> opSet, double x, double y) { for (Operation op : opSet) System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y)); }  この場合、パラメータ opSet の要素は Operation のサブタイプであることが要求 されるが、要素が enum でなくてもよい  その代わり、操作の実装に EnumSet と EnumMap は使用できない ⇒ 複数の実装型を組み合わせる必要がなければ、境界型トークンが良さそう 20
  • 21. インタフェースで模倣する手法の欠点  一つの enum 型が他の enum 型から実装を継承できない  Operation 型の場合は操作に関連付けられた記号の保存と取り出しのロジック が重複 public enum BasicOperation implements Operation { ... private final String symbol; BasicOperation(String symbol) { this.symbol = symbol; } @Override public String toString() { return symbol; } } public enum ExtendedOperation implements Operation { ... private final String symbol; ExtendedOperation(String symbol) { this.symbol = symbol; } @Override public String toString() { return symbol; } }  21 // 実装を継承できないのでコードが重複 // 実装を継承できないのでコードが重複 重複するコード量が大きい場合、ヘルパークラスや static なヘルパーメソッドで カプセル化できる
  • 22. まとめ  拡張可能な enum 型を書くことできないが  基本の enum 型に伴うインタフェースを書いて、そのインタフェースをそ の基本の enum 型に実装させることで模倣できる  クライアントがそのインタフェースを実装して独自の enum を作れる  API がインタフェースで書かれたとしたら、基本の enum 型を使用する 場所でもそれらの enum 型を使用できる 22