The King's Museum

東京で働くソフトウェアエンジニアのブログ。

【Effective Java 3rd】Item 1: Consider static factory methods instead of constructors

オブジェクトを生成するために public コンストラクタの他に static ファクトリーメソッドを用意するとよいでしょう。

static ファクトリーメソッドとは、インスタンスを返す単なる static メソッドのことです。 例えば、Java の Boolean では次のような static ファクトリーメソッドが提供されています。

public static Boolean valueOf (boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}

なお、GoF のデザインパターンで議論される「ファクトリーメソッド」とは異なるので注意が必要です。

Advantages

通常のコンストラクタと比較して static ファクトリーメソッドには次のようなメリットがあります。

名前がつけられる

コンストラクタの名前は必ずクラス名と一致しなければなりません。

一方、static ファクトリーメソッドではより適切な名前をつけることができます。

インスタンスの生成をコントロールできる

コンストラクタは必ずインスタンスを生成してしまいます。

一方、static ファクトリーメソッドでは必ずしもインスタンスを生成する必要はありません。 これは GoF のデザインパターンの Flyweight パターンに相当します。 さきほどの Boolean.valueOf はまさにこのパターンです。

インスタンスの生成をコントロールできることで、シングルトン(項目3)、インスタンス化不可能(項目4)、不変クラス(項目15)などのパターンに応用することもできます。

サブタイプのインスタンスを生成できる

コンストラクタは必ずそのクラスのインスタンスを生成します。

一方、static ファクトリーメソッドでは必ずしもそのクラスのインスタンスを返す必要がありません。 例えば、実装のためだけの非公開クラスを公開することなく、そのインスタンスを生成することができます。

Java8 以前ではインタフェースが static メソッドを持てませんでした。 そのため、Type というインタフェースを継承した実装クラスを生成するため、インスタンス化不可能な Types という Utility クラスを定義して static ファクトリーメソッドを用意していました。 しかし、Java8 からはインタフェースがインタフェースが static メソッドを持てるようになったのでこのテクニックの必要性はうすれています。

引数の値によって生成するインスタンスを変更できる

コンストラクタは生成する引数によってインスタンスを変更できません。

一方、static ファクトリーメソッドを使うと入力値によって生成するインスタンスを変更可能です。

EnumSet がよい例です。 EnumSet のファクトリーメソッドは enum 型の値の個数によって、生成するインスタンスを変更しています。 具体的には enum 要素が 64 以下なら RegularEnumSet のインスタンスを返しますが、それより大きければ JumboEnumSet のインスタンスを返します。

クラス作成時には存在しないインスタンスを生成できる

当たり前の話ですが、あるクラスのコンストラクタを作成するとき、生成するインスタンスのクラスは必ず定義されています。

一方、static ファクトリーメソッドでは作成時点では、返すクラスの定義は存在していなくてもかまいません。 この柔軟なファクトリーメソッドは Service Provider Framework の基本となります。

Disadvantages

static ファクトリーメソッドにはいくつかのデメリットもあります。

public または protected のコンストラクタを持たないクラスをサブクラスにできない

この制限は不便に感じるかもしれませんが、実際には問題ありません。 なぜなら、そのような場合は継承ではなく、コンポジョンの利用を促すからです。

他の static メソッドと区別がつきづらい

static ファクトリーメソッドのための API ドキュメントが存在しません。そのため、ドキュメント上で通常の static メソッドと static ファクトリーメソッドの区別がつきません。

これに対しては一般的な命名規則に従うことで弱点を克服しています。以下に命名規則の例を示します。

  • from()
    • 一つのパラメータをもらって対応するインスタンスを返します。
  • of()
    • 複数のパラメータをもらってそれらを取り扱うインスタンスを返します。
  • valueOf()
    • from() や of() の代替です。
  • instance() or getInstance()
    • パラメータで指定されたインスタンスを返します。
    • 入力したパラメータと同じ値を持つとは限りません。
  • create() or newInstance()
    • getInstance に似ていますが、必ず新しいインスタンスを生成します。
  • getType()
    • getInstance に似ていますが、ファクトリーメソッドが対象のクラスと異なるクラスにある場合に利用されます。
    • Type は返されるオブジェクトの型の名前です。
  • newType()
    • newInstance に似ていますが、ファクトリーメソッドが対象のクラスと異なるクラスにある場合に利用されます。
    • Type は返されるオブジェクトの型の名前です。
  • type()
    • getType や newType の代替です。

Effective Java

Effective Java

Coursera の "Deep Learning Specialization" をはじめたよ

久しぶりに Coursera を始めてみました。

www.coursera.org

今流行りの Deep Learning です。

流行ってるだけあって、世間にはいろんな教材があるわけで、何を使ってどうやって学ぶかは迷うところ。 その中で自分は Coursera の Andrew Ng 先生の講義を選んだ。他の教材を比較検討したわけじゃないけど、Coursera で Andrew 先生の講義なら間違いないでしょ、という結論。

以前、受講した先生のMachine Learning の講義もすごく良かったからね。

www.thekingsmuseum.info

Deep Learning でキャリアを築くぞ!とはぜんぜん思っていなくて、これからのエンジニア人生を考えるとこの領域を無視するわけにはいかないだろうし…。というくらいの動機。もちろん、とても興味ある領域だしね。

ところで、Coursera は最近けっこう有料の講義が増えてきてると思う。 でも、それはネガティブだとは思わないかな。 そのおかげで講義自体の質とかビデオ・資料まわりの使いやすさがとても向上しているように思う。 そもそも有料化といっても、1コース1万円弱なわけで。 それで世界的に活躍する人たちの講義が受講できる、というのはどう考えてもお得。

AlphaGo

ちょっと話題が逸れるけど、Netflix で AlphaGo のドキュメンタリー見た。

www.netflix.com

イ・セドル棋士が AlphaGo に三連敗したあと、一勝するシーンは鳥肌が立った(AlphaGo が勝利したことは覚えていたけれど、詳細な勝敗は覚えてなかった)。

このシーンを見ながら「人間の脳の力って侮れないなー」と思ったな。

AlphaGo って世界トップの研究者とエンジニアが10人くらい集まって、Google が持ってるとんでもない計算力使って試合に望んでいるわけで。対局してる間もバックヤードでエンジニア数人が常にシステムの状態チェックしたりしてるんだよね。

それに対して、イ・セドル棋士はたった一人で孤独に考え続けなければならないわけですよ。プレッシャーも半端ないし。 そんな状況でたとえ一勝とはいえ AlphaGo を倒しちゃうんだからね。 実況してる解説者たちが「やったー!勝ちましたー!」ってお互いにハイタッチしてたけど、俺も一緒にハイタッチしたい気分になったよw

【Effective Java 3rd Edition】Chapter 1: Introduction

この本は Java の言語とライブラリを効果的に利用するための手引きについて書かれています。 全部で 90 の項目があり、それぞれで一つのルールが示されています。

この本では最近の Java の特徴についてもカバーしています。

Feature Items Release
Lambdas Item 42-44 Java 8
Streams Item 45-48 Java 8
Optionals Item 55 Java 8
Default methods in interfaces Item 21 Java 8
try-with-resources Item 9 Java 7
@SafeVarargs Item 32 Java 7
Modules Item 15 Java 9

この本の規則は、明瞭性(clarity)と簡潔性(simplicity)という原則から導かれています。あらゆる再利用可能なコンポーネント(モジュール)は、その挙動でモジュールの利用者を驚かせてはいけませんし、その規模は小さくあるべきです。また、コードはコピーされないで再利用されるべきです。

エラーはなるべく早い段階で検知できるようにし、実行時ではなく、コンパイラ段階で検知できるように努めるべきです。

この本で提示される規則は常に守らなければならないわけではないですが、まずは規則を学び、ときにそれを破るという姿勢をもつべきです(守破離)。

明瞭で、正しく、再利用可能で、強固で、柔軟性があるようにコードを書いていれば、たいていの場合、必要なパフォーマンスが得られます。 そうしておけばパフォーマンスが本当に必要になったとき、簡単にそれを得ることができるでしょう。

Java の構成要素

Java には4種類の型があります。

  • interfaces(annotations を含む)
  • classes(enums を含む)
  • arrays
  • primitives

最初の3種類は reference types として知られています。また、class instance と array は objects と呼ばれます。

クラスは次の要素を持っています。

  • fields
  • methods
  • member classes
  • member interfaces

メソッドシグネチャは次の要素で構成されます。

  • name
  • the types of its formal parameter

メソッドの戻り値の型が含まれないことに注意してください。

用語

この本では『Java 言語仕様』とは異なる用語の使い方をしているケースがあります。 ただし、大抵のケースはそのまま理解できるものでしょう。

例えば、この本では「サブクラス化(subclassing)」を「継承(inheritance)」と書く場合があります。

API

この本において API とは次の要素を示しています。

  • classes
  • interfaces
  • constructors
  • members
  • serialized forms

プログラマはこれらを通して各種モジュールアクセスするためです。 これらの要素が Javadoc で標準出力されるのは、偶然ではなく意図的にそうなっています。

API を利用するプログラマをユーザーと呼び、API を利用するクラスをクライアントと呼びます。

Java 9 では module system が導入されています。 ライブラリが module system を使っている場合、module で宣言されたパッケージが公開 API となります。

感想

Effective Java 3rd を読むついでに、第二版(日本語)向けに書いた記事をアップデートしてみることにした。

最初に Effective Java の記事書いたのもう2年半前。 読み返してみるとやっぱり間違ってるところあるし、こういう記事書いておいてなんだけど、本気の人はちゃんと本で読んだ方がいいですよ・・・(そして僕に間違いを教えてください)

Effective Java

Effective Java

独自ドメイン化しました

この度、ブログを独自ドメイン化しました。

http://www.thekingsmuseum.info

はてなブログもプロになったので広告やキーワードリンクなどを消しました。 (もしかしたらいつの間にか Google AdSense が入っていたりするかもしれません)

ついでにこっそりアイコンやニックネームを僕自身のものに変更しました :-)

今後ともよろしくお願いします。

第226回 TOEIC の結果

去年の12月に受験した TOEIC の結果が返ってきた。

Listening Reading Total
425 445 870

あわよくば 900 超えないかなーなんて思ってたけどそんなことはなかった。 パート2の問題文がまともに頭に入ってこなくて(理由は不明)、かなり適当にマークしてしまった割にはとれたかな。

これまでの TOEIC のスコア推移は次の通り。

受験日 Listening Reading Total
2017/12(今回) 425 445 870
2017/3 430 415 845
2016/3 350 400 750

細切れにしか勉強時間が確保できないから、勉強してる実感はあまりないけど、スコアはちゃんと伸びてきてる。 毎日、少しずつ、ってのは勉強の王道ですね(特に言語学習では)。

前回、845 取ったときは「これぜったい上振れでしょ…」と思ってたけど、今回は 850 を超えたわけで「TOEIC 850 〜」くらいの位置にはいるんだよね。 でも、これくらいのスコアが取れるようになってきて、スコア 900 レベルだと自分のイメージしていた「英語ができる姿」にぜんぜん届かないことが分かってきた。

2年前英語を勉強し始めた頃は「TOEIC は最終的に 900 超が目標かな〜」なんて思ってたが…。

数日前、「暴かれる王国 サウジアラビア」を字幕無しの英語音声で見たけど、

  • 完璧に意味が理解できた(文をリピート出来る): 0.5 割
  • なんとなく意味が理解できた(単語などから推測):2.5 割
  • 言ったことは耳に入った(気がする)が、意味が分からなかった: 3割
  • 何を言ってるのかまったく分からなかった: 4割

って感じで、ゴールの遠さにちょっと絶望した。

でもまあ、ポジティブな面を見れば、Reading に関してはかなりレベルアップした。そこらへんの Developer Guide 程度の文書なら苦労なくスラスラと読めるようになったし。ちょっと砕けたブログとかエッセーだと途端にすらすら読めなくなっちゃうけど…。

Towards over 950

ということもあって、900 点を目標にしていると自分のイメージするゴールに全然到達しないので、まずは目標再設定して 950 点を今年の目標にした。

一般的には Listening のスコアが高くなる傾向があるみたいだけど、自分は感覚的にもスコア的にも Reading の方が明らかに得意。Reading のスコアが高い人の方がスコアが伸びやすいと書いてある記事を目にしたので頑張れば今年中の 950 も夢じゃないかも?とハードルを高めにしてみた。

本当は今までやってきたこととか、今年やろうと思ってる英語ネタを書き連ねようと思ったけど、長くなったので一旦これで終わりにして時間があったらまた書きます。

Gauche の勉強を再開。

2 年前くらいに Gauche を勉強したいなーと思ったんだけど、いろいろあって途中でやめてしまってたのを再開した。

hjm333.hatenablog.com

Scheme は SICP を Streams くらいまではやったので、簡単なプログラミングクイズみたいなのは解けたりするけど、普段使いできるレベルじゃない感じ。

目標は、

  • 普段のちょっとしたスクリプトを Gauche で書けるようになる。

という実務的なところと、

  • Lambda 式は、「レキシカルな環境を保持した手続き」(クロージャ)へと評価される
  • 手続き呼び出しは継続を伴った引数つき goto である

と本に書かれていた意味を理解できるようになる、という興味的なところかな。 まあ、現時点でもひとつ目はなんとなく理解できるけど。

理由

言語を勉強する時って「Hoge を勉強する理由」みたいな話になりがちだけど、Scheme に関しては「単純に興味があるから」くらいしか理由はない。

ここ数年はキャリアに効きそうなことを重視して勉強していたけど、単純に興味あることに少しは時間を費やしてもいいかなーと思ったのもある。 プロゲーマーのウメハラが「最近、なんとなく昔使ってたキャラをメインに使い始めたら、なんとなく人生が楽しくなってきたんですよね。昔、ゲーム始めた頃に持ってた感覚というか、そーゆーのが戻ってきた。」みたいなこと言ってたのに少し影響を受けた。

別に俺は昔 Scheme 使ってたわけじゃないけど、学生の頃に Lisp ってできるハッカーが使いこなしてるイメージがあっていつか使いこなしたいなーと思って。自分の興味あることを勉強する単純な楽しさみたいなものがここにある気がする。

キーバインド

あと Emacs の Scheme 用のキーバインドをちゃんと使いながらコード書こうとしてるんだけど、ぜんぜんうまくできないのがそれはそれで結構楽しい。 身体と頭が一致しない感じは子供の頃にキーボードの配置覚えた頃を思い出させる。外側の S 式に行こうとして、キーを押したら内側の S 式いっちゃったり。四苦八苦。

でも、頑張って練習してると昨日よりちょっとうまくカーソル動かせたりするとこれが嬉しかったりするんだよなー。

2歳半になる息子が、毎日できないことにもがきながらもどんどん成長している姿を見て、歳をとってもそういう姿勢は持っておきたいなーと感じた。

Effective Java 3rd Edition

Effective Java の 3rd Edition がついに発売するようだ。

Effective Java (3rd Edition)

Effective Java (3rd Edition)

ここからなら EPUB で買えそう。(そうすれば Kindle で読める)

www.informit.com

また解説記事書こうかな。。。

2018年1月21日追記

Effective Java 3rd Edition のまとめを書き始めました。

www.thekingsmuseum.info

(c) The King's Museum