Spark中Lambda表达式的变量作用域
通常,我们希望能够在lambda表达式的闭合方法或类中访问其他的变量,例如:
package java8test;
public class T1 {
public static void main(String[] args) {
repeatMessage("Hello", 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表达式中被定义,而是方法repeatMessage的参数变量。如果你思考一下,就会发现这里有一些隐含的东西。lambda表达式可能会在repeatMessage返回之后才运行,此时参数变量已经消失了。如果保留text和count变量会怎样呢?
为了理解这一点,我们需要对lambda表达式有更深入的理解。一个lambda表达式包括三个部分:
- 一段代码
- 参数
- 自由变量的值,这里的“自由”指的是那些不是参数并且没有在代码中定义的变量。
在我们的示例中,lambda表达式有两个自由变量,text和count。数据结构表示lambda表达式必须存储这两个变量的值,即“Hello”和20。我们可以说,这些值已经被lambda表达式捕获了(这是一个技术实现的细节。例如,你可以将一个lambda表达式转换为一个只含一个方法的对象,这样自由变量的值就会被复制到该对象的实例变量中)。
注意:含有自由变量的代码块才被称之为“闭包(closure)”。在Java中,lambda表达式就是闭包。事实上,内部类一直都是闭包。Java8中为闭包赋予了更吸引人的语法。
如你所见,lambda表达式可以捕获闭合作用域中的变量值。在java中,为了确保被捕获的值是被良好定义的,需要遵守一个重要的约束。在lambda表达式中,被引用的变量的值不可以被更改。例如,下面这个表达式是不合法的:
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++不是原子操作,如果多个线程并发执行该自增操作,天晓得会发生什么。
不要指望编译器会捕获所有并发访问错误。不可变的约束只作用在局部变量上,如果matches是一个实例变量或者闭合类的静态变量,那么不会有任何错误被报告出来即使结果同样未定义。同样,改变一个共享对象也是完全合法的,即使这样并不恰当。例如:
List<Path> matches = new ArrayList<>();
for(Path p: files)
//你可以改变matches的值,但是在多线程下是不安全的
new Thread(() -> {if(p中包含某些属性) matches.add(p);}).start();
注意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参数,以下面的代码为例:
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位于方法的何处,其意义都是一样的。
文章收录,引用自 http://my.oschina.net/fhd/blog/419892
Spark中Lambda表达式的变量作用域的更多相关文章
- lambda表达式,变量作用域
# lambda表达式 def filter_lt(predidcate,lt): result=[] for elem in lt: if predidcate(elem): result.appe ...
- Java8中Lambda表达式的10个例子
Java8中Lambda表达式的10个例子 例1 用Lambda表达式实现Runnable接口 //Before Java 8: new Thread(new Runnable() { @Overri ...
- VS编译环境中TBB配置和C++中lambda表达式
TBB(Thread Building Blocks),线程构建模块,是由Intel公司开发的并行编程开发工具,提供了对Windows,Linux和OSX平台的支持. TBB for Windows ...
- Java中lambda表达式详解
原文地址:http://blog.laofu.online/2018/04/20/java-lambda/ 为什么使用lambda 在java中我们很容易将一个变量赋值,比如int a =0;int ...
- Java8 Collections.sort()及Arrays.sort()中Lambda表达式及增强版Comparator的使用
摘要:本文主要介绍Java8 中Arrays.sort()及Collections.sort()中Lambda表达式及增强版Comparator的使用. 不废话直接上代码 import com.goo ...
- 为什么Java中lambda表达式不能改变外部变量的值,也不能定义自己的同名的本地变量呢?
作者:blindpirate链接:https://www.zhihu.com/question/361639494/answer/948286842来源:知乎著作权归作者所有.商业转载请联系作者获得授 ...
- Python中lambda表达式学习
lambda只是一个表达式,函数体比def简单很多. lambda的主体是一个表达式,而不是一个代码块.仅仅能在lambda表达式中封装有限的逻辑进去. lambda表达式是起到一个函数速写的作用.允 ...
- Java中lambda(λ)表达式的语法
举一个排序的例子,我们传入代码来检查一个字符串是否比另一个字符串短.这里要计算: first.length() - second.length() first和second是什么?他们都是字符串.Ja ...
- python中lambda表达式应用
对于简单的函数,也存在一种简便的表示方式,即:lambda表达式 #普通函数1 def func(a): return a+1 print 'test1_func0:',func(1000)4#lam ...
随机推荐
- Linux下UPnP sample分析
一.UPnP简介 UPnP(Universal Plug and Play)技术是一种屏蔽各种数字设备的硬件和操作系统的通信协议.它是一种数字网络中间件技术,建立在TCP/IP.HTTP协 ...
- 如何从本地导入.nupkg文件
买了本asp.net mvc4高级编程 里面的源码下载下来是.nupkg后缀的文件,不知道怎么引入到项目中, baidu无果,只好google,可怜我英语四级都难的人,不过所幸还是找到了方法: htt ...
- CSS3 nth 伪类选择器
考察下面的 HTML 代码片段: <div> <section>section 1</section> <section>section 2</s ...
- 背后的故事之 - 快乐的Lambda表达式(二)
快乐的Lambda表达式 上一篇 背后的故事之 - 快乐的Lambda表达式(一)我们由浅入深的分析了一下Lambda表达式.知道了它和委托以及普通方法的区别,并且通过测试对比他们之间的性能,然后我们 ...
- 修改策略组/注册表 屏蔽Win10升级解决方法
一.Windows非家庭版 第1步:按Win+R键调出运行对话框,输入命令“gpedit.msc”,按回车键启动组策略编辑器. 第2步:依次定位到“计算机配置→管理模板→Windows组件→Windo ...
- [转载]Google Guava官方教程(中文版)
原文链接 译文链接 译者: 沈义扬,罗立树,何一昕,武祖 校对:方腾飞 引言 Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] ...
- GitHub实战系列~1.环境部署+创建第一个文件 2015-12-9
GitHub实战系列汇总:http://www.cnblogs.com/dunitian/p/5038719.html ———————————————————————————————————————— ...
- 【.net 深呼吸】聊聊WCF服务返回XML或JSON格式数据
有时候,为了让数据可以“跨国经营”,尤其是HTTP Web有关的东东,会将数据内容以 XML 或 JSON 的格式返回,这样一来,不管客户端平台是四大文明古国,还是处于蒙昧时代的原始部落,都可以使用这 ...
- SQL Server-聚焦强制索引查询条件和Columnstore Index(九)
前言 本节我们再来穿插讲讲索引知识,后续再讲数据类型中的日期类型,简短的内容,深入的理解,Always to review the basics. 强制索引查询条件 前面我们也讲了一点强制索引查询的知 ...
- 从零开始编写自己的C#框架(1)——前言
记得十五年前自学编程时,拿着C语言厚厚的书,想要上机都不知道要用什么编译器来执行书中的例子.十二年前在大学自学ASP时,由于身边没有一位同学和朋友学习这种语言,也只能整天混在图收馆里拼命的啃书.而再后 ...