Java8的Lambda表达式,你会不?
理解Lambda
Lambda表达式可以是一段可以传递的代码,它的核心思想是将面向对象中的传递数据变成传递行为,也就是行为参数化,将不同的行为作为参数传入方法。
随着函数式编程思想的引进,Lambda表达式让可以用更加简洁流畅的代码来代替之前冗余的Java代码。
口说无凭,直接上个例子吧。在Java8之前,关于线程代码是这样的:
class Task implements Runnable{
@Override
public void run() {
System.out.println("Java8 之前 实现Runnable接口中的run方法");
}
}
Runnable t = new Task();
我们定义了一个Task类,让它实现Runnable接口,实现仅有的run方法,我们希望执行的线程体虽然只有一句话,但我们仍然花了大量大代码去定义。为了简化,我们可以采用匿名内部类的方式:
Runnable taskBeforeJava8 = new Runnable() {
@Override
public void run() {
System.out.println("Java8 之前的写法, 传入匿名类");
}
};
但是,其实还是不够简洁,我们用Lambda的写法是这样的:
// java8 之后
Runnable taskAfterJava8 = () -> System.out.println("Java8 之后的写法,lambda表达式");
我们仅仅使用()和->就完成了这件事,是不是非常简洁呢?如果你觉得虽然Lambda写法简洁,但是它的规则让人摸不着头脑,那就跟着我接下去学叭。
基础语法
(parameters) -> action
(parameters) -> expression
(parameters) -> {statements;}
parameters代表变量,可以为空,可以为单,可以为空,你能想到的方式他都可以。
action是实现的代码逻辑部分,可以是一行代码expression,也可以是一个代码片段statements。如果是代码片段,需要加上{}。
下面是一些合法的示例,你可以看看有没有掌握:
| 表达式 | 描述 |
|---|---|
() -> 1024 |
不需要参数,返回值为1024 |
x -> 2 * x |
接收参数x,返回其两倍 |
(x, y) -> x - y |
接收两个参数,返回它们的差 |
(int x, int y) -> x + y |
接收两个int类型参数,返回他们的和 |
(String s) -> print(s) |
接收一个String对象,并打印 |
函数式接口
什么是函数式接口?函数式接口是只有一个抽象方法的接口,用作lambda表达式的类型。
@FunctionalInterface // 此注解作用的接口 只能拥有一个抽象方法
public interface Runnable {
public abstract void run();
}
在这里,@FunctionalInterface注解是非必须的,有点类似于@Override,起强调作用,如果你的接口标注该注解,却没有遵循它的原则,编译器会提示你修改。
常用的函数式接口
JDK原生为我们提供了一些常用的函数式编程接口,让我们在使用他们编程时,不必关心接口名,方法名,参数名,只需关注它的参数类型,参数个数,返回值。
| 接口 | 参数 | 返回值 | 类别 | 示例 |
|---|---|---|---|---|
| Consumer | T | void | 消费型接口 | 打印输出某个值 |
| Supplier | None | T | 供给型接口 | 工厂方法获取一个对象 |
| Function | T | R | 函数型接口 | 获取传入列表的总和 |
| Predicate | T | boolean | 断言型接口 | 判断是否以summer为前缀 |
消费型接口
/**
* 消费型接口, 传入T 无返回值
*/
public static void consumerTest() {
Consumer<Integer> consumer = num -> System.out.println(num * num);
consumer.accept(10);
}
供给型接口
/**
* 供给型接口, 无参数,返回T
*/
public static void supplierTest() {
Supplier<Object> supplier = () -> new Object();
System.out.println(supplier.get());
}
断言型接口
/**
* 断言型 传入参数T ,返回boolean
*/
public static void predicateTest() {
Predicate<String> predicate = name -> name.startsWith("summer");
System.out.println(predicate.test("summerday"));
}
函数型接口
/**
* 函数型接口 传入T 返回R
*/
public static void functionTest() {
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
Function<List<Integer>, Integer> function = num -> {
int res = 0;
for (int n : list) {
res += n;
}
return res;
};
Integer num = function.apply(list);
System.out.println(num);
}
方法引用
方法引用可以看作特定Lambda表达式的快捷写法,主要分为以下两种:
- 指向静态方法的方法引用
- 指向现有对象的实例方法的方法引用
/**
* 方法引用
* 1. 指向静态方法的方法引用
* 2. 指向现有对象的实例方法的方法引用
*
* @author Summerday
*/
public class MethodReferenceTest {
public static List<String> getList(List<String> params, Predicate<String> filter) {
List<String> res = new LinkedList<>();
for (String param : params) {
if (filter.test(param)) {
res.add(param);
}
}
return res;
}
// 静态方法
public static boolean isStartWith(String name) {
return name.startsWith("sum");
}
public static void main(String[] args) {
List<String> params = Arrays.asList("summerday","tqbx","天乔巴夏","summer","");
//静态方法的方法引用 getList(params, name -> MethodReferenceTest.isStartWith(name));
List<String> list = getList(params, MethodReferenceTest::isStartWith);
System.out.println(list);
// 指向现有对象的实例方法的方法引用 getList(params, name -> name.isEmpty());
List<String> sum = getList(params, String::isEmpty);
System.out.println(sum);
}
}
数组引用
/**
* 数组引用
* @author Summerday
*/
public class ArrayReferenceTest {
public static void main(String[] args) {
// 普通lambda
Function<Integer,String[]> fun1 = x -> new String[x];
String[] res1 = fun1.apply(10);
System.out.println(res1.length);
// 数组引用写法
Function<Integer,String[]> fun2 = String[]::new;
String[] res2 = fun2.apply(10);
System.out.println(res2.length);
}
}
构造器引用
/**
* 构造器引用
* @author Summerday
*/
public class ConstructorReferenceTest {
public static void main(String[] args) {
// 普通lambda
Supplier<User> sup = () -> new User();
// 构造器引用
Supplier<User> supplier = User::new;
User user = supplier.get();
System.out.println(user);
}
}
class User{
}
总结
- lambda表达式没有名称,但有参数列表,函数主体,返回类型,可能还有一个可以抛出的异常的列表。
- lamda表达式让你可以将不同的行为作为参数传入方法。
- 函数式接口是仅仅声明了一个抽象方法的接口。
- 只有在接受函数式接口的地方才可以使用lambda表达式。
- lambda表达式允许你直接内联,为函数式接口的抽象方法提供实现,并将整个表达式作为函数式接口的一个实例。
- Java8自带了一些常用的函数式接口,包括
Predicate,Function,Supplier,Consumer,BinaryOperator。 - 方法引用让你重复使用现有的方法实现并直接传递他们:
Classname::method。
参考阅读
Java8的Lambda表达式,你会不?的更多相关文章
- Java8中Lambda表达式的10个例子
Java8中Lambda表达式的10个例子 例1 用Lambda表达式实现Runnable接口 //Before Java 8: new Thread(new Runnable() { @Overri ...
- java8的lambda表达式,将List<DTO> 转为 List<DO>
将List<PhoneDTO>转为List<PhoneDO>,通过java8的lambda表达式来操作,比传统的for循环精简很多: /** * List<PhoneDT ...
- java8的lambda表达式
关于java8的lambda表达式 lambda表达式一般用于接口,因为lambda表达式是函数式编程. 1.有且仅有一个抽象方法被称为函数式接口,函数式接口可以显示的被@FunctionalInte ...
- java8中lambda表达式的应用,以及一些泛型相关
语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利 顺带用到一些泛型编程,一切都是为了简化代码 场景: 一个数据类,用于记录职工信息 public clas ...
- java8之lambda表达式(1)-基本语法
lambda表达式,即带有参数的表达式,为更清晰地理解lambda表达式,先看如下例子: (1) class Student{ private String name; private Double ...
- java8之lambda表达式入门
1.基本介绍 lambda表达式,即带有参数的表达式,为了更清晰地理解lambda表达式,先上代码: 1.1 两种方式的对比 1.1.1 方式1-匿名内部类 class Student{ privat ...
- JAVA8之lambda表达式具体解释,及stream中的lambda使用
前言: 本人也是学习lambda不久,可能有些地方描写叙述有误,还请大家谅解及指正! lambda表达式具体解释 一.问题 1.什么是lambda表达式? 2.lambda表达式用来干什么的? 3.l ...
- 十分钟学会Java8的lambda表达式和Stream API
01:前言一直在用JDK8 ,却从未用过Stream,为了对数组或集合进行一些排序.过滤或数据处理,只会写for循环或者foreach,这就是我曾经的一个写照. 刚开始写写是打基础,但写的多了,各种乏 ...
- java8中Lambda表达式和Stream API
一.Lambda表达式 1.语法格式 Lambda是匿名函数,可以传递代码.使用“->”操作符,改操作符将lambda分成两部分: 左侧:指定了 Lambda 表达式需要的所有参数 右侧:指定了 ...
- Java8之lambda表达式
一.什么是lambda表达式? Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递).可以写出更简洁.更灵活的代码.作为一种更紧凑的代码 ...
随机推荐
- Node.js 爬虫爬取电影信息
Node.js 爬虫爬取电影信息 我的CSDN地址:https://blog.csdn.net/weixin_45580251/article/details/107669713 爬取的是1905电影 ...
- 常见MFC函数
1.MFC常用函数:WinExec()ExitWindowsEx()GlobalMemoryStatus()GetSystemInfo()GetSystemDirectory()GetWindowsD ...
- day02-多任务(进程和协程)
一.多任务的概念 简单地说,就是操作系统可以同时运行多个任务.打个比方,你一边在用浏览器上网,一边在听MP3,一边在用Word赶作业,这就是多任务,至少同时有3个任务正在运行.还有很多任务 ...
- 不会吧!做了这么久开发还有不会NIO的,看看BAT大佬是怎么用的吧
前言 在将NIO之前,我们必须要了解一下Java的IO部分知识. BIO(Blocking IO) 阻塞IO,在Java中主要就是通过ServerSocket.accept()实现的. NIO(Non ...
- python 定时任务框架apscheduler
文章目录 安装 基本概念介绍 调度器的工作流程 实例1 -间隔性任务 实例2 - cron 任务 配置调度器 方法一 方法二 方法三: 启动调度器 方法一:使用默认的作业存储器: 方法二:使用数据库作 ...
- 在线思维导图Ayoa可以用来梳理双十一优惠规则哦
一年一度的双十一又要来了,小伙伴们是否准备好开始买买买了呢?今年双十一,遇上英雄联盟S10总决赛,1/4决赛苏宁对上京东也让这个"电商大战"产生了很多有趣的梗.当然在玩梗的同时,广 ...
- kakafka - 为CQRS而生fka - 为CQRS而生
前段时间跟一个朋友聊起kafka,flint,spark这些是不是某种分布式运算框架.我自认为的分布式运算框架最基础条件是能够把多个集群节点当作一个完整的系统,然后程序好像是在同一台机器的内存里运行一 ...
- 从递归到memo到动态规划
//memo,记忆化搜索 class Solution { int[][] memo; public boolean wordBreak(String s, List<String& ...
- 蓝桥杯——四数平方(2016JavaB第7题)
四数平方(16JavaB7) 四平方和定理,又称为拉格朗日定理: 每个正整数都可以表示为至多4个正整数的平方和. 如果把0包括进去,就正好可以表示为4个数的平方和. 比如: 5 = 0^2 + 0^2 ...
- SpringBoot中JPA的学习
SpringBoot中JPA的学习 准备环境和项目配置 写一下学习JPA的过程,主要是结合之前SpringBoot + Vue的项目和网上的博客学习一下. 首先,需要配置一下maven文件,有这么两个 ...