Java Lambda 表达式(二):作用域

Java Lambda 表达式(二):作用域

引言

正如我们之前在 Java 变量捕获(Captured Variable)Java 变量隐藏(Shadow)两篇文章中所说的,局部类和匿名类都存在变量捕获和变量隐藏,而今天我们说到的 Lambda 表达式却有些许不同:Lambda 表达式存在变量捕获,但没有变量隐藏

更进一步说,Lambda 表达式的作用域是词法作用域,这表示:

  • Lambda 表达式不会从超类型继承任何名称或引入新级别的作用域
  • Lambda 表达式中的声明被解释为和封闭环境中的一样

示例代码

譬如以下的代码:

package com.wuxianjiezh.test;

import java.util.function.Consumer;

public class ScopeTest {

    public int x = 0;

    class InnerClass {

		// 内部类 `InnerClass` 中的变量 `x` 隐藏了与封闭类 `ScopeTest` 中同名的变量 `x`
        public int x = 1;

        void print(int x) {

            // 与内部类和匿名类一样,Lambda 表达式也会有变量捕获:
            // 只能访问封闭块中的最终(final)
            // 或实际上的最终(effectively final)(从 Java 8 开始)的局部变量(本地变量)和参数。
            //
            // 由于这个赋值语句,导致参数 `x` 不再是实际上的最终变量。
            // 以下语句会导致编译器在语句 A 处报错:
            // Variable used in Lambda expression should be final or effectively final
            //
            // x = 99;

            int y = 11;
            // 由于这个赋值语句,导致局部变量 `y` 不再是实际上的最终变量。
            // 以下语句会导致编译器在语句 B 处报错:
            // Variable used in Lambda expression should be final or effectively final
            //
            // y = 12;


            Consumer<Integer> consumer = z -> {
                // Lambda 表达式不会引入新级别的作用域(即不会隐藏变量),故以下语句会导致编译器报错:
                // Variable 'x' is already defined in the scope
                //
                // int x = 1;

                // Lambda 表达式存在变量捕获,故以下语句会导致编译器报错:
                // Variable used in Lambda expression should be final or effectively final
                // x = 100;

                // Lambda 表达式不会引入新级别的作用域,
                // 故可以在 Lambda 表达式中直接访问当前封闭作用域的字段、方法(参数)和局部变量:
                //
                System.out.println("x = " + x); // 语句 A,直接访问封闭作用域中的方法参数
                System.out.println("y = " + y); // 语句 B,直接访问封闭作用域中的局部变量
                System.out.println("z = " + z);
                System.out.println("this.x = " + this.x); // 使用 `this` 引用内部类的成员变量
                System.out.println("ScopeTest.this.x = " +
                        ScopeTest.this.x);// 使用变量所属的类名来引用较大范围的成员变量
            };

            consumer.accept(x);
        }
    }

    public static void main(String... args) {
        ScopeTest scopeTest = new ScopeTest();
        InnerClass innerClass = scopeTest.new InnerClass();
        innerClass.print(21);
    }
}

以上代码的输出结果为:

x = 21
y = 11
z = 21
this.x = 1
ScopeTest.this.x = 0

总结

为了便于记忆,我们可以将 Lambda 表达式作用域总结为以下几点:

  • Lambda 表达式是词法作用域,即它没有自己的作用域
  • Lambda 表达式没有自己的 this 关键字
  • Lambda 表达式有变量捕获,但没有变量隐藏
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值