Java : ローカルクラスを使いこなせ!

ついこの間まで、ローカルクラスの存在を知らなかった私([id:lethevert:20060115:p3]のコメント欄参照)が言うのもなんですが、関数的な方もメッセージ指向の方も、あまりJavaを甘く見ないほうがいいかもしれないです。
Javaは、非常に純粋なオブジェクト指向言語であり、かつ、構文糖衣([id:lethevert:20060111:p1]参照)に対して非常に保守的であることに加えて、ユーザー(つまりプログラマ)が大衆化されていることから、その力量を見誤られがちな気がしますが、特長をよくつかんでやれば、なかなか引けを取らない言語ですよ。

      • -

次の例は、ストリームからオブジェクトの配列を読み込む処理をローカルクラスと無名クラスの組み合わせで書いたものです。ストリームから要素数を取り出して、配列を作成する処理は、全ての種類のオブジェクトで共通なので、ローカルクラスに抜き出して共通化し、個別の処理だけを、無名クラスで実装しています。
関数型言語になれた方なら、こういう書き方は見慣れたやり方だと思いますが、Javaでも同じようなことがかけるという例です。

class OuterClass {
  public Object[] readStream
    (int type, final ObjectInputStream is)
    throws IOException
  {
    /* 汎用的なストリーム読み込み手続きのクラス */
    abstract class C {
      Object[] allObjects() throws IOException {
        int n = is.readInt();
        Object[] objs = new Object[n];
        for (int i=0; i<n; ++i){
          objs[i] = each();
        }
        return objs;
      }
      abstract Object each() throws IOException;
    }

    /* 本体部 - typeで読み込むオブジェクトの種類を切り替える */
    switch(type){
    case 0:
      return new C()
        { Object each() throws IOException
            { return DataClass0.readStream(is);}
        }.allObjects();
    case 1:
      return new C()
        { Object each() throws IOException
            { return DataClass1.readStream(is);}
        }.allObjects();
    case 2:
      return new C()
        { Object each() throws IOException
            { return DataClass2.readStream(is);}
        }.allObjects();
    default:
      return null;
    }
  }
}