Java 8 新特性:Lambda 表达式的作用域(Lambda 表达式补充版)

简介: Java 8 新特性:Lambda 表达式的作用域(Lambda 表达式补充版)

Lambda 表达式的作用域


在Lambda表达式中访问外层作用域和旧版本的匿名对象中的方式类似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。


Lambda表达式不会从超类(supertype)中继承任何变量名,也不会引入一个新的作用域。Lambda表达式基于词法作用域,也就是说lambda表达式函数体里面的变量和它外部环境的变量具有相同的语义(也包括lambda表达式的形式参数)。此外,this关键字及其引用,在Lambda表达式内部和外部也拥有相同的语义。


Lambda表达式全文地址:http://blog.csdn.net/sun_promise/article/details/51121205


1.访问局部变量


1)可以直接在lambda表达式中访问外层的局部变量


eg:

final int num = 1;
Converter<Integer, String> s =
        (param) -> String.valueOf(param + num);
s.convert(2);     // 3

 

但是和匿名对象不同的是,lambda表达式的局部变量(eg:num)可以不用声明为final

eg:

int num = 1;
Converter<Integer, String> s =
        (param) -> String.valueOf(param + num);
stringConverter.convert(2);     // 3

不过这里的局部变量(eg:num)必须不可被后面的代码修改(即隐性的具有final的语义)

eg:下面代码无法编译

int num = 1;
Converter<Integer, String> s =
        (param) -> String.valueOf(param + num);
num = 5;

 

num = 5;

Note:在Lambda表达式中试图修改局部变量是不允许的。


2)在 Lambda 表达式当中被引用的变量的值不可以被更改。

public void repeat(String string, int count) {
        Runnable runnable = () -> {
            for (int i = 0; i < count; i++) {
                string = string + "a";//编译出错
                System.out.println(this.toString());
            }
        };
        new Thread(runnable).start();
}

3)在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。

eg:

String first = "";
Comparator<String> comparator = (first, second) -> Integer.compare(first.length(),//编译会出错
                second.length());

2.访问对象字段与静态变量


和局部变量不同的是,Lambda内部对于实例的字段(即:成员变量)以及静态变量是即可读又可写。

eg:

class LambdaDemo {
    static int myStaticNum;
    int myNum;
    void testScopes() {
        Converter<Integer, String> s1 = (param) -> {
            myNum = 33;
            return String.valueOf(param);
        };
        Converter<Integer, String> s2 = (param) -> {
            myStaticNum = 87;
            return String.valueOf(param);
        };
    }
}

3.不能访问接口的默认方法


Lambda表达式中是无法访问到默认方法的。


4.Lambda表达式中的this


Lambda 表达式中使用 this 会引用创建该 Lambda 表达式的方法的 this 参数。

eg:

public class Test2 {
    public static void main(String[] args) {
        Test2 test = new Test2();
        test.method();
    }
    @Override
    public String toString() {
        return "Lambda";
    }
    public void method() {
        Runnable runnable = () -> {
            System.out.println(this.toString());
        };
        new Thread(runnable).start();
    }
}

显示结果:Lambda


5.综合理解Lambda表达式的作用域


(注:如果上面的3条内容都理解了,就不用再仔细看下面这个示例和分析了。)

eg:

public class Test {
    public static void main(String[] args) {
        repeatMessage("Hello world", 20);
    }
    public static void repeatMessage(String text,int count){
        Runnable r = () -> {
            for(int i = 0; i < count; i++){
                System.out.println(text);
                Thread.yield();
            }
        };
        new Thread(r).start();
    }
}

分析: Lambda表达式中的变量count和text,它们并没有在Lambda表达式中被定义,而是方法的参数。Lambda表达式可能会在repeatMessage()返回之后才运行,此时参数变量已经消失了。如果保留text和count变量会怎样呢?


为了更好地理解上面的情况,我们需要对Lambda表达式有更深入的理解。

一个lambda表达式包括三个部分:

一段代码。


参数。


自由变量的值,这里的“自由”指的是那些不是参数并且没有在代码中定义的变量。

在示例中,lambda表达式有两个自由变量,text和count。数据结构表示Lambda表达式必须存储这两个变量的值,即“Hello world ”和20。可以理解为,这些值已经被Lambda表达式捕获了(这是一个技术实现的细节。eg:你可以将一个lambda表达式转换为一个只含一个方法的对象,这样自由变量的值就会被复制到该对象的实例变量中)。


Note:含有自由变量的代码块才被称之为“闭包(closure)”。在Java中,lambda表达式就是闭包。事实上,内部类一直都是闭包。Java8中为闭包赋予了更吸引人的语法。


Lambda表达式可以捕获闭合作用域中的变量值。在java中,为了确保被捕获的值是被良好定义的,需要遵守一个重要的约束。在Lambda表达式中,被引用的变量的值不可以被更改。


eg:下面这个表达式是不合法的

public static void repeatMessage(String text,int count){
    Runnable r = () -> {
        while(count > 0){
            count--;        //错误,不能更改已捕获变量的值
            System.out.println(text);
            Thread.yield();
         }
     };
     new Thread(r).start();
}

 

做出这个约束是有原因的。更改lambda表达式中的变量不是线程安全的。假设有一系列并发的任务,每个线程都会更新一个共享的计数器。

int matches = 0;
for(Path p : files)
new Thread(() -> {if(p中包含某些属性) matches++;}).start();    //非法更改matches的值

 

不要指望编译器会捕获所有并发访问错误。不可变的约束只作用在局部变量上,如果matches是一个实例变量或者闭合类的静态变量,那么不会有任何错误被报告出来即使结果同样未定义。同样,改变一个共享对象也是完全合法的,即使这样并不恰当。

List<Path> matches = new ArrayList<>();
for(Path p: files)
//你可以改变matches的值,但是在多线程下是不安全的
new Thread(() -> {if(p中包含某些属性) matches.add(p);}).start();


Note:matches是“有效final”的(一个有效的final变量被初始化后,就永远不会再被赋一个新值的变量)。在我们的示例中,matches总是引用同一个ArrayList对象,但是,这个对象是可变的,因此是线程不安全的 。如果多个线程同时调用add方法,结果将无法预测。


Lambda表达式的方法体与嵌套代码块有着相同的作用域。因此它也适用同样的命名冲突和屏蔽规则。在Lambda表达式中不允许声明一个与局部变量同名的参数或者局部变量。  

Path first = Paths.get("/usr/bin");
Comparator<String> comp = (first,second) ->
    Integer.compare(first.length(),second.length());
//错误,变量first已经定义了


在一个方法里,你不能有两个同名的局部变量,因此,你也不能在lambda表达式中引入这样的变量。


当你在Lambda表达式中使用this关键字,你会引用创建该Lambda表达式的方法的this参数,

eg:

public class Application{
    public void doWork(){
        Runnable runner = () -> {....;System.out.println(this.toString());......};
    }
}


表达式this.toString()会调用Application对象的toString()方法,而不是Runnable实例的toString()方法。在Lambda表达式中使用this,与在其他地方使用this没有什么不同。Lambda表达式的作用域被嵌套在doWork()方法中,并且无论this位于方法的何处,其意义都是一样的。


目录
相关文章
|
11天前
|
安全 Java API
Java中的Lambda表达式:简洁与功能的结合
Java中的Lambda表达式:简洁与功能的结合
155 91
|
11天前
|
安全 Java
Java中的Switch表达式:更简洁的多路分支
Java中的Switch表达式:更简洁的多路分支
156 91
|
2月前
|
自然语言处理 Java Apache
在Java中将String字符串转换为算术表达式并计算
具体的实现逻辑需要填写在 `Tokenizer`和 `ExpressionParser`类中,这里只提供了大概的框架。在实际实现时 `Tokenizer`应该提供分词逻辑,把输入的字符串转换成Token序列。而 `ExpressionParser`应当通过递归下降的方式依次解析
167 14
|
25天前
|
Java 编译器
Java 17 Switch表达式:更简洁、更强大的流程控制
Java 17 Switch表达式:更简洁、更强大的流程控制
|
2月前
|
安全 Java API
Java 17 及以上版本核心特性在现代开发实践中的深度应用与高效实践方法 Java 开发实践
本项目以“学生成绩管理系统”为例,深入实践Java 17+核心特性与现代开发技术。采用Spring Boot 3.1、WebFlux、R2DBC等构建响应式应用,结合Record类、模式匹配、Stream优化等新特性提升代码质量。涵盖容器化部署(Docker)、自动化测试、性能优化及安全加固,全面展示Java最新技术在实际项目中的应用,助力开发者掌握现代化Java开发方法。
96 1
|
2月前
|
IDE Java API
Java 17 新特性与微服务开发的实操指南
本内容涵盖Java 11至Java 17最新特性实战,包括var关键字、字符串增强、模块化系统、Stream API、异步编程、密封类等,并提供图书管理系统实战项目,帮助开发者掌握现代Java开发技巧与工具。
125 1
|
2月前
|
设计模式 数据采集 Java
Java正则表达式的基础知识,进阶至熟练掌握。
通过大量的练习来熟悉它们的识别模式、如何设计模式来解决实际问题,才能够逐步达到熟练掌握。更多的是通过实践、编写代码和解决真实问题来完善技能。在这方面,没有快速的捷径,唯有刻意练习和长时间的代码实践。
54 0
|
搜索推荐 Java 程序员
Java 12都有哪些新特性?
Java 12都有哪些新特性?
197 0
Java 12都有哪些新特性?
|
Java API Apache
Java 9都有哪些新特性?
Java 9都有哪些新特性?
165 0

热门文章

最新文章