- 浏览: 56509 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (43)
- Java(JVM_JDK_JRE) (16)
- JMail_JBPM_JNI_Maven (1)
- Ajax_JS_JQuery_JQuery UI_ExtJS_正则 (8)
- Flex_ActionScript (0)
- C#_Asp.NET_Silverlight (0)
- SQL/MySQL/Oracle/SQLServer (1)
- WebLogic_Tomcat_JBoss (0)
- Lucene_JUnit_Dom4j_Log4J (2)
- JPA_Hibernate_iBatis (2)
- Android (0)
- HTTP_WebService_FTP (0)
- SaaS_SOA (0)
- JMeter (0)
- erlang (0)
- Spring_Spring security_Spring MVC (4)
- 生活 (2)
- 设计模式_UML (0)
- Linux (4)
- 面试 (1)
- 黑 (1)
- 杂项。。。 (0)
最新评论
-
masterHU:
/**
* 自定义异常类
* @author hK ...
IE标题兰被黑,注册表被锁 -
masterHU:
:lol:
IE标题兰被黑,注册表被锁 -
masterHU:
引用[u][/u]
IE标题兰被黑,注册表被锁 -
masterHU:
引用[img][/img][url][/url][flash= ...
IE标题兰被黑,注册表被锁 -
davencool:
我在redhat5.4下能安装,但是运行后出错了。不知道原因。 ...
Linux 飞鸽。。。。
前几天Oracle推出了Java 7官方的闭包与Lambda表达式的第一个实现,这基本上也是最终在正式版中的样式了。看了这个实现之后,我的第一感觉便是“丑”,当然不排除这是因为看惯了其他语言中实现的缘故。后来再仔细看了看又想了想,发现Java 7的实现也并非毫无可取之处,但似乎又感到某些做法上有一些问题。总之整个过程颇为有趣,决定将我的想法记录下来,希望可以吸引人来一起讨论一下。
Java 7中的Lambda表达式
Java 7中的Lambda表达式有两种形式,首先是第一种:
然后是第二种,含义与上面等价:
如果Lambda的body是“单个表达式”的话,便可以使用“小括号”,并省去最后的return关键字;如果body中需要包含多条语句的话,则必须使用“大括号”,而大括号内部可以包含多条语句,就像一个普通的方法体一样。这两种写法在C#中也有对应物,如在“单个表达式”的情况下:
第二种,即多条语句:
Java和C#的Lambda表达式都由两部分组成:“参数列表”和“表达式体”,但是它们有如下区别:
在Java中参数列表和表达式体之间没有分隔符号,而C#使用“=>”分隔。
对于“单个表达式”的Lambda来说,C#可以无需使用括号包含表达式体,而Java必须使用小括号。
如果只有单个参数,那么C#的参数列表可以省去小括号,而Java必须保留。
C#对参数列表会进行“类型推断”,而Java必须写清参数类型。
这些区别说大可大,说小可小,但是Java语言的设计的确让我感觉较C#为“丑”,这可能是个人主观因素,但我认为也不尽然。例如,如果我们需要对一个用户对象数组按照“年龄”进行排序,在C#里可以写作:
而在Java中则必须写为:
这句C#代码语义清晰:按照“u的Age进行排序”,而在Java代码中便显得比较累赘,语义似乎也不够清晰。Anders在设计C#语法的时候非常注重“声明式”代码,由此可见一斑。此外,我不明白为什么Java选择不对参数进行类型推断,在我看来这对于写出优雅代码十分重要(关于这点,在“Why Java Sucks and C# Rocks”系列中会有更详细的讨论)。不过Java也不是没有“推断”,例如从上面的代码片断中可以得知,Java对于Lambda表达式的返回值还是进行了类型推断。事实上,Java还推断了“异常类型”,这点稍后会有更多讨论。
当然,Java中可以“无中生有”地定义“匿名函数类型”(这点和VB.NET相对更为接近),而不需要像C#一样需要基于特定的“委托类型”,显得更为灵活。
SAM类型支持及闭包
SAM的全称是Single Abstract Method,如果一个类型为SAM类型,则意味着它 1) 是抽象类型(即接口或抽象类),且 2) 只有一个未实现的方法。例如这样一个Java接口便是个SAM类型:
于是我们便可以:
可见,我们使用Lambda表达式创建了Func接口的实例,这点是C#所不具备的。这点十分关键,因为在Java类库中已经有相当多的代码使用了SAM类型。不过我发现,在某些使用SAM的方式下似乎会产生一些“歧义”,例如这段代码:
在这里我们覆盖(override)了MyClass的hashCode方法,使它抛出RuntimeException,那么在调用MyMethod中定义的func1对象时会不会抛出异常?答案是否定的,因为在这个Lambda表达式中,隐藏的“this引用”代表了func对象,调用它的hashCode不会抛出RuntimeException。那么,假如我们要调用MyClass的hashCode怎么办?那就稍微有些麻烦了:
由于Func对象上没有n,因此这里的n便是MyClass类里定义的n成员了。因此,Java的闭包并非不会捕获字面上下文里的成员,只是在SAM类型的情况下,字面范围内(lexical scope)成员的优先级会低于目标抽象类型的成员。
总体来说,对于SAM类型的支持上,我认为Java是有可取之处的,只是我始终认为这个做法会产生歧义,因为我印象中其他语言里的Lambda表达式似乎都是捕获字面上下文的(当然它们可能也没有SAM支持)。但是,如何在“歧义”和“优雅”之间做出平衡,我一时也找不到令人满意的答案。
硬伤:Checked Exception
Java相当于其他常见语言有一个特别之处,那就是Checked Exception。Checked Exception意味着每个方法要标明自己会抛出哪些异常类型(RuntimeException及其子类除外),这也是方法契约的一部分,编译器会强制程序员写出满足异常契约的代码。例如某个类库中定义了这样一个方法:
其中throws后面标注的便是myMethod可能会抛出的异常。于是如果我们要写一个方法去调用myMethod,则可能是:
当我们写一个方法A去调用方法B时,我们要么在方法A中使用try...catch捕获B抛出的方法,要么在方法A的签名中标记“会抛出同样的异常”。如上面的myMethodCaller方法,便在内部处理了BException异常,而只会对外抛出AException。Java便使用这种方法严格限制了类库的异常信息。
Checked Exception是一个有争议的特性。它对于编写出高质量的代码非常重要,因为在哪些情况抛出异常其实都是方法契约的一部分(不仅仅是签名或返回值的问题),应该严格遵守,在类库升级时也不能破坏,否则便会产生兼容性的问题。例如,您关注MSDN里的文档时,就会看到异常的描述信息,只不过这是靠“文档”记录的,而Java则是强制在代码中的;但是,从另一个角度说,Checked Exception让代码编写变得非常麻烦,这导致的一个情况便是许多人在写代码时,自定义的异常全都是RuntimeException(因为不需要标记),每个方法也都是throws Exception的(这样代码中就不需要try...catch了),此时Checked Exception特性也基本形同虚设,除了造成麻烦以外几乎没有带来任何好处。
我之前常说:一个特性如果要被人广泛接受,那它一定要足够好用。现在如Scala和Grovvy等为Java设计的语言中都放弃了Checked Exception,这也算是从侧面印证了Checked Exception的尴尬境地吧。
而Checked Exception对于如今Lambda或闭包来说,在我看来更像是一种硬伤。为什么这么说?举个例子吧,假如有这么一个map方法,可以把一个数组映射成另一个类型数组:
好,那么比如这样一个需求:给定一个字符串数组,保存着文件名,要求获得它的标准路径。从表面上看来,我们可以这样写:
但事实上,这么做无法编译通过。为什么?因为getCanonicalPath方法会抛出IOException,我们在调用时必须显式地使用 try...catch进行处理。那么这段代码该怎么写?还真没法写。如果没有Checked Exception的话(如C#),我们还可以这么做(处理第一个抛出的IOException):
但是,如果我们要写出之前那种“漂亮”的写法,就不能使用Func<T, R>而必须是这样的接口类型:
或者是这样的“匿名函数类型”:
但是,作为Lambda和闭包的常用场景,如map,filter,fold等“函数式”元素,是不可能为某种特定的“异常类型”而设计的——异常类型千变万化,难道这也要用throws Exception来进行“统一处理”吗?Java虽然已经支持对异常类型的“推断”,但Checked Exception还是对Lambda和闭包的适用性造成了很大影响。
因此,我认为Checked Exception是一个“硬伤”。
其他
Java的Lambda和闭包还有一些特性,例如参数的“泛化”:
由于Number是Integer的基类,因此我们可以使用Number来构造一个接受Integer参数的匿名函数类型。由于示例较少,我还不清楚这个特性的具体使用场景和意义所在——不过我猜想,在Java中可能允许这样做吧:
此外还有一些特性,例如与MethodHandle类型的转化,我就没有特别的看法了。
文章来源:http://blog.zhaojie.me/2010/06/first-version-of-lambda-and-closures-in-java-7.html
Java 7中的Lambda表达式
Java 7中的Lambda表达式有两种形式,首先是第一种:
#int() func1 = #()(3); // "func1.()" returns 3 #int(int) func2 = #(int x)(x + 1); // "func2.(3)" returns 4 #int(int, int) func3 = #(int x, int y)(x - y); // "func3.(5, 3)" returns 2
然后是第二种,含义与上面等价:
#int() func1 = #(){ return 3; }; #int(int) func2 = #(int x){ return x + 1; }; #int(int, int) func3 = #(int x, int y){ return x – y; };
如果Lambda的body是“单个表达式”的话,便可以使用“小括号”,并省去最后的return关键字;如果body中需要包含多条语句的话,则必须使用“大括号”,而大括号内部可以包含多条语句,就像一个普通的方法体一样。这两种写法在C#中也有对应物,如在“单个表达式”的情况下:
// C# Func<int> func1 = () => 3; // "func1()" returns 3 Func<int, int> func2 = x => x + 1; // "func2(3)" returns 4 Func<int, int, int> func3 = (x, y) => x - y; // "func3(5, 3)" returns 2
第二种,即多条语句:
// C# Func<int> func1 = () => { return 3; }; Func<int, int> func2 = x => { return x + 1; }; Func<int, int, int> func3 = (x, y) => { return x – y; };
Java和C#的Lambda表达式都由两部分组成:“参数列表”和“表达式体”,但是它们有如下区别:
在Java中参数列表和表达式体之间没有分隔符号,而C#使用“=>”分隔。
对于“单个表达式”的Lambda来说,C#可以无需使用括号包含表达式体,而Java必须使用小括号。
如果只有单个参数,那么C#的参数列表可以省去小括号,而Java必须保留。
C#对参数列表会进行“类型推断”,而Java必须写清参数类型。
这些区别说大可大,说小可小,但是Java语言的设计的确让我感觉较C#为“丑”,这可能是个人主观因素,但我认为也不尽然。例如,如果我们需要对一个用户对象数组按照“年龄”进行排序,在C#里可以写作:
// C# users.Sort(u => u.Age);
而在Java中则必须写为:
Arrays.sort(users, #(User u)(u.Age));
这句C#代码语义清晰:按照“u的Age进行排序”,而在Java代码中便显得比较累赘,语义似乎也不够清晰。Anders在设计C#语法的时候非常注重“声明式”代码,由此可见一斑。此外,我不明白为什么Java选择不对参数进行类型推断,在我看来这对于写出优雅代码十分重要(关于这点,在“Why Java Sucks and C# Rocks”系列中会有更详细的讨论)。不过Java也不是没有“推断”,例如从上面的代码片断中可以得知,Java对于Lambda表达式的返回值还是进行了类型推断。事实上,Java还推断了“异常类型”,这点稍后会有更多讨论。
当然,Java中可以“无中生有”地定义“匿名函数类型”(这点和VB.NET相对更为接近),而不需要像C#一样需要基于特定的“委托类型”,显得更为灵活。
SAM类型支持及闭包
SAM的全称是Single Abstract Method,如果一个类型为SAM类型,则意味着它 1) 是抽象类型(即接口或抽象类),且 2) 只有一个未实现的方法。例如这样一个Java接口便是个SAM类型:
public interface Func<T, R> { R invoke(T arg); }
于是我们便可以:
Func<int, int>[] array = new Func<int, int>[10]; for (int i = 0; i < array.length; i++) { final int temp = i; array[i] = #(int x)(x + temp); }
可见,我们使用Lambda表达式创建了Func接口的实例,这点是C#所不具备的。这点十分关键,因为在Java类库中已经有相当多的代码使用了SAM类型。不过我发现,在某些使用SAM的方式下似乎会产生一些“歧义”,例如这段代码:
public class MyClass { @Override public int hashCode() { throw new RuntimeException(); } public void MyMethod() { Func<int, int> func = #(int x)(x * hashCode()); int r = func.invoke(5); // throw or not? } }
在这里我们覆盖(override)了MyClass的hashCode方法,使它抛出RuntimeException,那么在调用MyMethod中定义的func1对象时会不会抛出异常?答案是否定的,因为在这个Lambda表达式中,隐藏的“this引用”代表了func对象,调用它的hashCode不会抛出RuntimeException。那么,假如我们要调用MyClass的hashCode怎么办?那就稍微有些麻烦了:
Func<int, int> func = #(int x)(x * MyClass.this.hashCode()); 不过从另一段示例代码上看: public class MyClass { public int n = 3; public void MyMethod() { Func<int, int> func = #(int x)(x + n); int r = func.invoke(5); // 8 } }
由于Func对象上没有n,因此这里的n便是MyClass类里定义的n成员了。因此,Java的闭包并非不会捕获字面上下文里的成员,只是在SAM类型的情况下,字面范围内(lexical scope)成员的优先级会低于目标抽象类型的成员。
总体来说,对于SAM类型的支持上,我认为Java是有可取之处的,只是我始终认为这个做法会产生歧义,因为我印象中其他语言里的Lambda表达式似乎都是捕获字面上下文的(当然它们可能也没有SAM支持)。但是,如何在“歧义”和“优雅”之间做出平衡,我一时也找不到令人满意的答案。
硬伤:Checked Exception
Java相当于其他常见语言有一个特别之处,那就是Checked Exception。Checked Exception意味着每个方法要标明自己会抛出哪些异常类型(RuntimeException及其子类除外),这也是方法契约的一部分,编译器会强制程序员写出满足异常契约的代码。例如某个类库中定义了这样一个方法:
public void myMethod() throws AException, BException
其中throws后面标注的便是myMethod可能会抛出的异常。于是如果我们要写一个方法去调用myMethod,则可能是:
public void myMethodCaller() throws AException { try { myMethod(); } catch (BException ex) { throw new AException(ex); } }
当我们写一个方法A去调用方法B时,我们要么在方法A中使用try...catch捕获B抛出的方法,要么在方法A的签名中标记“会抛出同样的异常”。如上面的myMethodCaller方法,便在内部处理了BException异常,而只会对外抛出AException。Java便使用这种方法严格限制了类库的异常信息。
Checked Exception是一个有争议的特性。它对于编写出高质量的代码非常重要,因为在哪些情况抛出异常其实都是方法契约的一部分(不仅仅是签名或返回值的问题),应该严格遵守,在类库升级时也不能破坏,否则便会产生兼容性的问题。例如,您关注MSDN里的文档时,就会看到异常的描述信息,只不过这是靠“文档”记录的,而Java则是强制在代码中的;但是,从另一个角度说,Checked Exception让代码编写变得非常麻烦,这导致的一个情况便是许多人在写代码时,自定义的异常全都是RuntimeException(因为不需要标记),每个方法也都是throws Exception的(这样代码中就不需要try...catch了),此时Checked Exception特性也基本形同虚设,除了造成麻烦以外几乎没有带来任何好处。
我之前常说:一个特性如果要被人广泛接受,那它一定要足够好用。现在如Scala和Grovvy等为Java设计的语言中都放弃了Checked Exception,这也算是从侧面印证了Checked Exception的尴尬境地吧。
而Checked Exception对于如今Lambda或闭包来说,在我看来更像是一种硬伤。为什么这么说?举个例子吧,假如有这么一个map方法,可以把一个数组映射成另一个类型数组:
public R[] map(T[] array, Func<T, R> mapper) { ... }
好,那么比如这样一个需求:给定一个字符串数组,保存着文件名,要求获得它的标准路径。从表面上看来,我们可以这样写:
map(files, #(String f)(new File(f).getCanonicalPath())
但事实上,这么做无法编译通过。为什么?因为getCanonicalPath方法会抛出IOException,我们在调用时必须显式地使用 try...catch进行处理。那么这段代码该怎么写?还真没法写。如果没有Checked Exception的话(如C#),我们还可以这么做(处理第一个抛出的IOException):
try { map(files, #(String f)(new File(f).getCanonicalPath()) catch (IOException ex) { ... }
但是,如果我们要写出之前那种“漂亮”的写法,就不能使用Func<T, R>而必须是这样的接口类型:
public interface FuncThrowsIOException<T, R> { R invoke(T arg) throws IOException; }
或者是这样的“匿名函数类型”:
#String(String)(throws IOException) // toCanonicalPath = #(String f)(new File(f).getCanonicalPath())
但是,作为Lambda和闭包的常用场景,如map,filter,fold等“函数式”元素,是不可能为某种特定的“异常类型”而设计的——异常类型千变万化,难道这也要用throws Exception来进行“统一处理”吗?Java虽然已经支持对异常类型的“推断”,但Checked Exception还是对Lambda和闭包的适用性造成了很大影响。
因此,我认为Checked Exception是一个“硬伤”。
其他
Java的Lambda和闭包还有一些特性,例如参数的“泛化”:
#boolean(Integer) f = #(Number n)(n.intValue() > 0);
由于Number是Integer的基类,因此我们可以使用Number来构造一个接受Integer参数的匿名函数类型。由于示例较少,我还不清楚这个特性的具体使用场景和意义所在——不过我猜想,在Java中可能允许这样做吧:
#boolean(Number) f = #(Number n)(n.intValue() > 0); #boolean(Integer) f1 = f; // cast implicitly or explicitly
此外还有一些特性,例如与MethodHandle类型的转化,我就没有特别的看法了。
文章来源:http://blog.zhaojie.me/2010/06/first-version-of-lambda-and-closures-in-java-7.html
发表评论
-
beanshell简介
2011-01-04 17:49 1247我们知道,现在有很多脚本语言,大家平时使用的比较多的包括Per ... -
Eclipse编辑XML自动提示
2010-08-26 11:12 1236IED Eclipse Java EE IDE for Web ... -
JAVA对象怎样实现对一个方法的调用的?
2010-07-18 14:00 799举个例子: public class E ... -
Java中native方法学习
2010-07-18 00:05 1008Java不是完美的,Java的不足除了体现在运行速度上要比传统 ... -
Java中的A*(A star)寻径实现,最短路径的查找算法
2010-06-24 17:17 4899据我个人所知,目前流 ... -
正则表达式(根据Tag查询Html内容)
2010-06-24 17:08 1518使用正则表达式查询一段Html中的Title标签,包括内容!! ... -
类集框架的完整结构
2010-06-23 22:32 1033类集框架的几大接口:Collection,Map,Iterat ... -
java jvm 参数 -Xms -Xmx -Xmn -Xss 调优总结
2010-06-22 08:09 1074常见配置举例 堆大小设置 JVM 中最大堆大小有三方面限制: ... -
System.gc()
2010-06-19 22:18 1525int length = 3; Set<Sky&g ... -
各种语言禁止缓存的方法
2010-06-18 17:53 628HTML: <META HTTP-EQUIV=&q ... -
linux配置java环境变量(详细)
2010-06-18 17:50 743现在用linux的朋友越来 ... -
Java注释(Annotation)
2010-06-18 10:25 931Java5中提供了新的注释(Annotation),能够为类提 ... -
session机制详解
2010-06-12 19:47 707虽然session机制在web应用程序中被采用已经很长时间了, ... -
JVM概述
2010-06-12 19:41 750定义 Java Virtual Machi ... -
web.xml详解
2010-06-12 19:38 606部署描述符实际上是一个XML文件,包含了很多描述servlet ...
相关推荐
* lambda 表达式的闭包:lambda 表达式可以捕获外部变量,并将其作为闭包的一部分。 * 递归算法的优点:递归算法可以将复杂的问题分解成更小的子问题,从而使得问题变得更易解决。 * 递归算法的缺点:递归算法可能会...
Java 8 引入的 Lambda 表达式是 Java 编程语言的重大变革之一,它允许以更简洁的方式表示单方法接口的实现,极大地增强了 Java 语言的表达能力,尤其是结合了函数式接口、Stream API 和其他新特性后。接下来,我们将...
例如,一个接受两个整数并返回它们之和的Lambda表达式可以写作: ```csharp (int x, int y) => x + y; ``` 2. **多行Lambda表达式** 当Lambda表达式需要多行逻辑时,需要使用大括号包裹。例如: ```csharp ...
在C#中,Lambda表达式通常与委托类型关联,使得编写简洁的事件处理程序或 LINQ 查询成为可能。 ### 2. Lambda表达式语法 Lambda表达式的语法有两种形式:一种是表达式形式,另一种是语句形式。表达式形式的Lambda...
Lambda表达式可以使用与其相同范围scope内的变量,这个引入符的作用就是表明,其后的lambda表达式以何种方式使用(正式的术语是“捕获”)这些变量(这些变量能够在lambda表达式中被捕获,其实就是构成了一个闭包)...
Java8与Scala中的Lambda表达式深入讲解 Lambda表达式是函数式编程的基本组成部分,许多现代编程语言都把它作为关键部分集成在语言中。Java8终于要支持Lambda表达式!在这篇文章中,我们将深入讲解Java8与Scala中的...
例如,使用Lambda表达式可以实现匿名函数、函数对象、闭包等高级编程概念。 在实际应用中,Lambda表达式可以用来实现各种函数式编程的需求,如图形处理、数据分析、算法实现等等。同时,Lambda表达式也可以与STL算...
此外,Lambda表达式也可以与`QVector`、`QList`等容器结合,用于高效地迭代和操作数据集合,如`std::transform`和`std::for_each`算法: ```cpp QVector<int> numbers = {1, 2, 3, 4, 5}; std::transform(numbers....
在2013年发布的 JavaSE8 中包含一个叫做 Lambda Project 的计划,在 JSR-335 草案 中有描述。...在这篇文章中,将粗略的看一遍Java8的特性,并介绍 Lambda表达式。而且将试着放一些样例程序来解释一些概念和语法。
在Java中,接口中的默认方法和Lambda表达式是实现闭包的关键。 在Java 8中,引入了Lambda表达式来简化匿名内部类的使用,从而更好地支持闭包。Lambda表达式可以被视为没有名字的方法,它可以捕获和存储它被定义时...
查Lambda表达式资料时很容易被函数闭包、Lambda演算、形式系统这些深奥名词淹没而放弃学习,其实Lambda表达式就是匿名函数(annoymous function)——允许我们使用一个函数,但不需要给这个函数起名字。还是有点难懂...
Lambda表达式作为C++0x(即C++11)引入的重大新特性之一,极大地简化了创建函数对象的过程,使得在需要回调函数或自定义比较等场景下,代码更加简洁和直观。lambda表达式允许开发者以更自然的方式编写代码,无需显式...
Lambda表达式还可以与委托类型结合,用于事件处理。当添加事件处理程序时,可以直接使用Lambda表达式,而无需创建单独的方法。例如: ```csharp button.Click += (sender, e) => MessageBox.Show("Button clicked!")...
根据提供的文件信息,此文档是一本关于Java 8中Lambda表达式的书籍的一部分,具体书名为《Functional Programming in Java - Harnessing the Power of Java 8 Lambda Expressions》,作者是Venkat Subramaniam,出版...
C# 3.0引入Lambda表达式是与.NET Framework 3.5一起的,这一变化显著提高了代码的简洁性和可读性。 在C# 1.0和2.0中,如果想要将函数作为参数传递,需要定义委托类型,然后在方法中使用该委托类型定义参数,最后...
**第7章:Lambda与遗留代码** - **集成旧系统**:讨论了如何在不破坏现有系统架构的前提下,逐步引入Lambda表达式来改善代码质量。 - **代码重构**:提供了实用的策略和技巧,帮助开发者在保持代码稳定的同时,利用...
【C++ Lambda 表达式详解】 Lambda 表达式是 C++11 引入的一项重要特性,它提供了一种简洁的创建匿名函数的方法,这些函数可以用于各种场合,如函数对象、回调函数以及算法的自定义比较操作等。Lambda 表达式的语法...
在Java编程语言中,Lambda表达式是一种简洁、强大的功能,自Java 8开始引入,它使得函数式编程的概念得以实现。Lambda表达式的主要目标是简化处理匿名函数,即没有名字的函数,尤其在处理集合操作、事件处理以及多...
内容概要:python、lambda表达式的用法举例。 采用.txt 文本格式。无需解压,直接使用。 总结了lambda表达式的六种常见用法: 1.命名使用 2.与map()、 filter()和 reduce()等高阶函数配合 3.赋予key参数使用 4.直接...
lambda表达式可以访问lambda表达式块外的变量,这称为闭包。例如: int lamValue = 5; Func,int> sum = x => x+lamValue; 需要注意的是, lambda内部实现过程编译器会创建一个匿名类,它有一个构造函数来传递外部...