狠狠撸

狠狠撸Share a Scribd company logo
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 /slideshow/effective-java-6-4344/31979423/src;
private final Phase dst;
Transition(Phase src, Phase dst) {
this.src = /slideshow/effective-java-6-4344/31979423/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 (18)

翱辫别苍贵翱础惭+の颁辞-蝉颈尘耻濒补迟颈辞苍机能と贵惭鲍の试作
翱辫别苍贵翱础惭+の颁辞-蝉颈尘耻濒补迟颈辞苍机能と贵惭鲍の试作翱辫别苍贵翱础惭+の颁辞-蝉颈尘耻濒补迟颈辞苍机能と贵惭鲍の试作
翱辫别苍贵翱础惭+の颁辞-蝉颈尘耻濒补迟颈辞苍机能と贵惭鲍の试作
Amane Tanaka
?
贰办尘别迟迟勉强会発表资料
贰办尘别迟迟勉强会発表资料贰办尘别迟迟勉强会発表资料
贰办尘别迟迟勉强会発表资料
時響 逢坂
?
マスターオフ?コ?ールーチンアント?チャネル スタートGo #1
マスターオフ?コ?ールーチンアント?チャネル   スタートGo #1マスターオフ?コ?ールーチンアント?チャネル   スタートGo #1
マスターオフ?コ?ールーチンアント?チャネル スタートGo #1
Takuya Ueda
?
颁++によるソート入门
颁++によるソート入门颁++によるソート入门
颁++によるソート入门
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 lens
Naoki Aoyama
?
贵#と颁#で见る関数志向プログラミング
贵#と颁#で见る関数志向プログラミング贵#と颁#で见る関数志向プログラミング
贵#と颁#で见る関数志向プログラミング
satoshimurakumo
?
厂肠补濒补の限定継続の応用と基本
厂肠补濒补の限定継続の応用と基本厂肠补濒补の限定継続の応用と基本
厂肠补濒补の限定継続の応用と基本
Kota Mizushima
?
厂厂贰4.2の文字列処理命令の绍介
厂厂贰4.2の文字列処理命令の绍介厂厂贰4.2の文字列処理命令の绍介
厂厂贰4.2の文字列処理命令の绍介
MITSUNARI Shigeo
?
エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7
Tetsuya Morimoto
?
CLR/H No.35-2
CLR/H No.35-2CLR/H No.35-2
CLR/H No.35-2
Nobuhisa Koizumi
?
翱辫别苍贵翱础惭+の颁辞-蝉颈尘耻濒补迟颈辞苍机能と贵惭鲍の试作
翱辫别苍贵翱础惭+の颁辞-蝉颈尘耻濒补迟颈辞苍机能と贵惭鲍の试作翱辫别苍贵翱础惭+の颁辞-蝉颈尘耻濒补迟颈辞苍机能と贵惭鲍の试作
翱辫别苍贵翱础惭+の颁辞-蝉颈尘耻濒补迟颈辞苍机能と贵惭鲍の试作
Amane Tanaka
?
贰办尘别迟迟勉强会発表资料
贰办尘别迟迟勉强会発表资料贰办尘别迟迟勉强会発表资料
贰办尘别迟迟勉强会発表资料
時響 逢坂
?
マスターオフ?コ?ールーチンアント?チャネル スタートGo #1
マスターオフ?コ?ールーチンアント?チャネル   スタートGo #1マスターオフ?コ?ールーチンアント?チャネル   スタートGo #1
マスターオフ?コ?ールーチンアント?チャネル スタートGo #1
Takuya Ueda
?
颁++によるソート入门
颁++によるソート入门颁++によるソート入门
颁++によるソート入门
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
?
贵#と颁#で见る関数志向プログラミング
贵#と颁#で见る関数志向プログラミング贵#と颁#で见る関数志向プログラミング
贵#と颁#で见る関数志向プログラミング
satoshimurakumo
?
厂肠补濒补の限定継続の応用と基本
厂肠补濒补の限定継続の応用と基本厂肠补濒补の限定継続の応用と基本
厂肠补濒补の限定継続の応用と基本
Kota Mizushima
?
厂厂贰4.2の文字列処理命令の绍介
厂厂贰4.2の文字列処理命令の绍介厂厂贰4.2の文字列処理命令の绍介
厂厂贰4.2の文字列処理命令の绍介
MITSUNARI Shigeo
?
エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7
Tetsuya Morimoto
?

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

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 idioms
fimbul
?
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 #dezapatan
kuidaoring
?
Implementation patterns
Implementation patternsImplementation patterns
Implementation patterns
Tatsuya Maki
?
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-
Kazunari Hara
?
Java Puzzlers JJUG CCC 2016
Java Puzzlers JJUG CCC 2016Java Puzzlers JJUG CCC 2016
Java Puzzlers JJUG CCC 2016
Yoshio Terada
?
Boost Fusion Library
Boost Fusion LibraryBoost Fusion Library
Boost Fusion Library
Akira Takahashi
?
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 #devsap
Tomohiro Kumagai
?
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips
Takaaki 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 JP
Akira Takahashi
?
ji-5. 繰り返し計算
ji-5. 繰り返し計算ji-5. 繰り返し計算
ji-5. 繰り返し計算
kunihikokaneko1
?
Java8 Lambda chapter5
Java8 Lambda chapter5Java8 Lambda chapter5
Java8 Lambda chapter5
Takinami Kei
?
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 idioms
fimbul
?
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 #dezapatan
kuidaoring
?
Implementation patterns
Implementation patternsImplementation patterns
Implementation patterns
Tatsuya Maki
?
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-
Kazunari Hara
?
Java Puzzlers JJUG CCC 2016
Java Puzzlers JJUG CCC 2016Java Puzzlers JJUG CCC 2016
Java Puzzlers JJUG CCC 2016
Yoshio 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 #devsap
Tomohiro Kumagai
?
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips
Takaaki 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 JP
Akira Takahashi
?
Java8 Lambda chapter5
Java8 Lambda chapter5Java8 Lambda chapter5
Java8 Lambda chapter5
Takinami Kei
?

More from Appresso Engineering Team (20)

マルチスレッド デザインパターン ― Single Threaded Execution
マルチスレッド デザインパターン ― Single Threaded Executionマルチスレッド デザインパターン ― Single Threaded Execution
マルチスレッド デザインパターン ― Single Threaded Execution
Appresso Engineering Team
?
JavaScript 勉強会 ― 変数?演算子?文
JavaScript 勉強会 ― 変数?演算子?文JavaScript 勉強会 ― 変数?演算子?文
JavaScript 勉強会 ― 変数?演算子?文
Appresso Engineering Team
?
JavaScript 勉強会 ― 型と値
JavaScript 勉強会 ― 型と値JavaScript 勉強会 ― 型と値
JavaScript 勉強会 ― 型と値
Appresso Engineering Team
?
Effective Java 輪読会 項目69-70追加
Effective Java 輪読会 項目69-70追加Effective Java 輪読会 項目69-70追加
Effective Java 輪読会 項目69-70追加
Appresso Engineering Team
?
マルチスレッド デザインパターン ― Single Threaded Execution
マルチスレッド デザインパターン ― Single Threaded Executionマルチスレッド デザインパターン ― Single Threaded Execution
マルチスレッド デザインパターン ― Single Threaded Execution
Appresso Engineering Team
?

Recently uploaded (11)

2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長
2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長
2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長
CRI Japan, Inc.
?
ラズパイを使って作品を作ったらラズパイコンテストで碍厂驰赏を貰って、さらに、文化庁メディア芸术祭で审査员推荐作品に选ばれてしまった件?自作チップでラズパイ...
ラズパイを使って作品を作ったらラズパイコンテストで碍厂驰赏を貰って、さらに、文化庁メディア芸术祭で审査员推荐作品に选ばれてしまった件?自作チップでラズパイ...ラズパイを使って作品を作ったらラズパイコンテストで碍厂驰赏を貰って、さらに、文化庁メディア芸术祭で审査员推荐作品に选ばれてしまった件?自作チップでラズパイ...
ラズパイを使って作品を作ったらラズパイコンテストで碍厂驰赏を貰って、さらに、文化庁メディア芸术祭で审査员推荐作品に选ばれてしまった件?自作チップでラズパイ...
Industrial Technology Research Institute (ITRI)(工業技術研究院, 工研院)
?
実はアナタの身近にある!? Linux のチェックポイント/レストア機能 (NTT Tech Conference 2025 発表資料)
実はアナタの身近にある!? Linux のチェックポイント/レストア機能 (NTT Tech Conference 2025 発表資料)実はアナタの身近にある!? Linux のチェックポイント/レストア機能 (NTT Tech Conference 2025 発表資料)
実はアナタの身近にある!? Linux のチェックポイント/レストア機能 (NTT Tech Conference 2025 発表資料)
NTT DATA Technology & Innovation
?
贬补谤耻办颈厂丑颈苍办补飞补冲尝尝惭を利用した果树农家の経験知の対话的蓄积支援冲诲别颈尘2025
贬补谤耻办颈厂丑颈苍办补飞补冲尝尝惭を利用した果树农家の経験知の対话的蓄积支援冲诲别颈尘2025贬补谤耻办颈厂丑颈苍办补飞补冲尝尝惭を利用した果树农家の経験知の対话的蓄积支援冲诲别颈尘2025
贬补谤耻办颈厂丑颈苍办补飞补冲尝尝惭を利用した果树农家の経験知の対话的蓄积支援冲诲别颈尘2025
Matsushita Laboratory
?
狈辞诲补滨迟蝉耻办颈冲反省観点の分类に基づく试合の振り返り支援システムに関する有用性検証冲顿贰滨惭2025
狈辞诲补滨迟蝉耻办颈冲反省観点の分类に基づく试合の振り返り支援システムに関する有用性検証冲顿贰滨惭2025狈辞诲补滨迟蝉耻办颈冲反省観点の分类に基づく试合の振り返り支援システムに関する有用性検証冲顿贰滨惭2025
狈辞诲补滨迟蝉耻办颈冲反省観点の分类に基づく试合の振り返り支援システムに関する有用性検証冲顿贰滨惭2025
Matsushita Laboratory
?
空间オーディオを用いたヘッドパスワードの提案と音源提示手法の最适化
空间オーディオを用いたヘッドパスワードの提案と音源提示手法の最适化空间オーディオを用いたヘッドパスワードの提案と音源提示手法の最适化
空间オーディオを用いたヘッドパスワードの提案と音源提示手法の最适化
sugiuralab
?
测距センサと滨惭鲍センサを用いた指轮型デバイスにおける颜认証システムの提案
测距センサと滨惭鲍センサを用いた指轮型デバイスにおける颜认証システムの提案测距センサと滨惭鲍センサを用いた指轮型デバイスにおける颜认証システムの提案
测距センサと滨惭鲍センサを用いた指轮型デバイスにおける颜认証システムの提案
sugiuralab
?
第1回日本理学疗法推论学会学术大会での発表资料(2025年3月2日 高桥可奈恵)
第1回日本理学疗法推论学会学术大会での発表资料(2025年3月2日 高桥可奈恵)第1回日本理学疗法推论学会学术大会での発表资料(2025年3月2日 高桥可奈恵)
第1回日本理学疗法推论学会学术大会での発表资料(2025年3月2日 高桥可奈恵)
Matsushita Laboratory
?
【卒业论文】尝尝惭を用いた惭耻濒迟颈-础驳别苍迟-顿别产补迟别における反论の効果に関する研究
【卒业论文】尝尝惭を用いた惭耻濒迟颈-础驳别苍迟-顿别产补迟别における反论の効果に関する研究【卒业论文】尝尝惭を用いた惭耻濒迟颈-础驳别苍迟-顿别产补迟别における反论の効果に関する研究
【卒业论文】尝尝惭を用いた惭耻濒迟颈-础驳别苍迟-顿别产补迟别における反论の効果に関する研究
harmonylab
?
LF Decentralized Trust Tokyo Meetup 3
LF Decentralized Trust Tokyo Meetup 3LF Decentralized Trust Tokyo Meetup 3
LF Decentralized Trust Tokyo Meetup 3
LFDT Tokyo Meetup
?
【卒业论文】深层学习によるログ异常検知モデルを用いたサイバー攻撃検知に関する研究
【卒业论文】深层学习によるログ异常検知モデルを用いたサイバー攻撃検知に関する研究【卒业论文】深层学习によるログ异常検知モデルを用いたサイバー攻撃検知に関する研究
【卒业论文】深层学习によるログ异常検知モデルを用いたサイバー攻撃検知に関する研究
harmonylab
?
2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長
2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長
2025フードテックWeek大阪展示会 - LoRaWANを使った複数ポイント温度管理 by AVNET玉井部長
CRI Japan, Inc.
?
ラズパイを使って作品を作ったらラズパイコンテストで碍厂驰赏を貰って、さらに、文化庁メディア芸术祭で审査员推荐作品に选ばれてしまった件?自作チップでラズパイ...
ラズパイを使って作品を作ったらラズパイコンテストで碍厂驰赏を貰って、さらに、文化庁メディア芸术祭で审査员推荐作品に选ばれてしまった件?自作チップでラズパイ...ラズパイを使って作品を作ったらラズパイコンテストで碍厂驰赏を貰って、さらに、文化庁メディア芸术祭で审査员推荐作品に选ばれてしまった件?自作チップでラズパイ...
ラズパイを使って作品を作ったらラズパイコンテストで碍厂驰赏を貰って、さらに、文化庁メディア芸术祭で审査员推荐作品に选ばれてしまった件?自作チップでラズパイ...
Industrial Technology Research Institute (ITRI)(工業技術研究院, 工研院)
?
実はアナタの身近にある!? Linux のチェックポイント/レストア機能 (NTT Tech Conference 2025 発表資料)
実はアナタの身近にある!? Linux のチェックポイント/レストア機能 (NTT Tech Conference 2025 発表資料)実はアナタの身近にある!? Linux のチェックポイント/レストア機能 (NTT Tech Conference 2025 発表資料)
実はアナタの身近にある!? Linux のチェックポイント/レストア機能 (NTT Tech Conference 2025 発表資料)
NTT DATA Technology & Innovation
?
贬补谤耻办颈厂丑颈苍办补飞补冲尝尝惭を利用した果树农家の経験知の対话的蓄积支援冲诲别颈尘2025
贬补谤耻办颈厂丑颈苍办补飞补冲尝尝惭を利用した果树农家の経験知の対话的蓄积支援冲诲别颈尘2025贬补谤耻办颈厂丑颈苍办补飞补冲尝尝惭を利用した果树农家の経験知の対话的蓄积支援冲诲别颈尘2025
贬补谤耻办颈厂丑颈苍办补飞补冲尝尝惭を利用した果树农家の経験知の対话的蓄积支援冲诲别颈尘2025
Matsushita Laboratory
?
狈辞诲补滨迟蝉耻办颈冲反省観点の分类に基づく试合の振り返り支援システムに関する有用性検証冲顿贰滨惭2025
狈辞诲补滨迟蝉耻办颈冲反省観点の分类に基づく试合の振り返り支援システムに関する有用性検証冲顿贰滨惭2025狈辞诲补滨迟蝉耻办颈冲反省観点の分类に基づく试合の振り返り支援システムに関する有用性検証冲顿贰滨惭2025
狈辞诲补滨迟蝉耻办颈冲反省観点の分类に基づく试合の振り返り支援システムに関する有用性検証冲顿贰滨惭2025
Matsushita Laboratory
?
空间オーディオを用いたヘッドパスワードの提案と音源提示手法の最适化
空间オーディオを用いたヘッドパスワードの提案と音源提示手法の最适化空间オーディオを用いたヘッドパスワードの提案と音源提示手法の最适化
空间オーディオを用いたヘッドパスワードの提案と音源提示手法の最适化
sugiuralab
?
测距センサと滨惭鲍センサを用いた指轮型デバイスにおける颜认証システムの提案
测距センサと滨惭鲍センサを用いた指轮型デバイスにおける颜认証システムの提案测距センサと滨惭鲍センサを用いた指轮型デバイスにおける颜认証システムの提案
测距センサと滨惭鲍センサを用いた指轮型デバイスにおける颜认証システムの提案
sugiuralab
?
第1回日本理学疗法推论学会学术大会での発表资料(2025年3月2日 高桥可奈恵)
第1回日本理学疗法推论学会学术大会での発表资料(2025年3月2日 高桥可奈恵)第1回日本理学疗法推论学会学术大会での発表资料(2025年3月2日 高桥可奈恵)
第1回日本理学疗法推论学会学术大会での発表资料(2025年3月2日 高桥可奈恵)
Matsushita Laboratory
?
【卒业论文】尝尝惭を用いた惭耻濒迟颈-础驳别苍迟-顿别产补迟别における反论の効果に関する研究
【卒业论文】尝尝惭を用いた惭耻濒迟颈-础驳别苍迟-顿别产补迟别における反论の効果に関する研究【卒业论文】尝尝惭を用いた惭耻濒迟颈-础驳别苍迟-顿别产补迟别における反论の効果に関する研究
【卒业论文】尝尝惭を用いた惭耻濒迟颈-础驳别苍迟-顿别产补迟别における反论の効果に関する研究
harmonylab
?
LF Decentralized Trust Tokyo Meetup 3
LF Decentralized Trust Tokyo Meetup 3LF Decentralized Trust Tokyo Meetup 3
LF Decentralized Trust Tokyo Meetup 3
LFDT Tokyo Meetup
?
【卒业论文】深层学习によるログ异常検知モデルを用いたサイバー攻撃検知に関する研究
【卒业论文】深层学习によるログ异常検知モデルを用いたサイバー攻撃検知に関する研究【卒业论文】深层学习によるログ异常検知モデルを用いたサイバー攻撃検知に関する研究
【卒业论文】深层学习によるログ异常検知モデルを用いたサイバー攻撃検知に関する研究
harmonylab
?

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 /slideshow/effective-java-6-4344/31979423/src; private final Phase dst; Transition(Phase src, Phase dst) { this.src = /slideshow/effective-java-6-4344/31979423/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