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 ...
随机推荐
- eclipse从接口快速跳转到实现类
1.只跳转到实现类上 按住Ctrl键,把鼠标的光标放在要跳转的接口上面,选择第二个 2.直接跳转大实现的方法上 按住Ctrl键,把鼠标的光标放在要跳转的方法上面,选择第二个 对比可以发现,操作都是一样 ...
- Ctfweb(2)
CTFwebshow(2): phps源码泄露 思路:第一次接触phps这个后缀,第一眼打开的时候是想着用御剑去扫目录,但是很遗憾没有扫到index.phps,然后用burp抓包返回包信息也没有看到端 ...
- 微信小程序警告设置 enable-flex 属性以使 flexbox 布局生效的解决办法
微信小程序警告设置 enable-flex 属性以使 flexbox 布局生效的解决办法 具体情况: scroll-view 滚动,设置 display:flex 不生效并警告设置 enable-fl ...
- 后端程序员之路 33、Index搜索引擎实现分析2-对外接口和大体流程
# index_manager的单例是index server对外的唯一接口,part_indexer是index搜索的核心部分,index_manager持有了一组part_indexer. typ ...
- [源码解析] 消息队列 Kombu 之 基本架构
[源码解析] 消息队列 Kombu 之 基本架构 目录 [源码解析] 消息队列 Kombu 之 基本架构 0x00 摘要 0x01 AMQP 1.1 基本概念 1.2 工作过程 0x02 Poll系列 ...
- ELK----elasticsearch7.10.1安装配置
环境: vmware centos7 1.下载适合自己的es版本 https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-1 ...
- POJ-1847(SPFA+Vector和PriorityQueue优化的dijstra算法)
Tram POJ-1847 这里其实没有必要使用SPFA算法,但是为了巩固知识,还是用了.也可以使用dijikstra算法. #include<iostream> #include< ...
- RabbitMQ镜像队列集群搭建、与SpringBoot整合
镜像模式 集群模式非常经典的就是Mirror镜像模式,保证100%数据不丢失,在实际工作中也是用的最多的,并且实现集群比较的简单. Mirror镜像队列,目的是为了保证 RabbitMQ 数据的高可靠 ...
- 《逆向工程核心原理》——API HOOK
编写dll处理hook逻辑,注入到目标进程,实现api hook. Windows10 notepad,通过hook kernel32.dll.WriteFile,实现小写字母转大写保存到文件. ho ...
- 《逆向工程核心原理》——通过调试方式hook Api
1.附加目标进程, 2.CREATE_PROCESS_DEBUG_EVENT附加事件中将目标api处设置为0xcc(INT 3断点) 3.EXCEPTION_DEBUG_EVENT异常事件中,首先判断 ...