热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

新手小白学JAVALambda表达式

Lambda表达式1.函数式编程思想面向对象强调:万物节皆对象,我们做任何事情都需要通过对象函数式编程思想强调:尽量忽略面向对象的复杂语法,强调做什么,而不是通过什么去做所以,我们




Lambda表达式

1. 函数式编程思想


  1. 面向对象强调:万物节皆对象,我们做任何事情都需要通过对象
  2. 函数式编程思想强调:尽量忽略面向对象的复杂语法,强调做什么,而不是通过什么去做
    所以,我们先来完成一个简单的案例,感受下Lambda表达式是如何“直击要点”的~

2. 案例引入

需求:在多线程场景下,在控制台输出:多线程程序启动啦
思路1:创建自定义多线程类实现Runnble接口,创建对象启动
思路2:优化使用匿名内部类的方式来完成
思路3:使用Lambda表达式来完成

package cn.cxy.lambda;
/*本类用于lambda表达式入门
* 需求:在多线程场景下,在控制台输出:多线程程序启动啦*/
public class LambdaDemo {
public static void main(String[] args) {
//2.创建目标业务类对象
MyRunnable target = new MyRunnable();
//3.将目标业务类对象作为Thread类的构造参数传入
Thread t = new Thread(target);
//4.启动线程
t.start();
/*方案二:改进:使用匿名内部类的方式:*/
//5.使用匿名内部类的方式改进
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("多线程程序2启动啦");
}
}).start();
/*方案三:继续改进:使用lambda表达式的方式:*/
new Thread( () -> {
System.out.println("多线程程序3启动啦");
}).start();
}
}
/*实现方案1:以接口实现类的方式实现*/
//1.定义多线程类实现Runnable接口,重写run()
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("多线程程序启动啦");
}
}

3. Lambda表达式的标准格式

我们先来分析下以匿名内部类方式编写代码的格式 :


  1. 方法参数列表处的参数为空,说明本方法执行时不需要传参
  2. 方法的返回值类型为void,说明这个方法的执行并没有返回结果
  3. 方法体中的内容才是我们具体要做的业务

我们再来分析下以Lambda表达式方法编写代码的格式 :


  1. ()里面没有内容,我们可以把它看作是方法执行时不需要传参数,参数为空
  2. -> : 用箭头表示我们即将要做的事,也就是具体要做的业务
  3. { } : 我们可以把它看作是一个代码块代表了之前我们在方法体中需要写的业务内容
    在这里插入图片描述
    总结:Lambda表达式的标准格式为:(方法的形式参数)-> { 方法体 }
    1)如果有多个参数,参数之间用逗号隔开,如果没有参数,小括号里面为空
    2)-> 是一个固定的标准写法,使用的符号都是英文的,代表我们指向要操作的动作
    3){ } 里是我们具体要完成的业务,也就是我们方法的方法体

注意Lambda表达式的前提:接口+接口中有且仅有一个抽象方法


4.1 案例练习1:抽象方法无参数无返回值时:

创建接口:Animal

package cn.cxy.lambda;
//1.定义接口
public interface Animal {
//2.定义接口中没有参数也没有返回值的抽象方法
void eat();
}

创建接口的实现类:AnimalImpl

package cn.cxy.lambda;
//3.创建接口的实现类并实现方法
public class AnimalImpl implements Animal{
@Override
public void eat() {
System.out.println("小动物吃啥都行~");
}
}

创建测试类:TestAnimal

package cn.cxy.lambda;
//4.创建测试类
public class TestAnimal {
public static void main(String[] args) {
/*方案1:创建接口实现类对象调用*/
//6.1创建接口的实现类对象【多态对象】
Animal a = new AnimalImpl();
//6.2调用本类的getAnimal(),并把刚刚创建的多态对象传入
getAnimal(a);//小动物吃啥都行~
/*方案2:使用匿名内部类的方式来调用*/
//7.直接调用getAnimal(),参数处以创建匿名内部类的方式来完成
getAnimal(new Animal() {
@Override
public void eat() {
System.out.println("小动物现在都想吃小苹果~");
}
});
/*方案3:使用Lambda表达式来完成
* eat()没有参数,小括号为空,指向eat()里实际要执行的一句打印语句 */
getAnimal( () -> {
System.out.println("Lambda表达式的方式,小动物们都惊呆了~");
});
}
//5.创建测试类中的方法getAnimal()
public static void getAnimal(Animal a){
a.eat();
}
}

4.2 案例练习2:抽象方法有参数无返回值时:

创建接口:Fruit

package cn.cxy.lambda;
//1.创建接口
public interface Fruit {
//2.创建接口中带参数的抽象方法
void getKind(String s);
}

创建接口测试类FruitImpl:

package cn.cxy.lambda;
//3.创建接口的实现类并实现抽象方法
public class FruitImpl implements Fruit{
@Override
public void getKind(String s) {
System.out.println("参数s是:"+s);
System.out.println("我是一个大桃子~");
}
}

创建测试类TestFruit:

package cn.cxy.lambda;
//4.创建测试类进行测试
public class TestFruit {
public static void main(String[] args) {
/*方案1:创建接口实现类对象调用*/
//6.1创建接口的实现类对象【多态对象】
Fruit f = new FruitImpl();
//6.2调用本类的getFruit(),并把刚刚创建的多态对象传入
getFruit(f);
/*方案2:使用匿名内部类的方式来调用*/
//7.直接调用getFruit(),参数处以创建匿名内部类的方式来完成
getFruit(new Fruit() {
@Override
public void getKind(String s) {
System.out.println("参数s是:"+s);
System.out.println("我是一个大橙子~");
}
});
/*方案3:使用Lambda表达式来完成
* eat()没有参数,小括号为空,指向eat()里实际要执行的一句打印语句 */
getFruit( (String s) -> {
System.out.println("参数s是:"+s);
System.out.println("我是一颗大草莓");
});
}
//5.创建测试类的方法,需要传入接口对象,并且调用接口的功能
public static void getFruit(Fruit f){
f.getKind("猜猜我是什么水果?");
}
}

4.3 案例练习3:抽象方法有参数有返回值时:

创建接口:Student

package cn.cxy.lambda;
//1.创建接口
public interface Student {
//2.创建接口中带参数并且有返回值的抽象方法
int scoreCount(int a,int b,int c);
}

创建接口的实现类:

package cn.cxy.lambda;
//3.创建接口的实现类并实现抽象方法
public class StudentImpl implements Student{
@Override
public int scoreCount(int a, int b, int c) {
return a+b+c;
}
}

创建测试类TestStudent:

package cn.cxy.lambda;
//4.创建测试类进行测试
public class TestStudent {
public static void main(String[] args) {
/*方案1:创建接口实现类对象调用*/
//6.1创建接口的实现类对象【多态对象】
Student s = new StudentImpl();
//6.2调用本类的getFruit(),并把刚刚创建的多态对象传入
getScore(s);
/*方案2:匿名内部类的方式来调用也不简单,故此直接使用Lambda表达式来完成:
* 调用本方法时,将下方的参数60 70 80 作为参数传入*/
//7.直接使用Lambda表达式进行优化
getScore((int x,int y,int z) ->{
return x+y+z;//scoreCount()正常返回方法的返回值,交给下方的score变量来保存
});
}
//5.创建测试类的方法,需要传入接口对象,并且调用接口的功能
public static void getScore(Student s) {
int score = s.scoreCount(60, 70, 80);
System.out.println("总分为:"+score);
}
}

5. Lambda表达式的省略模式


  1. 在TestStudent测试类中,我们来学习Lambda表达式的简写形式1:

/*Lambda表达式的省略模式1:
* 参数的类型可以省略,但注意,如果有多个参数,不能只省略一个*/
//getScore((int x,int y,int z) ->{//之前的写法
//getScore((x,int y, int z) ->{//会报错
getScore((x,y,z) ->{//现在省略了所有参数的类型
return x+y+z;//scoreCount()正常返回方法的返回值,交给下方的score变量来保存
});

结论:参数的类型可以省略,但注意,如果有多个参数,不能只省略一个


  1. 在TestFruit测试类中,我们来学习Lambda表达式的简写形式2:

/*Lambda表达式的省略模式2:
* 如果方法的参数有且只有一个,参数的小括号可以省略*/
//getFruit( (String s) -> {//之前的写法,现在省略的参数的类型与小括号
getFruit( s -> {
System.out.println("参数s是:"+s);
System.out.println("我是一颗大草莓");
});

结论:如果方法的参数有且只有一个,参数的小括号可以省略


  1. 在TestAnimal测试类中,我们来学习Lambda表达式的简写形式3:

/*Lambda表达式的省略模式3:
* 如果大括号里的方法体只有一句,可以省略大括号和分号*/
getAnimal( () ->
System.out.println("Lambda表达式的方式,小动物们都惊呆了~")
);

结论;如果大括号里的方法体只有一句,可以省略大括号和分号


  1. 在TestStudent测试类中,我们来学习Lambda表达式的简写形式4:

/*Lambda表达式的省略模式4:
* 如果方法体只有一句,大括号与分号可以省略
* 除此之外,如果方法用关键字return返回返回值,return也需要一起省略掉*/
getScore((x,y,z) -> x+y+z );

结论;如果方法体里有return用来返回返回值,return也需要一起省略掉


6. Lambda表达式的注意事项:


  1. 必须是有一个接口,并且接口中只有一个抽象方法时使用
  2. 使用表达式时必须要有上下文环境推导出Lambda实际代表的接口

package cn.cxy.lambda;
public class TestLambda {
public static void main(String[] args) {
/*方式1:匿名内部类*/
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程启动啦");
}
}).start();
/*方式2:Lambda表达式写法1:根据局部变量r的类型推导出Lambda代表的接口*/
Runnable r = () -> System.out.println("用引用类型变量推断Lambda表示的是哪个接口");
new Thread(r).start();
/*方式3:Lambda表达式写法2:根据调用Thread(Runnable)方法的参数类型推导出Lambda代表的接口*/
new Thread(()-> System.out.println("Lambda方式线程启动啦")).start();
}
}

  1. 匿名内部类与Lambda表达式的区别/使用场景:
    1)不论被调用方法的参数是接口/抽象类/实体类,匿名内部类的形式均可以使用
    但是Lambda表达式只能是被调用方法参数为接口的时候使用
    2)不论接口里有几个抽象方法,都可以使用匿名内部类的形式
    但是Lambda表达式只支持接口中有且仅有一个抽象方法的情况
    3)实现原理不同:匿名内部类生效后会多产生一个额外单独的内部类字节码文件
    而Lambda表达式只有一个字节码文件
    在这里插入图片描述

创建接口:

package cn.cxy.lambda;
//1.创建接口与接口中的抽象方法
public interface Inter {
void eat();
}

创建抽象类:

package cn.cxy.lambda;
//2.创建抽象类与抽象类中的方法
public abstract class abstractClass {
abstract void sleep();
public void sleep2(){
System.out.println("一天要睡够8小时哦~");
}
}

创建普通类:

```java
package cn.cxy.lambda;
//3.创建普通实体类与类中的方法
public class normalClass {
public void play(){
System.out.println("最爱玩的就是代码啦~");
}
}

创建测试类:

package cn.cxy.lambda;
public class TestAnonymousAndLambda {
public static void main(String[] args) {
useFunction1(new Inter() {
@Override
public void eat() {
System.out.println("吃火锅~");
}
});
useFunction2(new abstractClass() {
@Override
void sleep() {
System.out.println("睡10个小时吧~");
}
});
useFunction3(new normalClass() {
@Override
public void play() {
System.out.println("代码写累了,完会游戏吧~");
}
});
useFunction1(()-> System.out.println("我是接口形式"));
//useFunction2(()-> System.out.println("我是抽象类的形式"));//会报错,不支持抽象类
//useFunction3(()-> System.out.println("我是普通实体类的形式"));//会报错,不支持普通类
}
public static void useFunction1(Inter i) {
i.eat();
}
public static void useFunction2(abstractClass a) {
a.sleep();
}
public static void useFunction3(normalClass n) {
n.play();
}
}


推荐阅读
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 从零学Java(10)之方法详解,喷打野你真的没我6!
    本文介绍了从零学Java系列中的第10篇文章,详解了Java中的方法。同时讨论了打野过程中喷打野的影响,以及金色打野刀对经济的增加和线上队友经济的影响。指出喷打野会导致线上经济的消减和影响队伍的团结。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • 面向对象之3:封装的总结及实现方法
    本文总结了面向对象中封装的概念和好处,以及在Java中如何实现封装。封装是将过程和数据用一个外壳隐藏起来,只能通过提供的接口进行访问。适当的封装可以提高程序的理解性和维护性,增强程序的安全性。在Java中,封装可以通过将属性私有化并使用权限修饰符来实现,同时可以通过方法来访问属性并加入限制条件。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 多维数组的使用
    本文介绍了多维数组的概念和使用方法,以及二维数组的特点和操作方式。同时还介绍了如何获取数组的长度。 ... [详细]
  • 数组的排序:数组本身有Arrays类中的sort()方法,这里写几种常见的排序方法。(1)冒泡排序法publicstaticvoidmain(String[]args ... [详细]
  • (三)多表代码生成的实现方法
    本文介绍了一种实现多表代码生成的方法,使用了java代码和org.jeecg框架中的相关类和接口。通过设置主表配置,可以生成父子表的数据模型。 ... [详细]
author-avatar
簕竹仔_591
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有