Effective Java Reloaded
先日、待望の「Effective Java」の第2版が発売されたので購入した。
Effective Java 第2版 (The Java Series)
- 作者: Joshua Bloch,柴田芳樹
- 出版社/メーカー: ピアソンエデュケーション
- 発売日: 2008/11/27
- メディア: 単行本(ソフトカバー)
- 購入: 77人 クリック: 936回
- この商品を含むブログ (264件) を見る
著者のジョシュア・ブロックは当時SunでJavaライブラリの設計にかかわり、Googleに移ったあともJava界に強い影響力を及ぼしている人だ。
第1版は、Javaでエレガントなコードを書こうと思ったら絶対に読んでおくべき本だった。
第1版(邦訳)は2001年に発売されたので、第2版の登場までに7年経ったことになる。
その間にJava5、Java6が登場し、Genericsやenumが言語仕様に追加されたため、第1版で提示された定石は必ずしもベストな書き方とは言えなくなった。
第2版はこれらの追加仕様をふまえ、加筆修正を行ったもの。
2006年のJavaのイベント(JavaOne2006)で「改訂版を執筆中」との告知があったと聞いてから、ずっと待ってたんだよ〜
(当時は第2版ではなく「Effective Java Reloaded」と言われていた)
特にJava5で追加されたenumについては、言語仕様を見ただけではいまいちピンと来ず、第1版で紹介された「タイプセーフenumパターン」を使い続けていたのだが、最新のJavaではどう記述すべきか、というのはずっと気になっていた。
Java5で追加されたenumはこの「タイプセーフenum」を言語仕様として取り込み、さらに「switch文で使えない」「ビット和演算などができない」などの、当時示された欠点も解消したものだという。
また、enumとあわせて追加されたEnumSetなどのクラスは、ジョシュア・ブロック本人が書いたらしい。設計・実装者本人による使用法の解説というわけだ。いやー楽しみ。
これまで参加したプロジェクトでも、Genericsや拡張for文は使われていても、enumが使われているところは少なかったのだよねえ…。巷でも、どのように使うべきかが知られていない機能ではなかろうか。
まだ読み始めたばかりだが、enumを使った完全なシングルトンの実装とか、最新のJavaで可能になった応用もいろいろ紹介されている。
第1版は当時の僕には相当難解で、ページを行きつ戻りつしているうちに読むのに半年くらいかかった記憶がある。現在でも内容のすべてを理解しているかちょっと怪しい。
復習も兼ねて、前回と内容が重複している部分も再度読みなおしてみよう。
ナチュラルキーとサロゲートキー
ビジネス上のIDである品番とか氏名コードを「ナチュラルキー」、これに対してビジネス上のコードIDをDBに格納するためだけに生成したものを「サロゲート(代理)キー」と呼ぶ。
テーブル設計をおこなう際、どちらをテーブルの主キーとするかは議論のわかれるところ。
- ナチュラルキーの特長、弱点
- DBエンジニアにとって扱いやすい。システム移行などの作業がシンプル
- コード体系の変更があった場合の影響が大きい
- サロゲートキーの特長、弱点
- コード体系の変更の影響を局所化できる
- オブジェクトモデルとの相性◎
- データベースに直接データ投入する場合でも、別途IDを採番する必要あり
- 一意キー制約を貼り忘れたままシステム稼動してしまうと…
- 初心者には敷居が高いかも
個人的にはサロゲートキー好きだけど、DBAやデータ移行担当者のスキルや経験、DBを複数システムから共用するなどの制約から諦めざるを得ない場面も多い。
また、サロゲートキー採用を推進する場合は、データ投入時にID採番するためのサンプル提供やメンテナンスツールを先行して作成するなど、初心者や未経験者へのフォローが必要かも。
Eclipse内蔵コンパイラとSunのJDKの違い
Eclipseに内蔵されているJavaコンパイラは、SunのJDKのものとは異なる。
そのため、ときおり挙動の異なる部分が見つかることがある。たとえば以下。
class Test {
public static void main(String args[]) {
Long l = 0L;
Double d = 100.0;
l += d; //エラー
}
}
上記のコードは、EclipseではコンパイルできるがJDK付属のjavacではコンパイルできない。
また、Genericsを使用した下記のコードも、Sunのコンパイラではエラーになる。
class GenericsTest {
public static void main(String args[]) {
List
どっちの挙動が正しいのだろう?
いずれにしてもワークベンチ上でコンパイルエラーになっていないからといって、迂闊にリポジトリにコミットするとJDKでコンパイルできないコードが混入してしまうので注意が必要だ。
消したファイルを復活
Subverisonで消してしまったファイルを復活したい場合がある。
古いリビジョンを参照して、その内容を新たに作成したファイルにコピー&ペーストしてもよいが、削除前の履歴は参照できなくなってしまう。
そういう場合は、削除前のリビジョンをマージすればよい。
削除したファイルのあったフォルダのファイル削除前のリビジョンを、現在のフォルダの作業コピーとマージしてコミットすれば、削除前の履歴を保持したままファイルを元に戻すことができる。
接続先によってプロキシを変更する
逆に、自動構成スクリプトを自分で書いてやれば、接続先によってプロキシの切り替えができるようになる。
function FindProxyForURL(url, host)
{
if *1
return "PROXY proxy1:80";
else
return "PROXY proxy2:80";
}
たとえば上記の場合、
- ローカルのドメイン(localdomain.com)内であれば直接接続する
- 接続先ホストが*.comであればproxy1をプロキシサーバにする
- それ以外はproxy2をプロキシサーバにする
となる
自動構成スクリプトは「file://c:\hoge\proxy.pac」のように指定できる場合もあるが、ブラウザによってはhttp://〜で記述しないと読んでくれないものがある。
このため、apacheなどのローカルWebサーバを立てて、そこに置いておくとよい。
*1:isPlainHostName(host) || dnsDomainIs(host, ".localdomain.com"))) return "DIRECT"; else if (shExpMatch(host, "*.com"
自動構成されたプロキシを調べる
最近は企業内のネットワークでもプロキシサーバの自動構成を行っていることが多い。
ブラウザのプロキシの設定を変更しなくても、自動構成スクリプトに従ってネットワーク管理者の推奨するプロキシに接続してくれるので便利なのだけど、自分ではプロキシサーバのIPアドレスはわからない。
たとえばソフトウェア開発ツール「Eclipse」のアップデートに使用する「更新サーバ」に企業内ネットワークから接続する場合、多くの場合プロキシサーバの設定をしなければいけないが、Eclipseはプロキシの自動設定を行ってくれないので、自分でIPアドレスとポートを設定する必要がある。ところが、プロキシサーバのIPアドレスがわからないため更新サーバに接続できない場合がある。
そういうとき、自動構成スクリプトのURLを自分で設定した場合は、自動構成スクリプトの内容を見るとプロキシサーバを知ることができる。
たとえば自動構成スクリプト(PACファイル)のURLが「http://www.example.co.jp/proxy.pac」だった場合、ブラウザで直接PACファイルのURLを指定して参照すると、どのようにプロキシサーバが決まるのかがわかる。
function FindProxyForURL(url,host)
{ if (isInNet(host,"192.168.0.0","255.255.0.0")) return "DIRECT";
else return "PROXY 192.168.0.10:8080; DIRECT";
}
PACファイルはJavaScriptで記述されている。上記の場合ローカルアドレスの場合は直接参照し、それ以外の場合はプロキシサーバ(192.168.0.10:8080)を参照するように設定されている。
自動構成スクリプトを直接設定した場合でなくても、DNSを使ってWPAD(Web Proxy Auto-Discovery)が設定されている場合は、自動構成スクリプトの場所を類推することができる。
たとえばブラウザの動作しているクライアントPCのアドレスがpc.hoge.example.co.jpだった場合、自動更新スクリプトは下記のいずれかになっているはず。
DHCPを使ってWPADを構成した場合、どうしたら自動構成スクリプトの内容やプロキシを知ることができるかはよくわからない。接続中のプロキシがどこか、調べる方法があってもよさそうなものだけど...