「Effective Java 第2版」を読んだ感想

投稿日:2017年5月11日 更新日:

こんにちは、okuzawatsです。
諸般の事情でAndroidアプリ開発の勉強を集中的にやっています。

Effective Java 第2版」をようやく読みました。
Javaについての理解が深まる、とても良い本でした。
Effective Javaを読んだ感想や、得られた学びについて書いていきます。

Enumの使い方

Effective Javaに書いてあった列挙型(Enum型)の解説がとても参考になりました。
定数でフラグ管理している時なんかはEnum型で置き換えられます。

列挙型(enumerated type)は、一年での季節、太陽系の惑星、トランプのデッキのスーツなどの固定数の定数からその値が成り立つ型です。

(Effective Java 第2版、p143)

Enumの基本的な書き方はこうです。
値なしで、識別子(列挙子)のみ定義します。

public enum Apple {
	FUJI,
	PIPPIN,
	GRANNY_SMITH
}

以下のような感じで列挙子を割り当てます。
列挙子に応じてSwitch文で分岐を作る、という感じの処理は良くやりますし、定数でフラグを管理するより全然いいです。

Apple apple = Apple.FUJI;

Javaのenum型の基本的な考え方は、単純です。
enumは、public static finalフィールドを通して、個々の列挙定数に対して1つのインスタンスを公開しているクラスです。

(Effective Java 第2版、p144)

クラスなので、コンストラクタを定義できたり、メソッドを定義できたりします。
Effective Javaのサンプルをこちらに引用してみます。

public enum Planet {
	MERCURY(3.302e+23, 2.439e6),
	(中略)
	NEPTUNE(1.024e+26, 2.477e7);
	
	private final double mass;
	private final double radius;
	private final double surfaceGravity;
	
	private static final double G = 6.67300E-11;
	
	Planet(double mass, double radius) {
		this.mass = mass;
		this.radius = radius;
		surfaceGravity = G * mass / (radius * radius);
	}
	
	public double mass() { return mass; }
	public double radius() { return radius; }
	public double surfaceGravity() { return surfaceGravity; }

	public double surfaceWeight(double mass) {
		return mass * surfaceGravity;
	}
}

Enumを使うだけでここまで書けます。

enum型には任意のメソッドやフィールドを追加できますし、任意のインターフェースを実装できます。

(Effective Java 第2版、p145)

public enum Operation {
	PLUS   { double apply(double x, double y) { return x + y; } },
	MINUS  { double apply(double x, double y) { return x - y; } },
	TIMES  { double apply(double x, double y) { return x * y; } },
	DIVIDE { double apply(double x, double y) { return x / y; } };
	
	abstract double apply(double x, double y);
}

Enumを使えば、フラグに応じて処理内容を変える、みたいなのを綺麗に書けていいですね。

Effective Javaを読んでEnum型に関する理解が深まりました。

防御的コピー

防御的コピーとは、インスタンスのパラメータをコピーして、コピーしたパラメータで何らかの処理をする、ということですね。
「行儀が悪い」クライアントに対して頑強なクラスになります。

クラスのクライアントは、クラスの不変式を破壊するために徹底した努力をすると想定して防御的にプログラムしなければなりません。

(Effective Java 第2版、p178)

以下のような感じで値をコピーして使います。
これはEffective Javaのサンプルです。

public Period(Date start, Date end) {
	this.start = new Date(start.getTime());
	this.end   = new Date(end.getTime);
	
	if (this.start.compareTo(this.end) > 0) {
		throw new IllegalArgumentException(this.start + " after " + this.end);
	}
}

常に防御的コピーをすべきかというとそうではなくて、クライアントが信頼できない場合に防御的コピーを使うと良い、というようなことがEffective Javaには書いてあります。

防御的コピーは、それに付随するパフォーマンス上のペナルティを持つ可能性があり、常に正当化されるとは限りません。
おそらく、そのクラスとそのクライアントが同じパッケージの一部であるなどの理由で、呼び出し側が内部要素を変更しないとクラスが信頼できるならば、防御的コピーをしなくても適切かもしれません。

(Effective Java 第2版、p181)

防御的コピー、使い所を考えて使っていきたいですね。

ドキュメントコメントを書く

APIは文書化しなければ使いものにならない、とEffective Javaには書いてあります。
Javaであれば、Javadocを使ってソースコード内にコメントの形でドキュメントを埋め込めます。

Javadocとは、サン・マイクロシステムズが開発したコンピュータソフトで、JavaのソースコードからHTML形式のAPI仕様書を生成するものである。
JavadocはJavaクラスの仕様書の標準の書式であり、多くのIDEは自動的にJavadoc HTMLを生成する機能を備えている。

(Wikipediaより引用)

文書化が必要なのは、公開(public)されているものすべてです。

APIを適切に文書化するためには、すべての公開されているクラス、インターフェース、コンストラクタ、メソッド、フィールド宣言の前にドキュメントコメントを書かなければなりません。

(Effective Java 第2版、p196)

Javadocの書き方の例はこちらです。
「/**」から始まり、「*/」で終わります。
コメントの書き方と似ていますが異なるものです。

/**
 * Returns the element at the specified position in this list
 * 
 * 

This method is not guaranteed to run in constant

* time. In some implementations it may run in time proposal * to the element posision. * * @param index index of element to return; must be * non-negative and less than the size of this list * @return the element at the specified position in this list * @throws IndexOutOfBoundsException if the index is out of range * ({@code index < 0 || index >= this.size()}) */ E get(int index);

Javadocの書き方については、適当にググってください。

Effective Javaを読んだ感想

Effective Java、なかなか読むのがしんどかったですが、とても参考になりました。
一度読んだだけでは理解しきれないので、定期的に読み直したいですね。

Androidアプリを作っていて、もっとJavaのことを勉強したい!
というような方には自信を持ってオススメできる本ですね!

茨城県つくば市在住のAndroidアプリエンジニアです。

-読書感想文

Copyright© Androidアプリ開発@つくば , 2017 AllRights Reserved Powered by AFFINGER4.