JDK8新特性(一) Lambda表达式及相关特性
函数式接口
函数式接口是1.8中的新特性,他不属于新语法,更像是一种规范
面向对象接口复习
在这里先回顾一下面向对象的接口,创建接口的关键字为interface,这里创建一个日志接口:
public interface LogService {
void info();
}
众所周知,Java中的接口是不能直接创建实例的,因为他的抽象方法没有得到实现:

当我们想要创建接口实例的时候一般都通过实现类来获取实例:
public class LogServiceImpl implements LogService {
@Override
public void info() {
System.out.println("哈哈哈哈");
}
}
这样我们就可以通过实现来创建这个接口的实例:
public class ApplicationMain {
public static void main(String[] args) {
LogService log = new LogServiceImpl();
log.info();
}
}
对接口中的方法进行实现除了实现类之外,还可以通过匿名内部类的方式来创建接口的实例:
public class ApplicationMain {
public static void main(String[] args) {
LogService log = new LogService() {
@Override
public void info() {
System.out.println("嘿嘿嘿");
}
};
}
}
什么是函数式接口
当一个接口只有一个抽象方法 ( 接口默认实现不算 ) 的时候这个接口就是函数式接口,上面的LogService就属于函数式接口,还有学习线程时的Runnable接口也属于函数式接口
函数式接口还有一个注解为@FunctionalInterface,据我了解这个注解可有可无,它主要起到的是检查的作用,当接口中的抽象方法数量大于1的时候就会报错:

内置常用函数式接口
Java中内置了一些常用的函数式接口,这里介绍其中的四种,不用刻意去记,用到就明白了
| 函数式接口 | 参数 | 返回值 | 说明 |
|---|---|---|---|
| Consumer | T | void | 对类型为T的实例进行操作 |
| Supplier | 无 | T | 返回类型为T的实例 |
| Function<T, R> | T | R | 通过对T的操作返回R的实例 |
| Predicate | T | boolean | 通过对T的操作返回boolean值 |
通过巧妙的运用函数式接口可以实现回调函数的功能
Lambda表达式
Lambda表达式是1.8中的新特性,主要针对函数式接口的匿名内部类实现做了简化
表达式基本语法
找到上面匿名内部类创建LogService的代码:
public class ApplicationMain {
public static void main(String[] args) {
LogService log = new LogService() {
@Override
public void info() {
System.out.println("嘿嘿嘿");
}
};
}
}
因为创建的实例就是接口本身,所以new的部分就可以省略不写,接口中需要实现的抽象方法只有一个,那么也没有必要指定具体实现的方法名称,简写后如下所示:
public class ApplicationMain {
public static void main(String[] args) {
LogService log = ()->{
System.out.println("哈哈哈哈");
};
log.info();
}
}
Lambda表达式前面的括号( )就代表参数列表,箭头->后面的代码块就代表着实现的具体方法体,如果info方法中有参数就可以这样写:
public class ApplicationMain {
public static void main(String[] args) {
LogService log = (msg)->{
System.out.println(msg);
};
log.info("老八秘制小汉堡");
}
}
使用Lambda表达式创建一个线程:
public class ApplicationMain {
public static void main(String[] args) {
// Runnable为函数式接口,所以可以使用Lambda表达式
new Thread(()->{
System.out.println("另一条线程");
}).start();
System.out.println("Main主线程");
}
}
表达式的简写
使用Lambda表达式代替匿名内部类的写法非常简洁,但是在满足特定条件的情况下,它还可以更简洁:
public class ApplicationMain {
public static void main(String[] args) {
/**
* 在参数列表只有一个参数的情况下,()可以省略不写
* 当代码块中只有一句代码时{}可以省略不写
* 当函数有返回值且代码块中只有一句代码时return可以省略不写
*/
LogService log = msg->System.out.println(msg);
log.info("老八秘制小汉堡");
}
}
Lambda表达式相比匿名内部类还有一个特点,当使用匿名内部类时会为匿名内部类生成一个class文件,而使用Lambda表达式时就不会额外生成class文件,这个不做重点
方法引用
方法引用是1.8中的新特性,配合Lambda表达式使用可以让代码更简洁
方法引用初体验
方法引用中需要的特殊符号为双冒号::,具体表现为以下形式:
| 表现形式 | 作用 |
|---|---|
| 对象::实例方法 | 通过对象调用实例中的方法 |
| 类::实例方法 | 通过类调用实例中的方法 |
| 类::静态方法 | 通过类调用实例中的静态方法 |
| 类::new | 创建该类的实例 |
当Lambda表达式中只有一句函数调用代码,且调用的目标函数的参数列表和Lambda表达式接收的参数列表一致时就可以使用方法引用,如下所示:
public class ApplicationMain {
public static void main(String[] args) {
// 代表的就是上面表格中表现形式的第一行 对象::实例方法
LogService log = System.out::println;
log.info("老八秘制小汉堡");
// forEach同样可以使用方法引用
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.forEach(System.out::println);
}
}
综合练习
针对上面的函数式接口,Lambda表达式以及方法引用做练习,代码会有些多:
/**
* 综合练习
* 函数式接口 + Lambda表达式 + 方法引用
*/
public class ApplicationMain {
public static void main(String[] args) {
// 方法引用 对象::实例方法
strToDate("2021-2-20 22:08:45", System.out::println);
// 方法引用 类::new
System.out.println(dateToStr(Date::new));
// 回调函数:取最大值
Integer integer = strListToIntList(Arrays.asList("135", "541", "244"), list -> {
int maxNumber = 0;
for (Integer item : list) {
if (item > maxNumber) {
maxNumber = item;
}
}
return maxNumber;
});
System.out.println("最大值为:" + integer);
// 实现过滤器功能
List<Integer> list = filter(Arrays.asList(800, 200, 1200, 600, 3000, 2400), item -> item > 1000);
System.out.println(list);
}
// Consumer:通过时间字符串快速获取Date对象
public static void strToDate(String date, Consumer<Date> consumer) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date parse = null;
try {
parse = sdf.parse(date);
} catch (ParseException e) {
System.err.println("转换失败!");
}
consumer.accept(parse);
}
// Supplier:通过Date对象快速获取到时间字符串
public static String dateToStr(Supplier<Date> supplier) {
Date date = supplier.get();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(date);
}
// Function:将String集合转换为Integer,后续操作交给调用者
public static Integer strListToIntList(List<String> list, Function<List<Integer>, Integer> function) {
ArrayList<Integer> integerList = new ArrayList<>();
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String next = iterator.next();
Integer integer = Integer.valueOf(next);
integerList.add(integer);
}
return function.apply(integerList);
}
// predicate:返回大于1000的数字
public static List<Integer> filter(List<Integer> list, Predicate<Integer> predicate) {
ArrayList<Integer> target = new ArrayList<>();
for (Integer item : list) {
if (predicate.test(item)) {
target.add(item);
}
}
return target;
}
}
JDK8新特性(一) Lambda表达式及相关特性的更多相关文章
- jdk8新特性--使用lambda表达式的延迟执行特性优化性能
使用lambda表达式的延迟加载特性对代码进行优化:
- java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合
java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合 比如,我有一张表: entity Category.java service CategoryServic ...
- JDK1.8新特性(一) ----Lambda表达式、Stream API、函数式接口、方法引用
jdk1.8新特性知识点: Lambda表达式 Stream API 函数式接口 方法引用和构造器调用 接口中的默认方法和静态方法 新时间日期API default Lambda表达式 L ...
- Java8 新特性学习 Lambda表达式 和 Stream 用法案例
Java8 新特性学习 Lambda表达式 和 Stream 用法案例 学习参考文章: https://www.cnblogs.com/coprince/p/8692972.html 1.使用lamb ...
- JDK8新特性之Lambda表达式
Lambda表达式主要是替换了原有匿名内部类的写法,也就是简化了匿名内部类的写法.lambda语法结构: (参数1,参数2...)->{重写方法的内容,不定义方法名} 先看一个使用匿名内部类定义 ...
- JDK8新特性02 Lambda表达式02_Lambda语法规则
//函数式接口:只有一个抽象方法的接口称为函数式接口. 可以使用注解 @FunctionalInterface 修饰 @FunctionalInterface public interface MyF ...
- JDK8新特性01 Lambda表达式01_设计的由来
1.java bean public class Employee { private int id; private String name; private int age; private do ...
- JDK8新特性:Lambda表达式
Lambda表达式,案例一:new Thread(() -> System.out.println("thread")); Lambda表达式,案例二:由参数/箭头和主体组成 ...
- Java8新特性之Lambda表达式
lambda表达式是java8给我们带来的几个重量级新特性之一,借用lambda表达式,可以让我们的java程序设计更加简洁.最近新的项目摒弃了1.6的版本,全面基于java8进行开发,本文是java ...
随机推荐
- Django框架admin后台管理和用户端静态文件
目录 一.admin后台管理 1. 如何使用 2. 路由分发的本质 二.用户上传的静态文件的展示 1. media配置 2. 手动开设media接口 三.图片防盗链 一.admin后台管理 djang ...
- Course2.1 Graph Paper Programming
Overview 通过日常生活中的活动来体验程序算法,目标时能够将现实世界的场景与程序场景关联起来. Objective 抓住将现实世界问题转换为程序的难点: 你认为非常明确的指令在计算机看来可能还是 ...
- CRLF注入原理
CRLF 指的是回车符(CR,ASCII 13,\r,%0d) 和换行符(LF,ASCII 10,\n,%0a),操作系统就是根据这个标识来进行换行的,你在键盘输入回车键就是输出这个字符,只不过win ...
- 在Asp.Net Core 5 中使用EF Core连接MariaDB
升级到Asp.Net Core 5,使用EF Core连接MariaDB,使用的Nuget包Pomelo.EntityFrameworkCore.MySql也升级到了5.0.0-alpha.2,然后发 ...
- mysql内一些可以布尔盲注的查询语句
一.left() 首先需要 use security; 这个数据库,然后进入之后再使用查询语句: 此时再使用: select left(database(),1)='s'; ...
- 泛微OA 多版本存在命令执行
参考 https://blog.csdn.net/qq_41770175/article/details/102821349 https://www.linktrust.net/oday/471.ht ...
- C# 基础 - 堆栈跟踪使用
使用一:可用于捕获报错时. using System.Diagnostics; ... StackTrace st = new StackTrace(true); string stackIndent ...
- 【java框架】MyBatis(7)--MyBatis注解开发
1.MyBatis注解开发 1.1.Lombok的基本使用 Lombok是SpringBoot2.1.X版本与IDEA官方支持的一个插件,它是为简化POJO类中繁杂重复代码:geter/setter/ ...
- Lzzy高级语言程序设计之for循环
public class Mq { public static void main(String[]args){ int a = 3 ; a++;// do{ System.out.println(& ...
- 安装RPM包或者源码包
RPM工具 RPM他是以一种数据库记录的方式将我们所需要的套件安装到linux主机的一套管理程序关于RPM各个选项的含义如下-i:表示安装-v:表示可视化-h:表示安装进度在安装RPM包时,常用的附带 ...