システム開発で思うところ

Javaで主にシステム開発をしながら思うところをツラツラを綴る。主に自分向けのメモ。EE関連の情報が少なく自分自身がそういう情報があったら良いなぁということで他の人の参考になれば幸い

Lambdaを使って内部リストを暴露しないで処理をする

最近、ちょっとずつStreamAPIだけでなく、Lambdaを使うことに少しずつ慣れてきつつあります。

Lambdaは無名クラスが簡単に使えるくらいの印象しか持っていなかったのですが、遅延評価の仕組みとして 徐々に使い方が分かってくると 何でもトンカチで殴りたくなるものです。 というわけではないのですが、自分で実装してみて「これは 良いかも」と思ったので ご紹介。

よくやる実装

ファーストクラスコレクションを作って構造と責務を閉じようとするのですが、どうしても内部コレクションを公開したいことはあります。
特に 副作用のある操作をしたい場合に、どうしても そういう実装をせざるを得ないケースです。 そういうときは Collections#unmodifiableList を使って不変なリストを返却するようなメソッドを実装して対応しています。

public class Callee {

    private List<String> items;

    public Callee() {
        this.items = Arrays.asList("aaa", "bbb", "ccc", "ddd");
    }

    public List<String> items() {
        return Collections.unmodifiableList(items);
    }
}
public class Caller {

    public void useList() {
        Callee callee = new Callee();
        List<String> items = callee.items();
        items.stream().forEachOrdered(System.out::println);
    }

}

Lambdaを使って構造公開しない実装

public class Callee {

    private List<String> items;

    public Callee() {
        this.items = Arrays.asList("aaa", "bbb", "ccc", "ddd");
    }

    public void forEachOrdered(Consumer<? super String> action) {
        this.items.stream().forEachOrdered(item -> action.accept(item));
    }

}


ポイントは List<String> items を外部公開することなく 処理が行えているところです。

public class Caller {

    public void useLambda() {
        Callee callee = new Callee();
        callee.forEachOrdered(System.out::println);
    }

}

補足

内部リストの公開以外にもドメインオブジェクト(ファーストクラスコレクション)側に外部依存が少なくなるのも嬉しいところです。

例えば DBアクセスのような処理です。 update(Connection conn, String userId)みたいなメソッドを準備すれば良いんじゃないの?というのが容易に想像できるわけですが、それだと ドメインオブジェクトにインフラ層のパッケージへの依存が生まれます。私としては それを回避できるのも嬉しいところです。*1

気をつけること

当たり前ですが なんでも、このやり方でやるのは良くないです。
Collections.unmodifiableList で不変を担保する代替にはなると思いますが、責務の放棄までしない方が良いです。
例えば、Caller側の情報を使うこともなく、副作用の伴う処理をしているわけでもない、ただ繰り返し処理をするだけというのであれば 目的としている使い方ではありません。それは Collections.unmodifiableListで公開していることと同じことになってしまうので、きちんとドメインオブジェクト側で メソッドとして準備をして、それを使うようにすべきだと思います。

さいごに

なんでも Lambda、なんでも StreamAPI、は正しいとは思いませんが、だからといって忌避することなく、少しずつ使ってみて 理解を深めておくことは大事かな、と思います。 私もまだまだ理解も実践も乏しいところがあります。
「おっ、おもしろそう」と何かしらの一助になれば幸いです。

*1:もちろん、緩衝材としてインターフェースを介すれば問題ないよね?というのもありますし、それはそれで有効な手段だと思います。