クロージャについてのメモ

オイラのイメージ(というか関連キーワード)は、
 匿名関数
 コールバック
 voidポインタ
 でりげーと

rubyセミナのライトニングトークなんかで、
lisp最強!!!」
なんて言葉を何回か聴いて、
何が最強なのか、その根拠を確かめるべく旅してます...

そーそーそーそー
たとえば、txtA.value="式"なんてときにわざわざ関数定義しなくっても
すんじゃうんだよね....

(function() {
        switch(v) {
        case 1:
                return 'A';
        case 2:
                return 'B';
        }
        return 'C';
})();

javaだとどうなるうんだっけ?

どーかなー?

(new Object() {
        public String toString() {
                switch (v) {
                case 1:
                        return "A";
                case 2:
                        return "B";
                }
                return "C";
        }
});

(はてなから引用)

関数内に出現する自由変数(関数内で宣言されていない変数)の解決の際、実行時の環境ではなく、関数を定義した環境の変数を参照できるようなデータ構造。

wikiによると

『典型的には、クロージャはある関数全体が他の関数(以下、エンクロージャ)の内部で宣言されたときに発生し、
内部の関数はエンクロージャのローカル変数(レキシカル変数)を参照する。
実行時に外部の関数が実行された際、クロージャが形成される。クロージャは内部の関数のコードとエンクロージャ
スコープ内の必要なすべての変数への参照からなる。』

との事。

< html>
<head>
<script>
// ↓クロージャ状態?①
function a(v1) {   // ←エンクロージャ?②
        var v2 = 1;
        function b(v3) {   // ← クロージャ関数?③
                alert(v1 + v2 + v3);
        }
        return b;
}

// ↓クロージャ関数の呼び出し?④
a(1)(2);
</script>
</head>
<body>
</body>
</html>


# 「エンクロージャのローカル変数」とは親関数のローカル変数や引数の事。
# レキシカルスコープが実装されていない処理系(エンクロージャが終了したら消えちゃうとか)もあるとの事。

定義はさておき(笑)、少なくとも、いわゆる親関数のローカル変数や引数を参照するニーズがあって、final修飾さ
れた変数は良く見かけるよね...

具体的な適用業務例としては、

// 超簡略化...
public class Batch1 {

        public void unloadTable1Data(String csvFilePath) {

                Table1DataAccess t1da = new Table1DataAccess();
                final ICsvBeanWriter csvWriter = new OCWriter(new OutputStreamWriter(new FileOutputStream(csvFilePath)));

                t1da.selectTable1(new Callback<Table1, Void>() {

                        @Override
                        public Void invoke(Table1 input) {

                                csvWriter.write(input);

                                return null;
                        }
                });

                csvWriter.close();
        }
}

public interface Callback<INPUT, OUTPUT> {
        OUTPUT invoke(INPUT input);
}

public class Table1 {
        ただのValueObject
        ...
}

public class Table1DataAccess {

        public void selectTable1(Callback<Table1, Void> callback) {

                Connection con = ...
                PreparedStatement ps = con.prepareStatement("SELECT ...");
                ResultSet rs = ps.executeQuery();

                while (rs.next()) {
                        Table1 t1 = ResultSetMapper.mapRow(rs, Table1.class);
                        callback.invoke(t1);
                }
        }
}

ビジネスロジックの一部(1行フェッチする毎の手続き)をコールバックにして、データアクセサレイヤに任すっていう、

バッチ処理で、データアクセサレイヤのクラスが、valueObject(EntityBean)のListを返して、ビジネスロジックレイヤの
クラスがくるくるなんてOutOfMelody爆なことをさせないためのフレームワーク

csvWriterは、クロージャメソッド(←勝手に命名w)が全行処理して、最後にcsvWriter.close()する必要があるから、
必然的にエンクロージャメソッド(←勝手に命名w)のローカル変数でfinalになる...