初步接触Java中的Lambda表达式
参考:
https://blog.csdn.net/w1764662543/article/details/89154408
https://blog.csdn.net/qq_31807385/article/details/82670505
https://www.cnblogs.com/nnxud/p/9827704.html
Java核心技术
Lambda表达式
- Lambda表达式简介
- 替代匿名内部类
- Lambda表达式的形式
- 方法引用
- 构造器引用
- 4种形式的Lambda表达式示例
- 变量作用域
- 函数式接口
- 函数式接口的定义
- 常见的函数式接口
- 示例
- Student类
- 测试代码
- @FunctionalInterface注解
第一次认真学习Lambda表达式,有错误还望指正。
Lambda表达式简介
可以将Lambda表达式理解为一个匿名函数;Lambda表达式允许将一个函数作为另外一个函数的参数; 我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码作为实参),也可以理解为函数式编程,将一个函数作为参数进行传递。
Lambda表达式只能用来简化仅包含一个抽象方法的接口的创建。
(1)只能是接口
否则报:Target type of a lambda conversion must be an interface
(2)只能是含有一个抽象方法的接口
否则报:Multiple non-overriding abstract methods found xxx
替代匿名内部类
lambda表达式用得最多的场合就是替代匿名内部类,而实现Runnable接口是匿名内部类的经典例子。
// 1.使用匿名类
Thread th1 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("2.匿名类的Runnable...");}
});
th2.start();
// 2.使用Lambda表达式
Runnable runnable = ()->System.out.println("线程启动了");
Thread th2 = new Thread(runnable);
// 调用th2.start()时会执行Lambda表达式的主体
th2.start();
// 3.更简洁的写法(但这种形式不如形式2方便人理解)
new Thread(()-> System.out.println("3.lambda表达式实现Runnable...")).start();
Lambda表达式的形式
([Lambda参数列表,即形参列表]) -> {Lambda体,即方法体}
使用 "->"将参数和实现逻辑分离;( ) 中的部分是需要传入Lambda体中的参数;{ } 中的部分,接收形参列表中的参数,完成一定的功能。->右边就相当于实现了接口中的抽象方法。此时Lambda表达式就是一个可用的接口实现类了。
若Lambda体中只有一条语句,return和大括号都可以省略不写。一定要注意,如果Lambda体中写了return,则必须加上{}。除此之外,Lambda表达式的形参列表的数据类型也可以省略不写,因为编译器可以通过上下文推断出数据类型。
package learnlambda;
// 自定义一个函数式接口
interface MyInterface{int add(int a,int b);
}
public class LambdaTest05 {public static void main(String[] args) {MyInterface mInstance1 = (x,y)-> x+y;System.out.println(mInstance1.add(2, 3));MyInterface mInstance2 = (x,y)-> { return x+y; };System.out.println(mInstance2.add(2, 3));}
}
方法引用
接口中要被实现的抽象方法的形参列表和返回值类型,必须与方法引用的方法的形参列表和返回值类型保持一致,否则不能使用方法引用。其实就是使用已存在的方法作为函数式接口中抽象方法的实现,因此已存在的方法的返回值类型与形参列表同接口中的抽象方法一致。
在方法引用中,使用操作符 “::”将类(或对象)与方法名分隔开来。值得注意的是,在使用方法引用给接口变量赋值的时候,并不需要给方法提供形式参数,而仅在调用的时候提供实参即可,这与先前的lambda表达式并无不同。
以下是方法引用的3种方式。
- •object::instanceMethod
- •Class::staticMethod
- •Class::instanceMethod
注意,使用方法引用和静态方法的概念不要弄混淆。
// 2. 比较器的示例// 1.以最简单的lambda表达式实现Comparator<Integer> com1 = (a,b)->{if(a>b){return 1;}else if(a<b){return -1;}else{return 0;}};// 2.使用Lambda表达式(这种形式的Lambda表达式必须指明形式参数)Comparator<Integer> com2 = (a,b)-> Integer.compare(a,b);// 3.使用方法引用(虽然Integer中的compare方法不是静态的)// 注意,赋值给接口变量,但并未指明形式参数Comparator<Integer> com3 = Integer::compare;// 调用方法int res1 = com1.compare(2, 3);int res2 = com2.compare(4, 5);int res3 = com3.compare(7,6);System.out.println("res1 = "+res1);System.out.println("res2 = "+res2);System.out.println("res3 = "+res3);
构造器引用
构造器引用的方法名为new,如Person::new 就表示Person构造器的一个引用。
Supplier<Student> supp = () -> new Student("zhao",23);
// 1.使用方法引用
Supplier<Student> supp2 = Student::new;
4种形式的Lambda表达式示例
Lambda表达式中,存在1)无参无返回值、2)有参无返回值、3)无参有返回值、4)有参有返回值,4种情况。
package learnlambda;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;
import java.util.stream.Stream;public class LambdaTest01 {public static void main(String[] args) {// 3.使用lambda表达式实现,不加{}// (1)无参无返回值
// new Thread(()-> System.out.println("3.lambda表达式实现Runnable...")).start();// (1)的另一种写法(更容易理解)Runnable runnable = ()->System.out.println("线程启动了"); Thread th1 = new Thread(runnable);th1.start();// (2)有参无返回值ArrayList<String> list = new ArrayList<>();list.add("zhao");list.add("qian");list.add("sun");list.add("li");list.forEach( (tele)->{System.out.println(tele);} );// (3)无参有返回值(当方法体只有一个return时,可以省略return)Random random = new Random(); Stream<Integer> stream = Stream.generate( () -> random.nextInt(100) );
// Stream<Integer> stream = Stream.generate(() ->{ return random.nextInt(100);});stream.forEach(t -> System.out.println(t));// (4)有参有返回值// 需求:按照字符串的长度排序String[] names ={"Bough","Paul","Peter","Alex"};// sort方法第2个参数需要传入一个实现了Comparator接口的对象// 而Comparator接口中含有抽象方法int compare(T o1, T o2);
// 重写该方法 则应当是:public int compare(String first, String second)
// { return first.length() - second.length();}// String[] names2 ={"Bough","Paul","Peter","Alex"};Comparator<String> com = (first,second) -> first.length()- second.length();Arrays.sort(names2,com);System.out.println(Arrays.toString(names2));// (4)的另一种简洁的写法Arrays.sort(names, (first,second)-> first.length() - second.length());System.out.println(Arrays.toString(names));}}
变量作用域
在lambda表达式中访问外围方法或类中的变量,由于使用lambda表达式的重点是延时执行,所以lambda表达式可能在外围方法调用返回很久之后才运行,而那时这个变量已经不存在了,所以lambda表达式必须存储自由变量的值。
如Java核心技术一书中的例子,在lambda表达式中访问外围方法或类中的变量。
public static void repeatMessage(String text,int delay){ActionListener listener = event ->{System.out.println(text);Toolkit.getDefaultToolkit().beep();};new Timer(delay,listener).start();
}
// 调用
repeatMessage("Hello",1000);
注意看,lambda 表达式中的变量 text,实际上是 repeatMessage 方法的一个参数变量。仔细想想,这里好像会有问题,尽管不那么明显。lambda 表达式的代码可能会在repeatMessage 调用返回很久以后才运行(个人理解:这可能主要是因为Lambda表达式的延时执行),而那时这个参数变量已经不存在了。
这里需要说明一下,自由变量指的是非lambda表达式的参数且不在lambda体中定义的变量。在lambda表达式中,只能引用值不会改变的变量。如果在lambda表达式中改变变量,并发执行多个动作时就会不安全。实际上,lambda表达式中捕获的变量必须是最终变量,最终变量的意思是这个变量初始化之后就不会再为它赋新值。
函数式接口
函数式接口的定义
如果一个接口只有一个抽象方法,那么就可以称该接口是函数式接口。当然,接口中既可以声明非抽象方法(Java8中可以声明static方法),也可以重写Object类的方法,如toString或clone,这些方法都有可能会让方法不再是抽象的。当需要这种接口的对象时,就可以提供一个lambda表达式。实际上,在Java中,对lambda表达式所能做的也只能是将其转换为函数式接口。值得注意的是,lambda表达式与函数式接口中的抽象方法的参数与返回值是一一对应的,即如果函数式接口中的抽象方法是有返回值,有参数的,那么要求Lambda表达式也是有返回值,有参数的(以此类推)。
常见的函数式接口
示例
Student类
package learnlambda;public class Student {private String name;private int age;public Student(){}public Student(String name,int age){this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}@Overridepublic String toString() {return "Student [ name :"+name+", age :"+age+"]";}
}
测试代码
package learnlambda;import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;public class LambdaTest03 {/*** 4种函数式接口的使用* @param args*/public static void main(String[] args) {// 1. 函数式接口的对象cons使用Lambda表达式相当于实现了Consumer接口的抽象方法accept// 所以当变量cons调用accept方法即在使用Lambda体。Consumer<String> cons = e->System.out.println("接收到的字符串 :"+e);cons.accept("woojopj");// 2.Supplier接口Supplier<Student> supp = () -> new Student("zhao",23);Student stu1 = supp.get();System.out.println(stu1.toString());Supplier<String> supp2 = ()-> "hello world".substring(2);String strSub = supp2.get();System.out.println("2.Supplier 的结果: "+strSub);// 3.Function接口Function<Student,String> func = (stu) ->{ return stu.getName();};Student stu2 =new Student("zhao",23);String str =func.apply(stu2);System.out.println("3.Function 的结果: "+str);// 4.Predicate接口// 判断学生年纪是否在20-30岁之间,否则返回错Predicate<Student> pre = (stu) ->{int age = stu.getAge();if( age>= 20 && age<=30){return true;}else{return false;}};System.out.println("4.Predicate 的结果 : "+pre.test(stu2));}
}
@FunctionalInterface注解
JDK1.8之后,如果是函数式接口,则可以添加 @FunctionalInterface注解表示这是一个函数式接口,但这并不是表示必须要使用该注解。根据定义,任何有一个抽象方法的接口都是函数式接口。不过使用 @FunctionalInterface注解确实是一个很好的做法。这样做有两个优点。 (1)如果你无意中增加了另一个非抽象方法, 编译器会产生一个错误消息。(2) 另外 javadoc 页里会指出你的接口是一个函数式接口。
@FunctionalInterface
interface MyInterface{int add(int a,int b);
}
初步接触Java中的Lambda表达式相关推荐
- 如何开始使用Java中的Lambda表达式
by Luis Santiago 路易斯·圣地亚哥(Luis Santiago) 如何开始使用Java中的Lambda表达式 (How to start working with Lambda Exp ...
- 如何在Java中使用Lambda表达式
如何在Java中使用Lambda表达式 Lambda表达式是Java 8新增的一个非常强大的特性.它使得函数式编程在Java中变得更加容易和直观. Lambda表达式的基础知识 在Java中,Lamb ...
- java中的lambda表达式学习
Lambda表达式是给函数式接口(SAM接口)的变量或形参赋值的表达式. Lambda表达式替代了原来使用匿名内部类的对象给函数式接口(SAM接口)的变量或形参赋值的形式. java提供了大量的函数式 ...
- Java中的lambda表达式如何理解——精简
✌️✌️✌️在写之前,我在考虑是否要写这篇文章,然而当我查阅"lambda表达式"的相关内容的时候,我发现大量的文章都出现了冗余的现象,文章的篇幅过于夸张,严重影响了大家阅读的兴趣 ...
- 通俗理解Java中的Lambda表达式
Lambda Lambda表达式支持将代码块作为方法参数, 允许使用更为简洁的方式实现抽象类或接口的抽象方法, 而不再是通过匿名内部类的方式, 它具有对某一方法重写或实现的功能; 接下来通过一个简单的 ...
- java lambda max_在Java中使用Lambda表达式查找Max
小编典典 该方法Comparator.comparing(-)旨在创建一个Comparator使用基于对象属性的订单进行比较的.当使用lambda表达式i -> i(这是(int i) -> ...
- 【java】理解和运用Java中的Lambda
1.概述 转载:理解和运用Java中的Lambda 前提 回想一下,JDK8是2014年发布正式版的,到现在为(2020-02-08)止已经过去了5年多.JDK8引入的两个比较强大的新特性是Lambd ...
- JAVA如何遍历arraylist数组,Java 程序使用Lambda表达式遍历ArrayList
Java 程序使用Lambda表达式遍历ArrayList 在此示例中,我们将学习在Java中使用lambda表达式遍历数组列表的每个元素. 要理解此示例,您应该了解以下Java编程主题: 示例:将A ...
- Java 8:在新的Nashorn JS引擎中编译Lambda表达式
在最近的一篇文章中,我了解了Java 8和Scala如何实现Lambda表达式. 众所周知,Java 8不仅引入了对Javac编译器的改进,而且还引入了全新的解决方案-Nashorn. 这个新引擎旨在 ...
- Java 8中使用Lambda表达式的策略模式
策略模式是" 设计模式:可重用对象的元素"书中的模式之一 . 本书所述的策略模式的意图是: 定义一系列算法,封装每个算法,并使它们可互换. 策略使算法独立于使用该算法的客户端而变化 ...
最新文章
- 能综合和仿真但是不能生成bit流文件的解决方法
- 在计算机上创建一个本地用户账户,在工作组中,默认时每台Windows计算机的( )能够在本地计算机的SAM数据库中创建并管理本地用户账户。...
- BZOJ4589. Hard Nim
- 在 CTreeCtrl 中枚举系统中的所有窗口!(II)
- yolo5纸张卡片顶点检测,实现任意倾斜角度较正
- 要使一个问题能够用计算机解决,如何正确并解决在使用计算机中的问题?
- 百亿级日访问量的应用如何做缓存架构设计?
- 电机学、电机拖动相关知识(试着更新电机的相关知识,感谢指出错误)
- invalid operands to binary expression 二进制表达式的无效操作数
- tplink 无线打印服务器,tplink打印服务器设置
- forEach() map()— —更新数组 filter()、includes()、find()、findIndex()— —筛选(删除)数组 some()、every()— 判断数组 reduce
- Flixel引擎学习笔记
- sklearn中KMeans重要参数n_clusters
- 以太坊的POS共识机制(二)理解 Serenity :Casper
- 程序员面试、算法研究、编程艺术、红黑树、机器学习5大经典原创系列集锦与总结
- 计算机产品选型与配置,高校校园网设备的选型和配置.DOC
- 怎样卸载teams_如何在Windows 10上永久卸载Microsoft Teams
- 论文阅读笔记 Sparse Representation-Based Intra Prediction for Lossless/Near Lossless Video Coding
- 南京工业大学校园网(智慧南工)自动登录
- numpy 基本操作
热门文章
- Python基础知识笔记(二)
- html表单-在线留言,aspcms自定义表单 在线留言修改
- c#水晶报表连接mysql_C# 水晶报表打印 绑定数据库表
- Java编程:java判断两个区间交差重叠
- Git:git同步git push时候提示filename too long解决办法
- 设计模式:JavaScript
- java 关闭进程_java在进程启动和关闭.exe程序
- 小白Linux入门之:CentOS基础命令
- SpringBoot两种定时任务(Spring Schedule 与 Quartz 整合 )实现
- 论文笔记_S2D.63_2020-ICRA_LiStereo:从雷达和双目立体图像生成稠密深度图