Effective Java

【Effective Java】各項目のまとめ

Effective Java シリーズの各項目の一覧。 第1章:はじめに 第1章:はじめに 第2章:オブジェクトの生成と消滅 項目1:コンストラクタの代わりに static ファクトリーメソッドを検討する 項目2:数多くのコンストラクタパラメータに直面した時にはビル…

【Effective Java】項目78:シリアライズされたインスタンスの代わりに、シリアライズ・プロキシを検討する

Serializable を実装すると、バグやセキュリティ上の問題が発生する可能性が高くなります。 コンストラクタ以外でインスタンスが生成されるようになるからです。 これらの可能性を大幅に減らす技法が、シリアライズ・プロキシ・パターン(Serialization Prox…

【Effective Java】項目77:インスタンス制御に対しては、readResolve より enum 型を選ぶ

シングルトンのクラスをシリアライズする場合、readResolve メソッドを使ってインスタンス制御するよりも enum 型による実装を選ぶべきです。 readResolve メソッド まず readResolve メソッドについて説明します。 例えば、次のようなシングルトンクラスを…

【Effective Java】項目76:防御的に readObject を書く

ストリームからオブジェクトをデシリアライズする readObject メソッドは実質的に public コンストラクタとして機能します。 そのため、クラスのコンストラクタで検査している正当性や不変式を readObject にも実装する必要があります。 Period クラスの例 …

【Effective Java】項目75:カスタムシリアライズ形式の使用を検討する(後半)

前回の記事ではデフォルトシリアライズとカスタムシリアライズの概要について説明しました。 hjm333.hatenablog.com 本記事では、カスタムシリアライズ実装の注意事項について説明します。 StringList のカスタムシリアライズ実装を再掲します。 public clas…

【Effective Java】項目75:カスタムシリアライズ形式の使用を検討する(前半)

シリアライズする方法には次の二つの種類があります。 デフォルトシリアライズ形式 カスタムシリアライズ形式 何の考慮もせずにデフォルトシリアライズ形式を用いることは、互換性やパフォーマンスの点で非常に危険です。 なるべくカスタムシリアライズ形式…

【Effective Java】項目74:Serializable を注意して実装する

項目74からはオブジェクトシリアライズ API について説明します オブジェクトをバイト列として符号化することをシリアライズ、バイト列からオブジェクトに復号化することをデシリアライズと呼びます。 シリアライズされたオブジェクトは仮想マシン間やネッ…

【Effective Java】項目73:スレッドグループを避ける

スレッドグループはもはや利用するべきではありません。 スレッドグループのスレッド一覧を取得するための enumerate メソッドは、スレッドを格納する十分な大きさの配列が渡されない場合、勝手に一部のスレッドを無視します。 また、スレッドの数を取得する…

【Effective Java】項目72:スレッドスケジューラに依存しない

プログラムの正しさやパフォーマンスをスレッドスケジューラーの動作に依存させてはいけません。 実行可能なスレッド数はプロセッサの数と比べて非常に大きくならないようにするべきです。 そうしておけば、スレッドスケジューラーがどのようなアルゴリズム…

【Effective Java】項目71:遅延初期化を注意して使用する

遅延初期化(lazy initialization)は、フィールドの値が必要になるまで初期化を遅らせる手法です。 static フィールドとインスタンスフィールドの両方に利用できます。 まず、第一に、通常は遅延初期化を使うべきではありません。 初期化を遅らせる仕組みに…

【Effective Java】項目70:スレッド安全性を文書化する

開発者は、クラスがマルチスレッド環境で利用された場合にどのように振る舞うかを文書化しなければなりません。 マルチスレッド環境における振る舞いを文書化しない場合、クラスの利用者は十分な同期を行わない(項目66)かもしれませんし、逆に過度な同期…

【Effective Java】項目69:wait と notify よりコンカレンシーユティリティを選ぶ(後半)

固有のロック Java は相互排他ロックを言語固有の機能として持っています。 このロックを利用するためには synchronzied ブロックを使います。 固有のロックは次のような仕組みで動作します。 synchronized ブロックに入る時、スレッドは指定されたオブジェ…

【Effective Java】項目69:wait と notify よりコンカレンシーユティリティを選ぶ(前半)

Java のスレッド操作 API として Object.wait() と Object.notify() があります。 しかし、Java 1.5 からはより高いレベルのユティリティが導入されたので wait() と notify() は使うべきではありません。 追加されたのは java.util.concurrent ユティリティ…

【Effective Java】項目68:スレッドよりエグゼキューターとタスクを選ぶ

Java 1.5 から、エグゼキューターフレームワークが利用できるようになりました。 このフレームワークを使うと、スレッドで実行するためのワークキューを簡単に作成することができます。 // スレッドで実行するためのエグゼキューターサービスの生成 Executor…

【Effective Java】項目67:過剰な同期は避ける

前回の記事では、同期が不十分な場合にはマルチスレッド環境において予期しないエラーが発生する可能性を説明しました。 hjm333.hatenablog.com hjm333.hatenablog.com 今回は前回とは逆の視点です。 過剰に同期することによって発生する問題について取り上…

Java の同期化とは何か(2)(【EffectiveJava】項目66:共有された可変データへのアクセスを同期する-後半-)

前回の記事では Java の同期化(synchronized)について説明してきました。 hjm333.hatenablog.com 今回の記事では「volatile」と「同期化が必要ない場合」について説明します。 volatile Java の同期化(synchronized)は次の性質を保証するものでした。 ア…

Java の同期化とは何か(1)(【EffectiveJava】項目66:共有された可変データへのアクセスを同期する-前半-)

複数のスレッドで可変データを共有する場合にはそれぞれのスレッドを同期化(synchronized)する必要があります。 Java の同期化は次の二つの性質を保証します。 アトミック性(処理の排他制御) メモリの可視性 アトミック性 異なるスレッドが共通のデータ…

【Effective Java】項目65:例外を無視しない

空の catch ブロックを使って例外を無視してはいけません。 // 空の catch ブロック try { ... } catch (Exception e) { } 例外を無視するとエラーがあるという事実が隠蔽されてしまいます。 それによって、他の場所で別の形でエラーが再現する可能性もあり…

【Effective Java】項目64:エラーアトミック性につとめる

オブジェクトのメソッドが例外をスローしたあとは、そのメソッドを呼び出す前の状態になっているべきです。 この性質を「エラーアトミックである」といいます。 「エラーアトミック」を達成する方法はいくつかあります。 不変オブジェクト エラーアトミック…

【Effective Java】項目63:詳細メッセージにエラー記録情報を含める

システムがキャッチされない例外で終了すると次の情報が出力されます。 スタックトレース 例外の文字列表現 例外の詳細メッセージ 最後の「例外の詳細メッセージ」はエラーの原因を調査するための唯一の手がかりであることが多いです。 そのため、例外の詳細…

【Effective Java】項目62:各メソッドがスローするすべての例外を文書化する

チェックされる例外は個別に宣言するべきです。 そして、それぞれの例外の発生条件を Javadoc の @throws に必ず文書化するべきです。 throws Exception や throws Throwable というように、複数の例外をまとめて throws 宣言してはいけません。 扱うべき例…

【Effective Java】項目61:抽象概念に適した例外をスローする

例外翻訳 メソッドの内部で発生した下位レイヤの例外は、外側に伝播させないほうがいい場合があります。 下位レイヤで発生した例外をそのままスローすると、利用者が混乱したり API を実装の詳細で汚染する場合があります。 そのレイヤの概念と合わない例外…

【Effective Java】項目60:標準例外を使用する

Java ではほとんどの場面で必要となる基本的な例外が標準ライブラリに含まれています。 すでに用意されている標準の例外を再利用することには次のような利点があります。 コードを確立されている慣例と一致させることができる 見慣れた例外によってコードの…

【Effective Java】項目59:チェックされる例外を不必要に使用するのを避ける

チェックされる例外はプログラマに例外の処理を強制させることができるので、プログラムの信頼性を大きく向上させることができます。 ただし、これを過剰に利用すると API が使いにくいものになってしまいます。 次の条件がすべて満たされる場合のみ、チェッ…

【Effective Java】項目58:回復可能な状態にはチェックされる例外を、プログラミングエラーには実行時例外を使用する

例外の種類 Java には次のような種類の例外があります。 チェックされる例外(checked exception) チェックされない例外(unchecked exception) 実行時例外(runtime exception) エラー(error) チェックされる例外 チェックされる例外がスローされると…

【Effective Java】項目57:例外的状態にだけ例外を使用する

例外は例外的な状況に対してのみ利用するべきです。 正常なパスで例外を利用するべきではありません。 よいパフォーマンスを得ようとして、次のようなコードを書く人達がいます。 try { int i = 0; while (true) range[i++].climb(); } catch (ArrayIndexOut…

【Effective Java】項目56:一般的に受け入れられている命名規約を守る

Java には命名規約(naming convention)があります。 命名規約は2種類に分類されていて、活字的(typographical)と文法的(grammatical)に分けられています。 活字的命名規約はパッケージ、クラス、インタフェース、メソッド、フィールド、型変数を扱っ…

【Effective Java】項目55:注意して最適化する

最適化に関してはさまざまな格言があります。 特に知られているのは Knuth によるものでしょう。*1 僅かな効率、たとえば、時間の約97%、については忘れるべきである。時期尚早の最適化は、すべての悪の根源である。 速いプログラムを書くことよりも、良…

【Effective Java】項目54:ネイティブメソッドを注意して使用する

Java Native Interface (JNI) を使うと C/C++ などで書かれたネイティブメソッドを呼び出すことができます。 歴史的にネイティブメソッドには3つの用途がありました。 レジストリ、ファイルロックなどのプラットフォーム固有機構へのアクセス 古いコードのラ…

【Effective Java】項目53:リフレクションよりインタフェースを選ぶ

リフレクション機構 リフレクション機構を使うと、ロードされたクラスの情報に、プログラムからアクセスすることができます。 具体的には Class インスタンスに対して、それが表すクラスのコンストラクタ・メソッド・フィールドを取得することができます。 …