哪位高人指点一下,C#中两个动态java8 lambda表达式 表达式有什么办法合并成一个? 谢谢!

C#中 Lambda表达式 与正则表达式的关系_百度知道
C#中 Lambda表达式 与正则表达式的关系
有点混淆,Lambda表示式就是正则表达式还是二者没有任何关联?
提问者采纳
八竿子打不着的关系lambda表达式是函数式语言的特性,c#利用自身动态编译的特性才实现这种效果的,可以用它写匿名函数等.像C,C++神马的都没有的.正则是各语言都有实现的,用来查询匹配等的
提问者评价
Thanks!了解清楚,总是混淆这两个
其他类似问题
lambda表达式的相关知识
其他2条回答
C#中 Lambda表达式 与正则表达式的关系 色。。图片。。。色。。。小说很精彩。。论。。坛。。。在。。。线...电。。影UDP。。UOP 9q
=& 是 Lambda 运算符 ,该运算符读为“goes to”。该 Lambda 运算符的左边是输入参数(如果有),右边包含表达式或语句块。d 是由 lambda表达式自动推断出来的,在这里d 就是一个Dinner实体啊
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁让天下没有难学的技术
Java8初体验(一)lambda表达式语法
Java8初体验(一)lambda表达式语法
感谢同事【天锦】的投稿。投稿请联系
本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘。因为本人也是刚刚开始学习Java8,所以文中肯定有错误和理解偏差的地方,希望大家帮忙指出,我会持续修改和优化。本文是该系列的第一篇,主要介绍Java8对屌丝码农最有吸引力的一个特性—lambda表达式。
java8的安装
工欲善其器必先利其器,首先安装JDK8。过程省略,大家应该都可以自己搞定。但是有一点这里强调一下(Windows系统):目前我们工作的版本一般是java 6或者java 7,所以很多人安装java8基本都是学习为主。这样就在自己的机器上会存在多版本的JDK。而且大家一般是希望在命令行中执行java命令是基于老版本的jdk。但是在安装完jdk8并且没有设置path的情况下,你如果在命令行中输入:java -version,屏幕上会显示是jdk 8。这是因为jdk8安装的时候,会默认在C:/Windows/System32中增加java.exe,这个调用的优先级比path设置要高。所以即使path里指定是老版本的jdk,但是执行java命令显示的依然是新版本的jdk。这里我们要做的就是删除C:/Windows/System32中的java.exe文件(不要手抖!)。
Lambda初体验
下面进入本文的正题–lambda表达式。首先我们看一下什么是lambda表达式。以下是维基百科上对于”Lambda expression”的解释:
a function (or a subroutine) defined, and possibly called, without being bound to an identifier。
简单点说就是:一个不用被绑定到一个标识符上,并且可能被调用的函数。这个解释还不够通俗,lambda表达式可以这样定义(不精确,自己的理解):一段带有输入参数的可执行语句块。这样就比较好理解了吧?一例胜千言。有读者反馈:不理解Stream的含义,所以这里先提供一个没用stream的lambda表达式的例子。
//这里省略list的构造
List&String& names = ...;
Collections.sort(names, (o1, o2) -& o1.compareTo(o2));
//这里省略list的构造
List&String& names = ...;
Collections.sort(names, new Comparator&String&() {
public int compare(String o1, String o2) {
pareTo(o2);
上面两段代码分别是:使用lambda表达式来排序和使用匿名内部类来排序。这个例子可以很明显的看出lambda表达式简化代码的效果。接下来展示lambda表达式和其好基友Stream的配合。
List&String& names = new ArrayList&&();
names.add(&TaoBao&);
names.add(&ZhiFuBao&);
List&String& lowercaseNames = names.stream().map((String name) -& {return name.toLowerCase();}).collect(Collectors.toList());
这段代码就是对一个字符串的列表,把其中包含的每个字符串都转换成全小写的字符串(熟悉Groovy和Scala的同学肯定会感觉很亲切)。注意代码第四行的map方法调用,这里map方法就是接受了一个lambda表达式(其实是一个java.util.function.Function的实例,后面会介绍)。
为什么需要Lambda表达式呢?在尝试回答这个问题之前,我们先看看在Java8之前,如果我们想做上面代码的操作应该怎么办。
先看看普通青年的代码:
List&String& names = new ArrayList&&();
names.add(&TaoBao&);
names.add(&ZhiFuBao&);
List&String& lowercaseNames = new ArrayList&&();
for (String name : names) {
lowercaseNames.add(name.toLowerCase());
接下来看看文艺青年的代码(借助):
List&String& names = new ArrayList&&();
names.add(&TaoBao&);
names.add(&ZhiFuBao&);
List&String& lowercaseNames = FluentIterable.from(names).transform(new Function&String, String&() {
public String apply(String name) {
return name.toLowerCase();
}).toList();
在此,我们不再讨论普通青年和文艺青年的代码风格孰优孰劣(有兴趣的可以去google搜索“命令式编程vs声明式编程”)。本人更加喜欢声明式的编程风格,所以偏好文艺青年的写法。但是在文艺青年代码初看起来看起来干扰信息有点多,Function匿名类的构造语法稍稍有点冗长。所以Java8的lambda表达式给我们提供了创建SAM(Single Abstract Method)接口更加简单的语法糖。
Lambda语法详解
我们在此抽象一下lambda表达式的一般语法:
(Type1 param1, Type2 param2, ..., TypeN paramN) -& {
statment1;
statment2;
//.............
return statmentM;
从lambda表达式的一般语法可以看出来,还是挺符合上面给出的非精确版本的定义–“一段带有输入参数的可执行语句块”。
上面的lambda表达式语法可以认为是最全的版本,写起来还是稍稍有些繁琐。别着急,下面陆续介绍一下lambda表达式的各种简化版:
1. 参数类型省略–绝大多数情况,编译器都可以从上下文环境中推断出lambda表达式的参数类型。这样lambda表达式就变成了:
(param1,param2, ..., paramN) -& {
statment1;
statment2;
//.............
return statmentM;
所以我们最开始的例子就变成了(省略了List的创建):
List&String& lowercaseNames = names.stream().map((name) -& {return name.toLowerCase();}).collect(Collectors.toList());
2. 当lambda表达式的参数个数只有一个,可以省略小括号。lambda表达式简写为:
param1 -& {
statment1;
statment2;
//.............
return statmentM;
所以最开始的例子再次简化为:
List&String& lowercaseNames = names.stream().map(name -& {return name.toLowerCase();}).collect(Collectors.toList());
3. 当lambda表达式只包含一条语句时,可以省略大括号、return和语句结尾的分号。lambda表达式简化为:
param1 -& statment
所以最开始的例子再次简化为:
List&String& lowercaseNames = names.stream().map(name -& name.toLowerCase()).collect(Collectors.toList());
4. 使用Method Reference(具体语法后面介绍)
//注意,这段代码在Idea 13.0.2中显示有错误,但是可以正常运行
List&String& lowercaseNames = names.stream().map(String::toLowerCase).collect(Collectors.toList());
Lambda表达式眼中的外部世界
我们前面所有的介绍,感觉上lambda表达式像一个闭关锁国的家伙,可以访问给它传递的参数,也能自己内部定义变量。但是却从来没看到其访问它外部的变量。是不是lambda表达式不能访问其外部变量?我们可以这样想:lambda表达式其实是快速创建SAM接口的语法糖,原先的SAM接口都可以访问接口外部变量,lambda表达式肯定也是可以(不但可以,在java8中还做了一个小小的升级,后面会介绍)。
String[] array = {&a&, &b&, &c&};
for(Integer i : Lists.newArrayList(1,2,3)){
Stream.of(array).map(item -& Strings.padEnd(item, i, '@')).forEach(System.out::println);
上面的这个例子中,map中的lambda表达式访问外部变量Integer i。并且可以访问外部变量是lambda表达式的一个重要特性,这样我们可以看出来lambda表达式的三个重要组成部分:
可执行语句
存放外部变量的空间
不过lambda表达式访问外部变量有一个非常重要的限制:变量不可变(只是引用不可变,而不是真正的不可变)。
String[] array = {&a&, &b&, &c&};
for(int i = 1; i&4; i++){
Stream.of(array).map(item -& Strings.padEnd(item, i, '@')).forEach(System.out::println);
上面的代码,会报编译错误。因为变量i被lambda表达式引用,所以编译器会隐式的把其当成final来处理(ps:大家可以想象问什么上一个例子不报错,而这个报错。)细心的读者肯定会发现不对啊,以前java的匿名内部类在访问外部变量的时候,外部变量必须用final修饰。Bingo,在java8对这个限制做了优化(前面说的小小优化),可以不用显示使用final修饰,但是编译器隐式当成final来处理。
lambda眼中的this
在lambda中,this不是指向lambda表达式产生的那个SAM对象,而是声明它的外部对象。
方法引用(Method reference)和构造器引用(construct reference)
前面介绍lambda表达式简化的时候,已经看过方法引用的身影了。方法引用可以在某些条件成立的情况下,更加简化lambda表达式的声明。方法引用语法格式有以下三种:
objectName::instanceMethod
ClassName::staticMethod
ClassName::instanceMethod
前两种方式类似,等同于把lambda表达式的参数直接当成instanceMethod|staticMethod的参数来调用。比如System.out::println等同于x-&System.out.println(x);Math::max等同于(x, y)-&Math.max(x,y)。
最后一种方式,等同于把lambda表达式的第一个参数当成instanceMethod的目标对象,其他剩余参数当成该方法的参数。比如String::toLowerCase等同于x-&x.toLowerCase()。
构造器引用
构造器引用语法如下:ClassName::new,把lambda表达式的参数当成ClassName构造器的参数 。例如BigDecimal::new等同于x-&new BigDecimal(x)。
吐槽一下方法引用
表面上看起来方法引用和构造器引用进一步简化了lambda表达式的书写,但是个人觉得这方面没有Scala的下划线语法更加通用。比较才能看出,翠花,上代码!
List&String& names = new ArrayList&&();
names.add(&TaoBao&);
names.add(&ZhiFuBao&);
names.stream().map(name -& name.charAt(0)).collect(Collectors.toList());
上面的这段代码就是给定一个String类型的List,获取每个String的首字母,并将其组合成新的List。这段代码就没办法使用方法引用来简化。接下来,我们简单对比一下Scala的下划线语法(不必太纠结Scala的语法,这里只是做个对比):
//省略List的初始化
List[String] names = ....
names.map(_.charAt(0))
在Scala中基本不用写lambda表达式的参数声明。
《Java SE 8 for the Really Impatient》
Java 8 Tutorial
Java 8 API doc
原创文章,转载请注明: 转载自
本文链接地址:
攻城师 at 淘宝码农,对各种新技术都会感兴趣。目前关注Scala,AngularJS和Netty
Latest posts by 一冰_天锦 ()
- 2014 年 4 月 11 日
- 2014 年 4 月 11 日
- 2014 年 4 月 11 日
(2 votes, average: 5.00 out of 5)
Loading...其他回答(2)
IQuerable&User& GetAll(predicate)
园豆:31046
索性我已经找到了,虽然有小bug不是很影响。
&&&您需要以后才能回答,未注册用户请先。什么时候使用linq语句,什么时候使用lambda表达式?
[问题点数:40分,结帖人yasire]
什么时候使用linq语句,什么时候使用lambda表达式?
[问题点数:40分,结帖人yasire]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
相关帖子推荐:
2010年 总版技术专家分年内排行榜第一2009年 总版技术专家分年内排行榜第一
2011年 总版技术专家分年内排行榜第二
2014年11月 .NET技术大版内专家分月排行榜第二2014年5月 .NET技术大版内专家分月排行榜第二2014年4月 .NET技术大版内专家分月排行榜第二2012年2月 多媒体/设计/Flash/Silverlight 开发大版内专家分月排行榜第二
2014年12月 .NET技术大版内专家分月排行榜第三2014年10月 .NET技术大版内专家分月排行榜第三2014年9月 .NET技术大版内专家分月排行榜第三2014年1月 .NET技术大版内专家分月排行榜第三2013年12月 .NET技术大版内专家分月排行榜第三2013年10月 .NET技术大版内专家分月排行榜第三2013年5月 .NET技术大版内专家分月排行榜第三2011年9月 .NET技术大版内专家分月排行榜第三2011年2月 .NET技术大版内专家分月排行榜第三2010年2月 .NET技术大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。您的位置: &
在C#中,委托和事件还有Lambada都是很重要的语法,在开发中可以提高效率。不过有大多人还不会使用或没有用过,这篇文章可以让大家有个参考。
  关于这个论题, 对此有比较深入的分析,可以参考。 比较了委托和C++指针的区别。
  .NET 中的委托确实和C/C++的函数指针非常相似。它是一个值类型,它包装了一个指向方法的引用。它的作用也是为了能够将方法和变量一样作为参数传递。委托的典型应用是控件的事件处理方法。很显然,一个控件在设计的时候没有办法知道当特定事件发生的时候,需要什么方法来处理,这就需要将方法作为参数传递给控件。在LINQ中,也大量用到了委托。
  声明一个委托要使用delegate关键字,如下:
delegate int Echo(string message);
  这句代码声明了一个委托类型,这个委托类型的实例可以接受参数为string,返回值为int型的函数。这个方法可以是对象的方法,也可以静态方法,还可以是匿名方法,只要方法的签名和返回值是和声明一致的。这和C的函数指针很像,但是函数指针仅仅包含函数入口地址,而委托是一个类型,它具有比函数指针更强的功能。其中一点就是当方法是实例方法的时候,这个方法可以获得对象的其他变量的值,文首的第二篇文章对此有详细介绍,不再赘述。第二点就是委托是支持多播的,也就是一串方法可以可以依次被执行。例如:
static int EchoOriginal(string message){
Console.WriteLine(message);
return 1;}static int EchoReverse(string message){
StringBuilder sb=new StringBuilder();
for(int i=message.Length-1;i&=0;i--)
sb.Append(message[i]);
Console.WriteLine(sb.ToString());
return -1;}
static void Main(string[] args){
Echo eo = EchoO
Echo er = EchoR
Echo all = eo +
eo("Hello world");
int i=all("Hello Delegate");
Console.WriteLine(i);}
  我们定义两个方法,这两个方法都符合Echo的声明,最后Echo的all实例可以接受两个委托,调用all的时候,eo,er会被一次钓鱼,返回值是最后一个委托的返回值。程序的输出是:
  Hello world
  Hello Delegate
  etageleD olleH
  事实上,方法并不需要和委托声明类型的签名完全一致,.net允许方法的返回值是继承自声明的返回值的类型,方法的参数类型是声明的参数的父类型。这就是.
  .NET的事件机制是以委托为基础的。事件机制有两部分组成,一部分是事件发布者,一部分是事件响应者。其实现原理就是由事件发布者声明一个委托对象,由事件响应者向那个委托挂载具体的处理方法,事件发布者在需要的时候调用这个委托,这样响应者的代码就会被执行。事实上,.NET也是这么做的。C#的event关键字就仅仅做了少量的工作,其中包括为类生成一个私有的delegate. event所支持的委托是有限制的委托,它的返回值必须是void,参数是两个,第一个是事件发生者,第二个参数是事件需要携带的参数。最简单的事件处理委托.net已经声明了:
public delegate void EventHandler(
Object sender,
EventArgs e )
  声明事件的基本方式是 event 委托类型事件名称;
  举个例子,有这样的类,每当找到一个奇数,他就会触发一个事件。我们的程序在接到这个事件的时候在屏幕输出一个提示。类的代码可以这样实现:
public class OddFinder
public event EventHandler FindO
public void Find(int from, int to)
for (int i = i &= i++)
if (i % 2 != 0)
if (FindOdd != null)
FindOdd(this, EventArgs.Empty);
  这个类很简单,展示了发起事件的基本方法。首先声明一个事件,指明这个事件处理函数的委托类型。在需要触发事件的时候,首先判断是否有事件处理函数挂载,然后调用这个委托即可。外部处理程序把事件处理程序挂载上去:
static void Main(string[] args){
OddFinder f = new OddFinder();
f.FindOdd += new EventHandler(f_FindOdd);
f.Find(1, 5);}static void f_FindOdd(object sender, EventArgs e){
Console.WriteLine("Found!");}
  这样程序运行后,就会在屏幕上输出3次Found!。如果需要在触发事件的时候,传递更多的信息给事件处理函数,比如当前找到的奇数是多少,那么就需要新建一个类继承自EventArgs,在这个类中可以添加一些需要的数据。 再声明一个委托,第二个参数为EventArgs类型即可。
  以上是基本的委托和事件的介绍,自.net 1.0开始就是如此,.net 2.0 引入了匿名方法,可以简化委托的某些操作。例如:
f.FindOdd += delegate(object sender, EventArgs e){
Console.WriteLine("Found!");};
  匿名方法使用delegate关键字加上参数表,最后是代码块来定义。它可以作为委托赋值给委托类型。它可以省去单独定义一个方法的麻烦。
  .net 3.0之后引入了Lambda表达式,它进一步简化了匿名方法的写法,使得在C#中,把函数作为参数传递变得更加简单自然,从而C#变得更加具有函数式语言的味道。关于函数式语言的进一步介绍,可以参考: 。 函数式语言的理论基础是Lambda Calulus,关于此可以参考 。
  Lambda表达式本质上还是匿名方法,它的一般形式是:(input parameters) =& expression
  左侧是参数列表,=&右侧是方法体,可以是一个表达式(expression lambda),也可以是大括号括起来的语句段(statement lambda)。它省略了delegate关键字,使得代码更加紧凑。例如:
n=&n%2==0;
  等价于:
delegate(int n){ return n%2==0;}
  expression lambda 广泛应用于LINQ,它可以用来构造,Expression Tree是LINQ的基础。可以通过动态构造Expression Tree来实现复杂的动态LINQ查询,不过这种方法虽然通用,对于数据库查询,使用起来和传统的拼接字符串相比还是很麻烦。下文将介绍微软的一个LINQ扩展,Dynamic LINQ。
上一篇:下一篇:

我要回帖

更多关于 nomos lambda 的文章

 

随机推荐