lambdaについて調べてみた その4

【概要】

今回はラムダ内での変数の扱いについてです。

スコープの扱いが匿名クラスとは違うとのことなので、
違いもあわせて調べてみました。

【変数の参照】

メソッドのパラメータ、ローカル変数、ラムダのパラメータの
参照について見てみます。

public class Sample {

    public static void main(final String[] args) {
        executeSampleLambda01("method arg");
    }

    private static void executeSampleLambda01(final String param) {
        String variableValue = "varVal";
        final Consumer<String> consumer = lambdaParam -> {
            System.out.println(param);
            System.out.println(variableValue);
            //variableValue = "varVal2"; エラー
            System.out.println(lambdaParam);          
        };
        //variableValue = "varVal2"; エラー

        consumer.accept("Test");
    }
}

メソッドパラメータ(param)、ローカル変数(variableValue)、
ラムダのパラメータ(lambdaParam)は参照することができます。

ラムダ内で参照している変数は変更することはできません。
変更するコードを書くとエラーになります。

ここは匿名クラスと同じっぽいです。

[実行結果]
method arg
varVal
Test

【同名の変数】

同名の変数があった場合の扱いです。

public class Sample {

    public static void main(final String[] args) {

        final String methodArg = "method arg";

        executeSampleLambda02(methodArg);
        executeInnerClass02(methodArg);
    }

    private static void executeSampleLambda02(final String param) {
        final Consumer<String> consumer = lambdaParam -> {
        //final Consumer<String> consumer = param -> { ラムダ引数paramはエラー
            System.out.println(lambdaParam);
        };

        consumer.accept("Test");
    }

    private static void executeInnerClass02(final String param) {

        final Consumer<String> consumer = new Consumer<String>() {

            @Override
            public void accept(final String param) {
                System.out.println(param);
            }
        };

        consumer.accept("Test");
    }
}

ラムダの場合、パラメータとラムダ外で定義した変数の
名前がかぶっている場合はエラーになります。

匿名クラスの場合、匿名クラス内のメソッドの
パラメータが優先されるのでエラーになりません。

【thisの扱い】

最後にラムダ・匿名クラス内でのthisの扱いについてです。

public class Sample {

    public static void main(final String[] args) {

        final Sample sample = new Sample();
        sample.executeSampleLambda03();
        sample.executeInnerClass03();
    }

    private void executeSampleLambda03() {
        final Runnable runnable = () -> {
            System.out.println(this.getClass().getName());
        };

        runnable.run();
    }

    private void executeInnerClass03() {
        final Runnable runnable = new Runnable() {

            @Override
            public void run() {
                System.out.println(this.getClass().getName());
            }
        };

        runnable.run();
    }
}

thisは問題なく参照できます。

[実行結果]
hoge.Sample
hoge.Sample$2

匿名クラスの場合はコンパイル時にクラスが作成されて、
ラムダはコンパイル時には作成されずに実行されるようです。
($2になっているのはexecuteInnerClass02のサンプルで一つ作成しているからです)

【いろいろ書いたけど】

ラムダの変数の扱いと匿名クラスでのスコープの違いを調べてみました。

ラムダ内では受け取ったパラメータのみを扱うようにした方が
シンプルで混乱もなくて良いと思います。

今回調べたのは念のためと言うことで。