什么是 Lambdas 表达式 ?

小驴来这里学习 2014-03-14 09:55:12
博客园上看到说,Java 8 中将加入Lambdas 表达式,这是个什么东西?

C#中有类似的功能吗?
...全文
275 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
thewitcher~ 2014-03-25
  • 打赏
  • 举报
回复
List<UserInfo> list = GetUserInfoList();
var a = list.where(p => p.Name == "zhangsan").ToList();
  • 打赏
  • 举报
回复
多了个s就不是Lambda了么?????
风一样的大叔 2014-03-20
  • 打赏
  • 举报
回复
Lambda工程是即将到来的Java8的一大主题,可能也是程序员们最期待已久的东西。随着Java lambdas的到来,还有一个有趣的东西被附带的加进了Java语言——defender(守卫者)方法。在这篇文章里,我的目的是要看看面纱后的东西 ——看看在运行时环境里lambdas是表现的,在方法的调度过程中涉及到哪些字节码指令。 尽管Java 8还没有正式发布,我们仍然可以下载各种平台上的早期预览版,在其上做简单的尝试。 你也想试试lambdas,是吗? 如果你熟悉其它的还有lambda表达式的编程语言,比如Groovy 或 Ruby,当第一眼看到Java里的lambda时,你也许会吃惊于它的不简单。在Java里,lambda表达式是“SAM”(Single Abstract Method)——一个含有一个抽象方法的接口(是的,现在接口里可以含有一个非抽象的方法,defender守卫方法)。 举个例子,大家熟知的Runnable接口就可以完美的被当作一个SAM类型: Runnable r = () -> System.out.println("hello lambda!"); ,这同样也适用于Comparable接口: Comparator<Integer> cmp = (x, y) -> (x < y) ? -1 : ((x > y) ? 1 : 0); 写成下面的样子也是一样的: Comparator<Integer> cmp = (x, y) -> { return (x < y) ? -1 : ((x > y) ? 1 : 0); }; 从中可以看出,单行的lambda表达式似乎是隐含了一个return语句。 那么,如何写一个能接受lambda表达式作为参数的方法呢?这样,你需要先把这个参数声明成函数式的接口,然后把lambda传入: interface Action { void run(String param); } public void execute(Action action){ action.run("Hello!"); } 一旦有了一个能将函数式接口作为参数的方法,我们就可以像下面这样调用它: execute((String s) -> System.out.println(s)); 还可以更简洁,这个表达式可以被替换成对一个方法的引用,因为它只是单个方法,而且它们的参数是相同的: execute(System.out::println); 然而,如果参数上有任何其它形式的变化,我们就不能直接引用方法,必须写全lambda表达式: execute((String s) -> System.out.println("*" + s + "*")); 我觉得这种语法还是相当漂亮的,现在,Java语言里有了一个非常优雅的lambdas解决方案,尽管Java里并不存在函数式类型。 JDK 8里的函数式接口 我们已经知道,lambda在运行时的表现形式是一个函数式的接口(或“SAM类型”)——只有一个抽象方法的接口。尽管JDK里已经有了不少这样的接口,例如Runnable 和 Comparable ,它们符合这种标准,但很显然,对于一个新API的进化来说,这是不够的。我们不可能所有地方都用Runnables接口。 在JDK 8 里有个新包,java.util.function,里面包含了很多函数式接口,都是提供在新API里使用的。我不想把它们全列出来——你们自己可以去看一下,学习一下这个新包 但看起来这个新包在不断的变化,经常性的一些新接口会出现而另一些会消失。例如,以前曾有过 java.util.function.Block 这个类,最新的版本中却没有它,我写这篇博客时使用的版本是: anton$ java -version openjdk version "1.8.0-ea" OpenJDK Runtime Environment (build 1.8.0-ea-b75) OpenJDK 64-Bit Server VM (build 25.0-b15, mixed mode) 我研究发现,它现在被 Consumer 接口替代,collection包里的所有新方法都将使用它。例如,Collection接口里定义了forEach方法,如下: public default void forEach(Consumer<? super T> consumer) { for (T t : this) { consumer.accept(t); } } Consumer接口里一个有趣地方是,它实际上定义了一个抽象方法——accept(T t)和一个defender方法——Consumer<T> chain(Consumer<? extend T> consumer)。这就是说你可以链式调用这个接口。我不确定如何使用,因为我在JDK包里没有找到chain(..)的使用方法说明。 我还发现所有的接口都使用了@FunctionalInterface运行时注注解注释。这个注释不仅仅是个说明,它还被javac使用来验证这个接口是否真是一个函数式接口,是否至少有一个抽象方法在里面。 所以,如果我们来编译下面的这段代码 @FunctionalInterface interface Action { void run(String param); void stop(String param); } 编译器会告诉我们: java: Unexpected @FunctionalInterface annotation Action is not a functional interface multiple non-overriding abstract methods found in interface Action 而下面的就能编译通过: @FunctionalInterface interface Action { void run(String param); default void stop(String param){} } 反编译lambdas 我对语法语言特征其实并不是很好奇,我更好奇的是这些特征在运行时的表现形式,这就是为什么我像往常一样,拿起我喜爱的javap工具,开始查看lambdas里的这些类的字节码。 目前(在Java 7之前),如果你想在Java里模拟lambdas,你需要定义一个匿名的内部类。它在编译后会产生一个具体的class。如果你在一段代码里定义了多个这样的类,你会发现这些类后面会跟着一些数字。那lambdas也会这样吗? 看看下面的这段代码: public class Main { @FunctionalInterface interface Action { Object run(String s); } public void action(Action action){ action.run("Hello!"); } public static void main(String[] args) { new Main().action((String s) -> System.out.print("*" + s + "*")); } } 编译产生了两个类文件:Main.class 和 Main$Action.class,没有匿名类实现里那样的序号化的类。那么,在Main.class里应该会有一些东西来代表我在main方法里定义的lambdas表达式的实现。 $ javap -p Main Warning: Binary file Main contains com.zt.Main Compiled from "Main.java" public class com.zt.Main { public com.zt.Main(); public void action(com.zt.Main$Action); public static void main(java.lang.String[]); private static java.lang.Object lambda$0(java.lang.String); } 啊哈!编译类了产生了lambda$0方法!使用-c -v指示符会让我们看到真正的字节码,以及常量池的定义。 main方法里显示,invokedynamic被用来调度这个调用: public static void main(java.lang.String[]); Code: 0: new #4 // class com/zt/Main 3: dup 4: invokespecial #5 // Method "":()V 7: invokedynamic #6, 0 // InvokeDynamic #0:lambda:()Lcom/zt/Main$Action; 12: invokevirtual #7 // Method action:(Lcom/zt/Main$Action;)V 15: return 而在常量池里,你也可以找到运行时的启动方法: BootstrapMethods: 0: #40 invokestatic java/lang/invoke/LambdaMetafactory.metaFactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; Method arguments: #41 invokeinterface com/zt/Main$Action.run:(Ljava/lang/String;)Ljava/lang/Object; #42 invokestatic com/zt/Main.lambda$0:(Ljava/lang/String;)Ljava/lang/Object; #43 (Ljava/lang/String;)Ljava/lang/Object; 你会发现到处都是在使用MethodHandle API,但我们现在不打算深入到里面。现在我们可以确认一点,我们的定义是引用了编译出来lambda$0方法。 我很好奇,如果我定义一个相同名字的静态方法会怎样——毕竟“lambda$0”是一个有效的标识符!于是,我定义了自己的lambda$0方法: public static Object lambda$0(String s){ return null; } 而编译失败,编译器不允许我在代码了拥有这个方法: java: the symbol lambda$0(java.lang.String) conflicts with a compiler-synthesized symbol in com.zt.Main 同时,如果我删掉这段定义lambdas表达式的代码,程序能顺利编译通过。这就是说,lambdas表达式在编译期间会比类里的其它数据早先分析,不过这只是我的猜测。 请注意:在这个例子中,lambda并没有去引用任何变量,也没有引用类内部的任何方法。这就是为什么产生的lambda$0方法是静态的。如果lambdas引用了上下文中的变量或方法,那生成的将是一个非静态方法。所以,不要被这个例子误导——lambdas是可以捕获上下文环境内容的! 总结lambdas 我可以毫无疑问的说,lambdas和伴随它一起的各种特征(守卫方法(defender) ,升级的集合类库)将很快给Java带来巨大的冲击。它的语法相当的简单,一旦程序员们意识到这些功能给开发效率带来的好处,我们将会看到大量的程序员都会运用这个功能。 看看lambdas会编译成什么样子,这对于我来说是一件非常有趣的事情,我很开心,因为我看到这些所有的invokedynamic指令调用都没有出现匿名内部类。 转自
q107770540 2014-03-18
  • 打赏
  • 举报
回复
java和c#的语法本来就很类似
  • 打赏
  • 举报
回复
引用 3 楼 vbfool 的回复:
[quote=引用 2 楼 Jelly1989 的回复:] [quote=引用 1 楼 feiyun0112 的回复:] Lambda 表达式 http://msdn.microsoft.com/zh-cn/library/bb397687.aspx ***************************************************************************** 签名档: http://feiyun0112.cnblogs.com/
它不是有个s吗,是lambda的复数版?[/quote] 怎么看怎么像是笔误啊[/quote] 和Lambdas的第一次亲密接触 为什么都无视那个S呢。。。
vbfool 2014-03-18
  • 打赏
  • 举报
回复
引用 2 楼 Jelly1989 的回复:
[quote=引用 1 楼 feiyun0112 的回复:] Lambda 表达式 http://msdn.microsoft.com/zh-cn/library/bb397687.aspx ***************************************************************************** 签名档: http://feiyun0112.cnblogs.com/
它不是有个s吗,是lambda的复数版?[/quote] 怎么看怎么像是笔误啊
wg5945 2014-03-18
  • 打赏
  • 举报
回复
总归要改点东西吧~~ 就像那个啥cos之类的~~ 名字什么的都一样就不好了~~
黄昏的投影 2014-03-18
  • 打赏
  • 举报
回复
C#、Java都有,百度一下,资料很多
  • 打赏
  • 举报
回复
引用 1 楼 feiyun0112 的回复:
Lambda 表达式 http://msdn.microsoft.com/zh-cn/library/bb397687.aspx ***************************************************************************** 签名档: http://feiyun0112.cnblogs.com/
它不是有个s吗,是lambda的复数版?
feiyun0112 2014-03-14
  • 打赏
  • 举报
回复
Lambda 表达式
http://msdn.microsoft.com/zh-cn/library/bb397687.aspx

*****************************************************************************
签名档: http://feiyun0112.cnblogs.com/

13,347

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 .NET技术前瞻
社区管理员
  • .NET技术前瞻社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧