Java8 新特性之Lambda表达式
1. Lambda 表达式概述
- Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递);
- Lambda 表达式可以写出更简洁,更灵活的代码;
// Lambda 表达式入门程序
public class TestLambda{
List<Employee> employees = Arrays.asList(
new Employee("张三",16,1000),
new Employee("李四",22,2000),
new Employee("熊大",25,1300),
new Employee("熊二",32,1200),
new Employee("赵六",43,3200)
);
@Test
public void test2(){
List<Employee> list = filterEmpByAge(employees);
for(Employee emp : list){
System.out.println(emp);
}
}
// 需求一: 获取当前公司中,员工年龄大于等于30的员工信息
public List<Employee> filterEmpByAge(List<Employee> list){
List<Employee> emps = new ArrayList<>();
for(Employee emp : list){
if(emp.getAge() >= 30){
emps.add(emp);
}
}
return emps;
}
// 需求二: 获取当前公司中,员工工资大于等于2000的员工信息
public List<Employee> filterEmpBySal(List<Employee> list){
List<Employee> emps = new ArrayList<>();
for(Employee emp : list){
if(emp.getSalary() >= 2000){
emps.add(emp);
}
}
return emps;
}
// 优化方式一: 策略设计模式
@Test
public void test3(){
// 按年龄过滤
List<Employee> list = filterEmployee(employees,new FilterEmployeeByAge());
for(Employee employee : list){
System.out.println(employee);
}
// 按工资过滤
List<Employee> list2 = filterEmployee(employees,new FilterEmployeeBySal());
for(Employee employee : list2){
System.out.println(employee);
}
}
public List<Employee> filterEmployee(List<Employee> list, MyPredicte<Employee> mp){
List<Employee> emps = new ArrayList<>();
for(Employee employee : list){
if(mp.test(employee)){
emps.add(employee);
}
}
}
// 优化方式二: 匿名内部类
// 不再需要创建泛型接口的实现类
@Test
public void test4() {
// filterEmployee(employees, 匿名内部类);
List<Employee> list = filterEmployee(employees, new MyPredicate<Emplooyee>(){
public boolean test(Employee emp){
return emp.getSalary() <= 2000;
}
});
for(Employee employee : list){
System.out.println(employee);
}
}
// 优化方式三: Lambda 表达式
@Test
public void test5(){
List<Employee> list = filterEmployee(employees, (e) -> e.getSalary() <= 2000);
list.forEach(System.out::println);
}
// 优化方式四: Stream API
@Test
public void test6(){
employees.stream()
.filter((e) -> e.getSalary() <= 2000)
.forEach(System.out::println);
// 获取所有员工的名字
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
}
}
// 创建泛型接口
public interface MyPredicate<T>{
public boolean test(T t);
}
// 创建泛型接口的实现类
public class filterEmpByAge implements MyPredicate<Employee> {
public boolean test(Employee emp){
return emp.getAge() >= 30;
}
}
public class filterEmpBySal implements MyPredicate<Employee> {
public boolean test(Employee emp){
return emp.getSalary() >= 2000;
}
}
2. Lambda 表达式基础语法
->
: 该操作符称为箭头操作符或Lambda 操作符,将Lambda 表达式拆分成两部分:- 左侧: Lambda 表达式的参数列表;
- 右侧: Lambda 表达式所需执行的功能,即 Lambda 体;
- 语法格式一: 无参数,无返回值
() -> System.out.println("Hello Lambda!");
- 语法格式二: 有一个参数,无返回值;
(x) -> System.out.println(x);
- 或者
x -> System.out.println(x);
若只有一个参数,小括号可以省略不写;
- 语法格式三: 有两个以上的参数,有返回值,并且 Lambda 体中有多条语句;
- Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即"类型推断";
(Integer x, Integer y) -> Integer.compare(x,y);
其中,数据类型 Integer,可以省略不写;
// 测试类
public class TestLambda{
@Test
public void test01(){
int num = 0; // JDK 1.7 之前,必须是final,才能在匿名函数内部使用
// JDK 1.8 可以不使用 final, 但是在匿名函数内部仍然不能进行运算
// 无参数,无返回值
// 1. Java8 之前写法:
Runnable r = new Runnable(){
public void run(){
System.out.println("Hello World!" + num);
}
};
r.run();
// Lambda 表达式
Runnable r2 = () -> System.out.println("Hello World!");
r2.run();
}
@Test
public void test02(){
// 有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
Comparator<Integer> com = (x,y) -> {
System.out.println("函数式接口");
return Integer.compare(x,y);
};
// 有两个以上的参数,有返回值,Lambda 体中只有一条语句; 大括号和return可以省略
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
}
}
3. Lambda 表达式需要"函数式接口"的支持
- 函数式接口:接口中只有一个抽象方法时,称为函数式接口;
- 可以使用注解
@FunctionalInterface
进行修饰,这样,可以检查该接口是否是函数式接口;
// Lambda 练习
// 声明一个带两个泛型的函数式接口,泛型类型为<T,R>, T 为参数, R 为返回值;
// 接口中声明对应抽象方法;
// 在 TestLambda 类中声明方法,使用接口作为参数,计算两个 long 型参数的和与乘积
// 函数式接口
@FunctionalInterface
public interface MyFunction<T,R>{
public R getValue(T t1, T t2);
}
// 测试类
public class TestLambda{
public void option(Long l1, Long l2, MyFunction<Long,Long> mf){
System.out.println(mf.getValue(l1,l2));
}
@Test
public void test(){
option(100L,200L,(x,y) -> x+y);
option(100L,200L, (x,y) -> x*y);
}
}
4. 四大内置核心函数式接口
- 消费型接口:
Consumer<T>
- 参数类型: T
- 返回值类型: void
- 用途: 对类型为T的对象进行操作,包含方法:
void accept(T t)
- 供给型接口:
Supplier<T>
- 参数类型: 无
- 返回值类型: T
- 用途: 返回类型为T的对象,包含方法:
T get()
- 函数型接口:
Function<T,R>
- 参数类型: T
- 返回值类型: R
- 对类型为T的对象进行操作,并返回结果,结果是R类型的对象,包含方法:
R apply(T t)
- 断言型接口:
Predicate<T>
- 参数类型: T
- 返回值类型: boolean
- 确定类型为T的对象是否满足某约束,并返回boolean值;包含方法:
boolean test(T t)
5. 方法引用
- 方法引用: 若 Lambda 体中的内容有方法已经实现了,我们可以使用"方法引用";
可以理解为,方法引用是 Lambda 表达式的另外一种表现形式; - 主要有三种语法格式:
对象::实例方法名
类::静态方法名
类::实例方法名
- 注意: Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致!
- 注意2: 若 Lambda 参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用
ClassName::method
方式调用;
5.1 构造方法引用
ClassName::new
- 注意: 需要调用的构造器参数列表要与函数式接口中抽象方法的参数列表保持一致!
5.2 数组引用
Type::new
public class TestMethodRef{
@Test
public void test(){
Consumer<String> con = (x) -> System.out.println(x);
con.accept("测试方法....");
//对象::实例方法名
Consumer<String> con2 = System.out::println;
con2.accept("测试方法");
// 示例二: 获取员工姓名
Employee emp = new Employee();
Supplier<String> sup = () -> emp.getName();
String str = sup.get();
System.out.println(str);
Supplier<String> sup2 = emp::getName;
String str2 = sup2.get();
System.out.println(str2);
}
@Test
public void test2(){
// 类::静态方法名
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
Comparator<Integer> com2 = Integer::compare;
}
@Test
public void test3(){
// 类::实例方法名
BiPredicate<String,String> bp = (x,y) -> x.equals(y);
Bipredicate<String,String> bp2 = String::equals;
}
@Test
public void test4(){
Supplier<Employee> sup = () -> new Employee();
// 构造器引用(无参构造器)
Supplier<Employee> sup2 = Employee::new;
Function<Integer,Employee> fun = (x) -> new Employee(x);
// 构造器引用(有一个参数的构造器)
Function<Integer,Employee> fun = Employee::new;
}
@Test
public void test5(){
Function<Integer,String[]> fun = (x) -> new String[x];
String[] strs = fun.apply(10);
System.out.println(strs.length);
// 数组方式的引用
Function<Integer,String[]> fun2 = String[]::new;
}
}
参考资料
Java8 新特性之Lambda表达式的更多相关文章
- java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合
java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合 比如,我有一张表: entity Category.java service CategoryServic ...
- Java8 新特性学习 Lambda表达式 和 Stream 用法案例
Java8 新特性学习 Lambda表达式 和 Stream 用法案例 学习参考文章: https://www.cnblogs.com/coprince/p/8692972.html 1.使用lamb ...
- Java8新特性之Lambda表达式
lambda表达式是java8给我们带来的几个重量级新特性之一,借用lambda表达式,可以让我们的java程序设计更加简洁.最近新的项目摒弃了1.6的版本,全面基于java8进行开发,本文是java ...
- 【Java8新特性】Lambda表达式基础语法,都在这儿了!!
写在前面 前面积极响应读者的需求,写了两篇Java新特性的文章.有小伙伴留言说:感觉Lambda表达式很强大啊!一行代码就能够搞定那么多功能!我想学习下Lambda表达式的语法,可以吗?我的回答是:没 ...
- 【Java8新特性】- Lambda表达式
Java8新特性 - Lambda表达式 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! ...
- 夯实Java基础(二十二)——Java8新特性之Lambda表达式
1.前言 Java 8于14年发布到现在已经有5年时间了,经过时间的磨练,毫无疑问,Java 8是继Java 5(发布于2004年)之后的又一个非常最重要的版本.因为Java 8里面出现了非常多新的特 ...
- java8新特性之——lambda表达式的使用
lambda表达式简介 个人理解,lambda表达式就是一种新的语法,没有什么新奇的,简化了开发者的编码,其实底层还是一些常规的代码.Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解 ...
- 【Java8新特性】Lambda表达式
一.Lambda 表达式 是什么? Lambda读音:拉姆达. Lambda是一个匿名函数,匿名函数就是一个没有名字的函数. Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中). ...
- Java8 新特性(一)- Lambda 表达式
2014年3月18日发布了JavaSE 8 不追求技术的新,追求技术的稳定 本质:Lambda 表达式是一个匿名函数 作用:简化代码,增强代码的表达力 Lambda 语法格式 // 格式1:无参无返回 ...
随机推荐
- 【持续更新】GDB使用笔记
多文件程序的调试,例子: 文件结构: /demo Makefile /src demo.cpp util.cpp /include util.h 截图: ----------------------- ...
- jar 打包命令详解
原文: https://blog.csdn.net/marryshi/article/details/50751764 本文详细讲述了JAR命令的用法,对于大家学习和总结jar命令的使用有一定的帮助作 ...
- python学习笔记(5)--泡菜:永久存储
说明: 1. 导入pickle泡菜模块. 2. wb方式(二进制)创建.pkl文件. 3. pickle.dump把一个数组或什么数据灌进这个新建的文件. 4. 然后就生成了一个pkl文件,用来存放数 ...
- QT4.8.5 源码编译记录
今天想将以前的虚拟机的 QT4.8.5 集成到一个虚拟机里面,所以就重新编译了一次 QT4.8.5的源码 走了一点点小弯路,特此记录. 一.交叉编译器,不能直接从原来的虚拟机里面拷贝,必须使用官网的交 ...
- 用分立元件实现串口通讯TTL/RS232电平转换
1.计算机串口通信的RS-232电平:用正负电压来表示逻辑状态.逻辑1= = -3V--15V,逻辑0=+3-+15V. 2.单片机串口通信的TTL电平:输出高电平>2.4V,输出低电平< ...
- linux socket can测试
1. Overview / What is Socket CAN -------------------------------- The socketcan package is an implem ...
- Bitmap转灰度字节数组byte[]
工作中遇到图片转灰度数组的须要,经过研究和大神的指导.终于得到例如以下两个方法.能够实现位图转灰度数组 简单的位图转灰度数组就是:得到位图中的每一个像素点,然后依据像素点得到RGB值,最后对RGB值, ...
- 详解 Go 语言中的 time.Duration 类型
swardsman详解 Go 语言中的 time.Duration 类型swardsman · 2018-03-17 23:10:54 · 5448 次点击 · 预计阅读时间 5 分钟 · 31分钟之 ...
- kettle利用触发器实现数据同步
2016年8月17日 一.目的 通过触发器实现数据同步二.思路 1.在数据库需要同步的源表中建立一个insert触发器,当有新数据插入时,会自动将新插入数据的主键记录到临时表temp中.(当然也可以记 ...
- python XlsxWriter Example: Hello World
http://xlsxwriter.readthedocs.io/example_hello_world.html The simplest possible spreadsheet. This is ...