Java 8 特性 —— lambda 表达式
Lambda 表达式
Lambda表达式本质上是一个匿名方法。常见的一个例子是,在 IDEA + JDK8 的环境下按照Java传统的语法规则编写一个线程:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello World!");
}
});
IDEA会给出提示 Anonymous new Runnable() can be replaced with lambda less... (Ctrl+F1) ,说匿名内部类可以使用 Lambda 表达式替换。
使用 Lambda 表达式则只需要使用一句话就可代替上面使用匿名类的方式。
new Thread(() -> System.out.println("Hello World!"));
在这个例子中,传统的语法规则,我们是将一个匿名内部类作为参数进行传递,我们实现了Runnable接口,并将其作为参数传递给Thread类,这实际上我们传递的是一段代码,也即我们将代码作为了数据进行传递,这就带来许多不必要的“样板代码”。
在JDK8之前,Java是不支持函数式编程的,所谓的函数编程,即可理解是将一个函数(也称为“行为”)作为一个参数进行传递。通常我们提及得更多的是面向对象编程,面向对象编程是对数据的抽象(各种各样的POJO类),而函数式编程则是对行为的抽象(将行为作为一个参数进行传递)。在JavaScript中这是很常见的一个语法特性,但在Java中将一个函数作为参数传递这却行不通,好在JDK8的出现打破了Java的这一限制。
如上例所见,Lambda表达式一共有三部分组成:参数列表,箭头(->),以及一个表达式或语句块。
Lambda 表达式和函数式接口结合
什么场景下可以使用 Lambda 表达式?
能够接收 Lambda 表达式的参数类型,是一个只包含一个抽象方法的接口。只包含一个抽象方法的接口为“函数式接口”。
例如上例,Runnable 接口只包含一个抽象方法,所以它被称为“函数式接口”,所以它可以使用 Lambda 表达式来代替匿名内部类,作为 Thread 的构造参数。
函数式接口有无入参和有无返回值,可分为四种情形:
无参无返回值
有参无返回值
无参有返回值
有参有返回值
Lambda 表达式和这四种形式的函数式接口结合也就有四种情况;
无参无返回值
package com.boomoom; @FunctionalInterface
public interface InterfaceWithNoParam {
void run();
}
package com.boomoom;
import org.junit.Test;
public class FunctionInterfaceTest {
//匿名内部类
InterfaceWithNoParam param1 = new InterfaceWithNoParam() {
@Override
public void run() {
System.out.println("通过匿名内部类实现run()");
}
};
//Lambda表达式
//空括号表示无参
InterfaceWithNoParam param = () -> System.out.println("通过Lambda表达式实现run()") ;
@Test
public void testInterfaceWithNoParam() {
this.param.run();
this.param1.run();
}
}
通过Lambda表达式实现run()
通过匿名内部类实现run()
有参无返回值
package com.boomoom; @FunctionalInterface
public interface InterfaceWithParam {
void run(String s);
}
package com.boomoom;
import org.junit.Test;
public class FunctionInterfaceTest {
InterfaceWithParam param = new InterfaceWithParam() {
@Override
public void run(String s) {
System.out.println("通过" + s + "实现run(String)");
}
};
InterfaceWithParam param1 = (String s) -> System.out.println("通过" + s + "实现run(String)");
@Test
public void testInterfaceWithParam() {
this.param.run("匿名类");
this.param1.run("Lambda");
}
}
通过匿名类实现run(String)
通过Lambda实现run(String)
Lambda 表达式“(String) -> Sysout.out.println("通过" + s + "实现run(String)")”,左边传递的是参数,此处指明参数类型,也可不指定,通过上下文进行类型推导;但在有些情况下不能推导出参数类型(在编译时不能推导通常IDE会提示),此时则需要指明参数类型。我个人建议,任何情况下指明函数的参数类型。
哪种情况不能推导出参数类型呢?就是函数接口是一个泛型的时候。
@FunctionalInterface
public interface InterfaceWithParam<T> {
void run(T param);
}
无参有返回值
package com.boomoom; @FunctionalInterface
public interface InterfaceUnVoidWithNoParam {
String run();
}
package com.boomoom;
import org.junit.Test;
public class FunctionInterfaceTest {
InterfaceUnVoidWithNoParam interfaceUnVoidWithNoParam = new InterfaceUnVoidWithNoParam() {
@Override
public String run() {
return "Hello 匿名内部类!";
}
};
InterfaceUnVoidWithNoParam interfaceUnVoidWithNoParam1 = () -> "Hello Lambda!";
@Test
public void test() {
System.out.println("返回结果是:"+ this.interfaceUnVoidWithNoParam.run());
System.out.println("返回结果是:"+ this.interfaceUnVoidWithNoParam1.run());
}
}
返回结果是:Hello 匿名内部类!
返回结果是:Hello Lambda!
有参有返回值
package com.boomoom; @FunctionalInterface
public interface InterfaceUnVoidWithParam {
String run(Integer i);
}
package com.boomoom;
import org.junit.Test;
public class FunctionInterfaceTest {
InterfaceUnVoidWithParam interfaceWithParams = new InterfaceUnVoidWithParam() {
@Override
public String run(Integer integer) {
return String.valueOf(integer);
}
};
InterfaceUnVoidWithParam interfaceWithParams1 = (Integer integer) -> String.valueOf(integer);
@Test
public void test() {
System.out.println("您输入的是:"+ this.interfaceWithParams.run(1));
System.out.println("您输入的是:"+ this.interfaceWithParams1.run(2));
}
}
您输入的是:1
您输入的是:2
这四种基本情况已经大致清楚了,特别是需要弄清,什么时候可以使用 Lambda 表达式代替匿名内部类,也就是 Lambda 表达式的应用场景是函数式接口。Lambda 表达式这一新特性在 JDK8 中的引入,更大的好处则是集合 API 的更新,新增的 Stream 类库,使得我们在遍历使用集合时不再像以往那样不断地使用 for 循环。
JDK8 使用集合
示例:计算来自“hangzhou”的学生数量有多少。
在JDK8 前的代码:
for (Student student : studentList) {
if (student.getCity().equals("hangzhou")) {
count++;
}
}
JDK8 使用集合的正确姿势:
count = studentList.stream().filter((student -> student.getCity().equals("hangzhou"))).count();
API 的使用“难度”恰似提高了,实际只是不熟悉而已。传统迭代的方式需要阅读完整个循环才能明白代码逻辑,JDK8 通过流的方式则可以望文生义且代码量大大减小。
其中最为重要的是 Stream 流。Stream 的是通过函数式编程方式实现的在集合类上进行复杂操作的工具。关于 Stream 的用法和实现方式,详见此篇。使用JDK8的开发环境进行开发,尽量使用新的集合操作 API。
参考:https://www.cnblogs.com/yulinfeng/p/8452379.html
http://www.runoob.com/java/java8-lambda-expressions.html
https://www.cnblogs.com/yw0219/p/7302597.html
https://blog.csdn.net/io_field/article/details/54380200
Java 8 特性 —— lambda 表达式的更多相关文章
- 关于java新特性lambda表达式的理解即使用
Lambda 表达式的使用 1.举例: (o1,o2) -> Integer.compare(o1,o2); 2.格式: -> : lambda操作符 或 箭头操作符 ->左边 : ...
- Java 8 新特性 - Lambda表达式
Lambda表达式 vs 匿名类既然lambda表达式即将正式取代Java代码中的匿名内部类,那么有必要对二者做一个比较分析.一个关键的不同点就是关键字 this.匿名类的 this 关键字指向匿名类 ...
- Lambda 表达式,Java中应用Lambda 表达式
一.Lambda 表达式 简单来说,编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数. 链接:知乎 先举一个普通的 Python 例 ...
- Java8新特性-Lambda表达式是什么?
目录 前言 匿名内部类 函数式接口 和 Lambda表达式语法 实现函数式接口并使用Lambda表达式: 所以Lambda表达式是什么? 实战应用 总结 前言 Java8新特性-Lambda表达式,好 ...
- Java 终于有 Lambda 表达式啦~Java 8 语言变化——Lambda 表达式和接口类更改【转载】
原文地址 en cn 下载 Demo Java™ 8 包含一些重要的新的语言功能,为您提供了构建程序的更简单方式.Lambda 表达式 为内联代码块定义一种新语法,其灵活性与匿名内部类一样,但样板文件 ...
- 乐字节-Java8新特性-Lambda表达式
上一篇文章我们了解了Java8新特性-接口默认方法,接下来我们聊一聊Java8新特性之Lambda表达式. Lambda表达式(也称为闭包),它允许我们将函数当成参数传递给某个方法,或者把代码本身当作 ...
- java 8 中lambda表达式学习
转自 http://blog.csdn.net/renfufei/article/details/24600507 http://www.jdon.com/idea/java/10-example-o ...
- Java 8中Lambda表达式默认方法的模板方法模式,你够了解么?
为了以更简单的术语描述模板方法,考虑这个场景:假设在一个工作流系统中,为了完成任务,有4个任务必须以给定的执行顺序执行.在这4个任务中,不同工作流系统的实现可以根据自身情况自定义任务的执行内容. 模板 ...
- JDK新特性-Lambda表达式的神操作
一.Lambda表达式的介绍 Lambda表达式是 Java8 中最重要的新功能之一.使用 Lambda 表达 式可以替代只有一个抽象函数的接口实现,告别匿名内部类,代码看 起来更简洁易懂.Lambd ...
随机推荐
- 【转】JavaSE面试题目收集
1.是否可以从一个static方法内部发出对非static方法的调用? 不可以.当一个static方法被调用时,可能还没有创建任何实例对象,如果从一个static方法中发出对非static方法的调用, ...
- animate-queue和step-animate
Step-animate: 分为3部分:{配置},{step:function(){...},duration:1000} <div id="warpper" style=& ...
- 时空地图TimeGIS.com生成正交曲线网格
数值模拟中对数学物理方程的求解过程中经常需要生成网格,这里提供了一种方便的方法,只需要简单地勾画出区域的轮廓, 就可以生成相应的正交曲线网格,详情请访问 www.TimeGIS.com
- 章节十、4-CSS Classes---用多个CSS Classes定位元素
以下演示操作以该网址中的输入框为例:https://learn.letskodeit.com/p/practice 一.使用input[class=inputs]验证元素是否唯一 注意:使用“clas ...
- Vue2.0 --- vue-cli脚手架中全局引入JQ
第一步:安装jQuery npm/cmpn方式安装(默认安装1.7.X版本的JQ) npm/cnpm install jQuery 如果想安装更高版本的JQ那么可以选择在package.json文件下 ...
- CQOI2019(十二省联考)游记
CQOI2019(十二省联考)游记 Day -? 自从联赛爆炸,\(THUWC\)爆炸,\(WC\)爆炸(就没有不爆炸的)之后我已经无所畏惧... 听说是考\(4.5 h\)吗? Day -1 \(Z ...
- 添加python虚拟环境
在我centos上装有两个python版本 # 我在~/py3/目录下创建虚拟环境,该目录为python3的一个独立环境 [root@localhost /]# cd home [root@local ...
- pip "Cannot uninstall 'six'. It is a distutils installed project..." 解决方法
安装 mysql-connector-python 时,由于依赖包 six 之前已经安装过,但是不能自动更新到所需版本.有如下错误提示: pip "Cannot uninstall 'six ...
- Hive JDBC:java.lang.RuntimeException: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: root is not allowed to impersonate anonymous
今天使用JDBC来操作Hive时,首先启动了hive远程服务模式:hiveserver2 &(表示后台运行),然后到eclipse中运行程序时出现错误: java.sql.SQLExcepti ...
- 实现Kubernetes跨集群服务应用的高可用
在Kubernetes 1.3版本,我们希望降低跨集群跨地区服务部署相关的管理和运营难度.本文介绍如何实现此目标. 注意:虽然本文示例使用谷歌容器引擎(GKE)来提供Kubernetes集群,您可以在 ...