JDK新特性-Lambda表达式的神操作
一、Lambda表达式的介绍
Lambda表达式是 Java8 中最重要的新功能之一。使用 Lambda 表达
式可以替代只有一个抽象函数的接口实现,告别匿名内部类,代码看
起来更简洁易懂。Lambda表达式同时还提升了对集合、框架的迭代、
遍历、过滤数据的操作。lambda表达式可以替代只有一个抽象函数的接口实现,告别匿名内部类,代码看起来更简洁易懂
lambda表达式同时还提升了对集合、框架的迭代、遍历、过滤数据的操作
lambda可以极大的减少代码冗余,同时代码的可读性要好过冗长的内部类,匿名类
例如以前我们使用匿名内部类来实现代码:
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("running1 .....");
}
};
runnable.run();
使用lambda表达式实现更简洁的代码:
Runnable runnable3 = ()-> System.out.println("running2....");
runnable3.run();
lambda表达式语法:
LambdaParameters -> LambdaBody
args -> expr或者(object ... args)-> {函数式接口抽象方法实现逻辑}
1、()参数的个数,根据函数式接口里面抽象的参数个数来决定,当参数只有一个的时候,()可以省略
2、当expr逻辑非常简单的时候,{}和return可以省略
案例说明:
public static void main(String[] args) throws Exception {
Callable<String> c1 = new Callable() {
@Override
public String call() throws Exception {
return "muxiaonong";
}
};
System.out.println(c1.call());
Callable<String> c2 = ()->{return "muxiaonong2";};
System.out.println(c2.call());
//逻辑很简单的时候省略 {} 和 return
Callable<String> c3 = ()->"muxiaonong3";
System.out.println(c3.call());
}
二、Lambda表达式的特点
- 函数式编程
- 参数类型自动推断
- 代码量少,简洁
三、Lambda表达式案例
实现方式列表:
()->{}
()->{System.out.println(1);}
()->System.out.println(1)
()->{return 100;}
()->100
()->null
(int x)->{return x+1;}
(int x)->x+1
(x)->x+1
x->x+1
案例1:线程实现方式:
public static void main(String[] args) {
//匿名内部类方式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("runing1..........");
}
});
//Lambda表达式方式
new Thread(() -> {System.out.println("runing2.....");}).start();
}
案例2:集合遍历实现方式
public static void main(String[] args) {
List<String> list = Arrays.asList("java","python","scala","javascript");
//普通匿名内部类方式
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
//Lambda方式
Collections.sort(list,(a,b) -> a.length() - b.length());
list.forEach(System.out::println);
}
四、Lambda表达式的应用场景
重要的事情说三遍:任何有函数式接口的地方 * 3
什么是函数式接口: 只有一个抽象方法(Object类中的方法除外)的接口是函数式接口
五、Lambda表达式实际应用
5.1 无参实体类模拟
模拟数据库连接层:
@FunctionalInterface
public interface StudentDao {
void insert(Student student);
}
实体类
/** @Author mxn
* @Description 学生实体类
* @Date 10:19 2020/11/7
* @Param
* @return
**/
public class Student {
}
public static void main(String[] args) {
StudentDao sd1 = new StudentDao() {
@Override
public void insert(Student student) {
System.out.println("插入学生1");
}
};
StudentDao sd2 = (student)->{
System.out.println("student: "+student);
};
StudentDao sd3 = (Student student)-> System.out.println("student3:"+student);
sd1.insert(new Student()); //输出 插入学生1
sd2.insert(new Student());// 输出
sd3.insert(new Student());// 输出
}
5.2 有参实体类模拟
实体类
/** @Author mxn
* @Description
* @Date 10:26 2020/11/7
* @Param
* @return
**/
public class Teacher {
}
接口模拟层
@FunctionalInterface
public interface TeacherDao {
int get(Teacher teacher);
}
实现层
public static void main(String[] args) {
TeacherDao td1 = new TeacherDao() {
@Override
public int get(Teacher teacher) {
return 1;
}
};
TeacherDao td2 = (teacher)->{return 2;};
TeacherDao td3 = (Teacher teacher)->{return 3;};
TeacherDao td4 = (teacher)->4;
TeacherDao td5 = (Teacher teacher)->5;
System.out.println(td1.get(new Teacher()));//输出 1
System.out.println(td2.get(new Teacher()));//输出 2
System.out.println(td3.get(new Teacher()));//输出 3
System.out.println(td4.get(new Teacher()));//输出 4
System.out.println(td5.get(new Teacher()));//输出 5
}
六、函数式接口
Supplier:
代表一个输出
Consumer:
代表一个输入
BiConsumer:
代表两个输入
Function:
代表一个输入,一个输出(一般输入和输出是不同类型的)
UnaryOperator:
代表一个输入,一个输出(输入和输出是相同类型的)
BiFunction:
代表两个输入,一个输出(一般输入和输出是不同类型的)
BinaryOperator:
代表两个输入,一个输出(输入和输出是相同类型的)
在Java中提供了一系列的函数式接口,用来接受后续传入的逻辑,但是对输入和输出有要求
6.1 Supplier:代表一个输出
Supplier<String> s1 = ()->{return "muxiaonong";};
Supplier<String> s2 = ()->"muxiaonong2";
System.out.println(s1.get());//输出 muxiaonong
System.out.println(s2.get());//输出 muxiaonong2
6.2 Consumer:代表一个输入
Consumer<String> c11 = (str) -> System.out.println(str);
c11.accept("beijing");//输出 beijing
6.3 BiConsumer:代表两个输入
BiFunction<String,String,Integer> bf = (a,b)->a.length()+b.length();
System.out.println(bf.apply("大吉大利", "今晚吃鸡"));//输出一个字符串长度 8
6.4 Function:代表一个输入,一个输出
// Function<String,Integer> 用来接收后面的函数的实现,规定必须有一个输入(String)有一个输出(Integer)
Function<String,Integer> f1 = (str)->{return str.length();};
System.out.println(f1.apply("abcdefg"));//输出长度 7
七、方法的引用
- 方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法,方法引用提供了一种引用而不执行方法的方式,如果抽象方法的实现恰好可以使用调用另外一个方法来实现,就有可能可以使用方法引用
7.1 方法引用的分类
类型 | 语法 | 对应的lambda表达式 |
---|---|---|
静态方法引用 | 类名::staticMethod | (args) -> 类名.staticMethod(args) |
实例方法引用 | inst::instMethod | (args) -> inst.instMethod(args) |
对象方法引用 | 类名::instMethod | (inst,args) -> 类名.instMethod(args) |
构造方法引用 | 类名::new | (args) -> new 类名(args) |
7.2 静态方法引用
- 静态方法引用: 如果函数式接口的实现恰好可以通过 调用一个静态方法 来实现,那么就可以使用静态方法引用
/**
* @program: lambda
* @ClassName Test2
* @description:
* @author: muxiaonong
* @create: 2020-10-28 22:15
* @Version 1.0
**/
public class Test2 {
//无参静态方法
static String put(){
System.out.println("put.....");
return "put";
}
//有参静态方法
public static void getSize(int size){
System.out.println(size);
}
//有参 有返回值静态方法
public static String toUpperCase(String str){
return str.toUpperCase();
}
//两个入参,一个返回值静态方法
public static Integer getLength(String str,String str2){
return str.length()+str2.length();
}
public static void main(String[] args) {
//无参静态方法-普通调用
System.out.println(put());//输出put
//无参静态方法-原生调用
Supplier<String> s1 = ()-> Test2.put();
System.out.println(s1.get());//输出put
//无参静态方法-静态方法引用
Supplier<String> s2 = Test2::put;
System.out.println(s2.get());//输出put
//无参静态方法-内部类调用
Supplier<String> s3 = Fun::hehe;
System.out.println(s3.get()); //输出hehe
// 有参静态方法-静态方法引用
Consumer<Integer> c1 = Test2::getSize;
Consumer<Integer> c2 = (size)-> Test2.getSize(size);
c1.accept(123);
c2.accept(111);
//有参有返回值静态方法
Function<String,String> f1 = (str)->str.toUpperCase();
Function<String,String> f2 = (str)-> Test2.toUpperCase(str);
Function<String,String> f3 = Test2::toUpperCase;
Function<String,String> f4 = Test2::toUpperCase;
System.out.println(f1.apply("abc"));//输出 ABC
System.out.println(f2.apply("abc"));//输出 ABC
System.out.println(f3.apply("abc"));//输出 ABC
System.out.println(f4.apply("abc"));//输出 ABC
// 两个参数 一个返回值 函数式接口
BiFunction<String,String,Integer> bf = (a, b)->a.length()+b.length();
BiFunction<String,String,Integer> bf2 = Test2::getLength;
System.out.println(bf2.apply("abc", "def"));//输出 6
System.out.println(bf.apply("abc", "def"));//输出 6
}
//内部类
class Fun {
public static String hehe(){
return "hehe";
}
public static String toUpperCase(String str){
return str.toUpperCase();
}
}
}
7.3 实例方法引用
- 实例方法引用: 如果函数式接口的实现恰好可以通过调用一个实例的实例方法来实现,那么就可以使用实例方法引用
public class Test3 {
//实例无参方法
public String put(){
return "put...";
}
//实例有参方法
public void getSize(int size){
System.out.println("size:"+size);
}
//实例有参有返回值方法
public String toUpperCase(String str){
return str.toUpperCase();
}
public static void main(String[] args) {
//实例无参方法返回-普通调用
System.out.println(new Test3().put());//输出 put...
Supplier<String> s1 = ()->new Test3().put();
Supplier<String> s2 = ()->{return new Test3().put();};
Supplier<String> s3 = new Test3()::put;
System.out.println(s1.get());//输出 put...
System.out.println(s2.get());//输出 put...
System.out.println(s3.get());//输出 put...
//唯一的创建一个test3对象
Test3 test = new Test3();
Consumer<Integer> c1 = (size)->new Test3().getSize(size);
Consumer<Integer> c2 = new Test3()::getSize;
Consumer<Integer> c3 = test::getSize;
c1.accept(123);//输出 size:123
c2.accept(123);//输出 size:123
c3.accept(123);//输出 size:123
Function<String,String> f1 = (str)->str.toUpperCase();
Function<String,String> f2 = (str)->test.toUpperCase(str);
Function<String,String> f3 = new Test3()::toUpperCase;
Function<String,String> f4 = test::toUpperCase;
System.out.println(f1.apply("abc"));//输出 ABC
System.out.println(f2.apply("abc"));//输出 ABC
System.out.println(f3.apply("abc"));//输出 ABC
System.out.println(f4.apply("abc"));//输出 ABC
}
}
7.4 对象方法引用
- 对象方法引用: 抽象方法的第一个参数类型刚好是实例方法的类型,抽象方法剩余的参数恰好可以当做实例方法的参数。如果函数式接口的实现能由上面说的实例方法调用来实现的话,那么就可以使用对象方法引用
/** @Author mxn
* @Description //TODO 对象方法引用
* @Date 14:26 2020/11/7
* @Param
* @return
**/
public class Test4 {
public static void main(String[] args) {
Consumer<Too> c1 = (too)->new Too().foo();
c1.accept(new Too());//输出 foo
Consumer<Too> c2 = (Too too) ->new Too2().foo();
c2.accept(new Too());//输出 foo---too2
Consumer<Too> c3 = Too::foo;
c3.accept(new Too());//输出 foo
BiConsumer<Too2,String> bc = (too2,str)->new Too2().show(str);
BiConsumer<Too2,String> bc2 = Too2::show;
bc.accept(new Too2(),"abc");
bc2.accept(new Too2(),"def");
BiFunction<Exec,String,Integer> bf1 = (e,s)->new Exec().test(s);
bf1.apply(new Exec(),"abc");
BiFunction<Exec,String,Integer> bf2 = Exec::test;
bf2.apply(new Exec(),"def");
}
}
class Exec{
public int test(String name){
return 1;
}
}
class Too{
public Integer fun(String s){
return 1;
}
public void foo(){
System.out.println("foo");
}
}
class Too2{
public Integer fun(String s){
return 1;
}
public void foo(){
System.out.println("foo---too2");
}
public void show(String str){
System.out.println("show ---too2"+str);
}
}
7.5 构造方法引用
- 构造方法引用: 如果函数式接口的实现恰好可以通过调用一个类的构造方法来实现,那么就可以使用构造方法引用
/** @Author mxn
* @Description //TODO 构造方法引用
* @Date 14:27 2020/11/7
* @Param
* @return
**/
public class Test5 {
public static void main(String[] args) {
Supplier<Person> s1 = ()->new Person();
s1.get();//输出 调用无参的构造方法
Supplier<Person> s2 = Person::new;
s2.get();//输出 调用无参的构造方法
Supplier<List> s3 = ArrayList::new;
Supplier<Set> s4 = HashSet::new;
Supplier<Thread> s5 = Thread::new;
Supplier<String> s6 = String::new;
Consumer<Integer> c1 = (age)->new Account(age);
Consumer<Integer> c2 = Account::new;
c1.accept(123);// 输出 age 参数构造123
c2.accept(456);//输出 age 参数构造456
Function<String,Account> f1 = (str)->new Account(str);
Function<String,Account> f2 = Account::new;
f1.apply("abc");//输出 str 参数构造abc
f2.apply("def");//输出 str 参数构造def
}
}
class Account{
public Account(){
System.out.println("调用无参构造方法");
}
public Account(int age){
System.out.println("age 参数构造" +age);
}
public Account(String str){
System.out.println("str 参数构造" +str);
}
}
class Person{
public Person(){
System.out.println("调用无参的构造方法");
}
}
八、小结
- JAVA 8 引入 Lambda表达式是接收了函数式编程语言的思想,和指令式编程相比,函数式编程强调函数的计算比指令的执行重要。
- lambda表达式可以使代码看起来简洁,但一定程度上增加了代码的可读性以及调试的复杂性,所以在使用时应尽量是团队都熟悉使用,要么干脆就别用,不然维护起来是件较痛苦的事,今天的小知识就到这里了,有问题的小伙伴可以在下方进行留言,大家加油!
JDK新特性-Lambda表达式的神操作的更多相关文章
- 乐字节-Java8新特性-Lambda表达式
上一篇文章我们了解了Java8新特性-接口默认方法,接下来我们聊一聊Java8新特性之Lambda表达式. Lambda表达式(也称为闭包),它允许我们将函数当成参数传递给某个方法,或者把代码本身当作 ...
- Java8新特性-Lambda表达式是什么?
目录 前言 匿名内部类 函数式接口 和 Lambda表达式语法 实现函数式接口并使用Lambda表达式: 所以Lambda表达式是什么? 实战应用 总结 前言 Java8新特性-Lambda表达式,好 ...
- Java 8 新特性 - Lambda表达式
Lambda表达式 vs 匿名类既然lambda表达式即将正式取代Java代码中的匿名内部类,那么有必要对二者做一个比较分析.一个关键的不同点就是关键字 this.匿名类的 this 关键字指向匿名类 ...
- C#10新特性-lambda 表达式和方法组的改进
C# 10 中对Lambda的语法和类型进行了多项改进: 1. Lambda自然类型 Lambda 表达式现在有时具有"自然"类型. 这意味着编译器通常可以推断出 lambda 表 ...
- 大数据之路week06--day03(jdk8新特性 Lambda表达式)
为什么使用Lambda表达式?(做为初学者接触这个新的语法,会很懵逼,说道理,我在接触到这一块的时候,语法规则我看到了也很懵逼,因为这个和逻辑的关系不是很大,但就是作为一种新的语法出现,一时间很难接受 ...
- Java8新特性: lambda 表达式介绍
一.lambda 表达式介绍 lambda 表达式是 Java 8 的一个新特性,可以取代大部分的匿名内部类,简化了匿名委托的使用,让你让代码更加简洁,优雅. 比较官方的定义是这样的: lambda ...
- JDK8的新特性——Lambda表达式
JDK8已经发布快4年的时间了,现在来谈它的新特性显得略微的有点“不合时宜”.尽管JDK8已不再“新”,但它的重要特性之一——Lambda表达式依然是不被大部分开发者所熟练运用,甚至不被开发者所熟知. ...
- java8新特性——Lambda表达式
上文中简单介绍了一下java8得一些新特性,与优点,也是为本次学习java8新特性制定一个学习的方向,后面几篇会根据上文中得新特性一一展开学习.本文就从java8新特性中比较重要的Lambda表达式开 ...
- jdk8的新特性 Lambda表达式
很多同学一开始接触Java8可能对Java8 Lambda表达式有点陌生. //这是一个普通的集合 List<Employee> list = em.selectEmployeeByLog ...
随机推荐
- 硬核测试:Pulsar 与 Kafka 在金融场景下的性能分析
背景 Apache Pulsar 是下一代分布式消息流平台,采用计算存储分层架构,具备多租户.高一致.高性能.百万 topic.数据平滑迁移等诸多优势.越来越多的企业正在使用 Pulsar 或者尝试将 ...
- 整理requests和正则表达式爬取猫眼Top100中遇到的问题及解决方案
最近看崔庆才老师的爬虫课程,第一个实战课程是requests和正则表达式爬取猫眼电影Top100榜单.虽然理解崔老师每一步代码的实现过程,但自己敲代码的时候还是遇到了不少问题: 问题1:获取respo ...
- SQL实战——02. 查找入职员工时间排名倒数第三的员工所有信息
查找入职员工时间排名倒数第三的员工所有信息CREATE TABLE `employees` (`emp_no` int(11) NOT NULL,`birth_date` date NOT NULL, ...
- Python中matplotlib.pyplot.imshow画灰度图的多种方法
转载:https://www.jianshu.com/p/8f96318a153f matplotlib库的教程和使用方法此处就不累赘了,网上有十分多优秀的教程资源.此处直接上代码: def demo ...
- Arduino PID Library
Arduino PID Library by Brett Beauregard,contact: br3ttb@gmail.com What Is PID? PID是什么 From Wikipe ...
- P4821 [中山市选]生成树
题目链接 我们可以看一下题目中给的这张图. 首先,树是没有环的,所以我们要把所有的环上的边都删去一条. 我们可以现在每个五边形上删去一条边. 但删完之后我们会发现,里面还有一圈. 这时候,我们就要在这 ...
- 本文介绍如何使用 Docker Swarm 来部署 Nebula Graph 集群,并部署客户端负载均衡和高可用
本文作者系:视野金服工程师 | 吴海胜 首发于 Nebula Graph 论坛:https://discuss.nebula-graph.com.cn/t/topic/1388 一.前言 本文介绍如何 ...
- 实验三 HTML表格和表单的制作
实验三 HTML表格和表单的制作 [实验目的] 1.掌握表格的创建.结构调整与美化方法: 2.熟悉表格与单元格的主要属性及其设置方法: 3.掌握通过表格来进行网页页面的布局方法. [实验环境] 连接互 ...
- 多层级makefile
多层级makefile 当项目变大之后,需要多层级的makefile来编译,每个makefile的具体功能实现参考单源文件目录makefile.然后再在顶层目录写一个总的makefile来实现编译逻辑 ...
- pyquery 匹配NavigableString
pyquery 匹配NavigableString不像xpath那样精确找打匹配对象,只需匹配包含NavigableString的根节点