java 8 Lambda表达式(翻译自Stackoverflow)
(原文链接)Lambda只能作用于一个只有一个抽象方法的函数式接口(Function Interface),不过函数式接口可以有任意数量default或static修饰的方法(因此,它们有时也被当做单抽象方法类型接口或者说是SAM类型接口)
- interface Foo1 {
- void bar();
- }
- interface Foo2 {
- int bar(boolean baz);
- }
- interface Foo3 {
- String bar(Object baz, int mink);
- }
- interface Foo4 {
- default String bar() { // default so not counted
- return "baz";
- }
- void quux();
- }
当我们声明一个函数式接口,可以添加上@FunctionalInterface声明符.这并没有什么特别的效果,只是添加了这个声明符的接口如果不是函数式的,那么编译器便会报错,因此它实际是一个提醒,告诉我们这个接口不应该被修改(被添加更多的抽象方法).
- @FunctionalInterface
- interface Foo5 {
- void bar();
- }
- @FunctionalInterface
- interface BlankFoo1 extends Foo3 { // 从Foo3中继承抽象方法
- }
- @FunctionalInterface
- interface Foo6 {
- void bar();
- boolean equals(Object obj); // 重写Object的方法并不会被计入
- }
相反的,下面并不是一个函数式接口,因为它有超过一个的抽象方法
- interface BadFoo {
- void bar();
- void quux(); // <-- 第二个方法会导致禁用lambda,因为lambda会不知道到底要实现哪一个抽象方法
- }
下面同样不是一个函数式接口,因为它没有任何方法
- interface BlankFoo2 { }
注意下面的例子,假设你有一个接口
- interface Parent { public int parentMethod(); }
并且有一个子接口继承自它
- interface Child extends Parent { public int ChildMethod(); }
那么这个子类并不是一个函数式接口因为它有两个方法
Java 8同样在java.util.funciton中提供了一系列的通用函数式接口模版.例如内置接口Predicate<T>,它只包含一个方法,这个方法需要传入一个T类型参数,并返回一个布尔类型的值.
Lambda表达式
下面是Lambda表达式的基本结构
上图中fi是一个类的单例,就和实现了FuctionalInterface接口的匿名类一样,它以{System.out.println("Hello"); }这段方法体重写了接口的抽象方法,换而言之,上面的等同于
- FunctionalInterface fi = new FunctionalInterface() {
- @Override
- public void theOneMethod() {
- System.out.println("Hello");
- }
- };
Lambda表达式只是等效于一个匿名类,因为在Lambda表达式中,像this,super或toString()这些引用的是被调用的类本身,而不是新建的对象.
使用Lambda表达式你可以不必特别指定方法的名称---这也不需要,因为在一个函数式接口中有且只有一个抽象方法,这样java也只会重写这一个;
在这种情况下,Lambda表达式的类型并不确定(如重载方法),因此你可以在Lambda表达式中添加一个类型转换,来告诉编译器它应该是什么类型,就如下面例子一样
- Object fooHolder = (Foo1) () -> System.out.println("Hello");
- System.out.println(fooHolder instanceof Foo1); // returns true
如果函数式接口的方法有参数的话,那么参数名应该写在Lambda表达式括号中.这里并不需要声明参数或返回值的类型,因为java会自动从接口中获取(如果愿意声明的话,即使你声明了类型,java并也不会报错),因此,下面两个例子是等效的
- Foo2 longFoo = new Foo2() {
- @Override
- public int bar(boolean baz) {
- return baz ? 1 : 0;
- }
- };
- Foo2 shortFoo = (x) -> { return x ? 1 : 0; };
如果这个方法只有一个参数的话,参数外的括号也可以省略
- Foo2 np = x -> { return x ? 1 : 0; }; // 可以省略
- Foo3 np2 = x, y -> x.toString() + y //error 不可以省略
隐式返回
如果lambda表达式内的代码是一个java表达式而不是代码块的话,它会被当做一个方法返回的表达式值.因此下面两个例子是等效的
- IntUnaryOperator addOneShort = (x) -> (x + 1);
- IntUnaryOperator addOneLong = (x) -> { return (x + 1); };
访问局部变量(闭包值)
lambda表达式只是匿名类简写的语法糖,因此它也同样遵守访问作用域内局部变量的规则;局部变量必须被当做以final关键字修饰,在lambda表达式中无法被修改
- IntUnaryOperator makeAdder(int amount) {
- return (x) -> (x + amount); // 这是合法的,即使amount会超出作用域,因为amount没有被修改
- }
- IntUnaryOperator makeAccumulator(int value) {
- return (x) -> { value += x; return value; }; // error 将无法编译通过
- }
如果有必要以这种方式包含一个变量,应该用一个普通对象复制该变量,想了解更多请查看Java Closures with lambda expressions.;
接收Lambda表达式
因为lambda是一个接口的实现,所以没有特别需要做的当一个方法接收lambda作为参数时:任何一个接收函数式接口的方法都可以接收lambda表达式
- public void passMeALambda(Foo1 f) {
- f.bar();
- }
- passMeALambda(() -> System.out.println("Lambda called"));
Lambda表达式的类型
一个lambda表达式自己没有什么特定的类型,显然的是,参数的数量和类型,连同返回值的类型能够传达一些信息,这些信息能够唯一限制它将被赋予的类型.当lambda用以下一些方式被分配给一个函数式接口类型时,它将接收一个特定类型;
- 直接被赋值一个函数类型,比如 myPredicate = s -> s.isEmpty()
- 将它作为参数传递当需要一个函数类型参数时,比如 stream.filter(s -> s.isEmpty())
- 将它作为返回值从一个返回函数类型的方法中返回,比如 return s -> s.isEmpty()
- 将它转换为一个函数类型,比如 (Predicate<String>) s -> s.isEmpty()
直到任何一个赋值给函数类型操作执行前,lambda都没有一个确定类型.为了举例,可以看下这个lambda表达式 o -> o.isEmpty()
.相同的lambda表达式会被赋予不同的函数类型.
- Predicate<String> javaStringPred = o -> o.isEmpty();
- Function<String, Boolean> javaFunc = o -> o.isEmpty();
- Predicate<List> javaListPred = o -> o.isEmpty();
- Consumer<String> javaStringConsumer = o -> o.isEmpty(); // 返回值被忽略
- com.google.common.base.Predicate<String> guavaPredicate = o -> o.isEmpty();
现在他们被指定类型,这些例子展示了即使看起来一样的lambda表达式,但他们是完全不同的类型,不能够相互之间再被赋值;
java 8 Lambda表达式(翻译自Stackoverflow)的更多相关文章
- 深入探索Java 8 Lambda表达式
2014年3月,Java 8发布,Lambda表达式作为一项重要的特性随之而来.或许现在你已经在使用Lambda表达式来书写简洁灵活的代码.比如,你可以使用Lambda表达式和新增的流相关的API,完 ...
- Java 8 Lambda表达式10个示例【存】
PS:不能完全参考文章的代码,请参考这个文件http://files.cnblogs.com/files/AIThink/Test01.zip 在Java 8之前,如果想将行为传入函数,仅有的选择就是 ...
- Java 8 lambda表达式示例
例1.用lambda表达式实现Runnable 我开始使用Java 8时,首先做的就是使用lambda表达式替换匿名类,而实现Runnable接口是匿名类的最好示例.看一下Java 8之前的runna ...
- Java基础学习总结(44)——10个Java 8 Lambda表达式经典示例
Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里.在Ja ...
- Java 8 Lambda表达式
Java 8 Lambda表达式探险 http://www.cnblogs.com/feichexia/archive/2012/11/15/Java8_LambdaExpression.html 为 ...
- 深入浅出 Java 8 Lambda 表达式
摘要:此篇文章主要介绍 Java8 Lambda 表达式产生的背景和用法,以及 Lambda 表达式与匿名类的不同等.本文系 OneAPM 工程师编译整理. Java 是一流的面向对象语言,除了部分简 ...
- Java 8 Lambda 表达式
Lambda 是啥玩意 简单来说,Lambda 就是一个匿名的方法,就这样,没啥特别的.它采用一种非常简洁的方式来定义方法.当你想传递可复用的方法片段时,匿名方法非常有用.例如,将一个方法传递给另外一 ...
- Java 8 Lambda 表达式详解
一.Java 8 Lambda 表达式了解 参考:Java 8 Lambda 表达式 | 菜鸟教程 1.1 介绍: Lambda 表达式,也可称为闭包,是推动 Java 8 发布的最重要新特性. La ...
- 用Java 8 Lambda表达式实现设计模式:命令模式
在这篇博客里,我将说明如何在使用 Java 8 Lambda表达式 的函数式编程方式 时实现 命令 设计模式 .命令模式的目标是将请求封装成一个对象,从对客户端的不同类型请求,例如队列或日志请求参数化 ...
随机推荐
- 一个最简单的cell按钮点击回调
在cell.h定义 @property(nonatomic,strong)void(^pushType)(NSInteger); 在cell.m按钮点击时 _pushType(1):(举例) ...
- VS工程中的Windows.h
才发现这个Windows.h是有些奥秘的,不是随便引用就可以的. 1,C++工程,头文件引用要讲求一定顺序.如果cpp文件先引用a.h,再引用b.h,则后者自动包含a.h.这一点很重要. 2,Wind ...
- Django之反向生成url
首先新建一个项目test_url,项目包含一个名为app01的应用 在urls.py文件中生成如下内容 from django.conf.urls import url from django.sho ...
- thinkphp使用自带webserver
进入命令行,进入 tp5/public 目录后,输入如下命令:php -S localhost:8888 router.php 然后进行访问
- 前端-Useful Js Plugins
Validform.min.js:提供对表单的验证.提交等功能,具体可查阅相关文档,@Validform 示例: $("#id").Validform() ; WdatePicke ...
- Codeforces Round #398 (Div. 2)
Codeforces Round #398 (Div. 2) A.Snacktower 模拟 我和官方题解的命名神相似...$has$ #include <iostream> #inclu ...
- 豹哥嵌入式好讲堂:ARM Cortex-M调试过程探析(1)- 4线接口标准(JTAG)
大家好,我是豹哥,猎豹的豹,犀利哥的哥.今天豹哥给大家讲的是嵌入式调试里的接口标准JTAG. 在结束<ARM Cortex-M开发文件详解>系列文章之后,豹哥修整了一小段时间,但是讲课的心 ...
- Vue中,父组件向子组件传值
1:在src/components/child/文件夹下,创建一个名为:child.vue的子组件 2:在父组件中,设置好需要传递的数据 3:在App.vue中引入并注册子组件 4:通过v-bind属 ...
- 使用Python的requests库进行接口测试——session对象的妙用
from:http://blog.csdn.net/liuchunming033/article/details/48131051 在进行接口测试的时候,我们会调用多个接口发出多个请求,在这些请求中有 ...
- php+redis 学习 五 消息推送
<?php header('content-type:text/html;chaeset=utf-8'); /** * redis实战 * * 发布 * * @example php publi ...