Lambda基础语法

Java8中引入了一个新的操作符“ -> ”,该操作符被称为箭头操作符或Lambda操作符,箭头操作符将Lambda表达式拆分成两部分:

  • 左侧:Lambda表达式的参数列表
  • 右侧:Lambda表达式中所需要执行的功能,即Lambda体

Lambda表达式常见的五种语法如下:

  1. 语法格式一:无参数,无返回值 (如Runable接口中的run方法)
  @Test
public void test01(){
Runnable run01 = new Runnable() {
@Override
public void run() {
System.out.println("通过匿名内部函数实现!");
}
};
run01.run(); Runnable run02 =() -> System.out.println("Hello Lambda!");
run02.run();
}

 2. 语法格式二:有一个参数,无返回值 (如Java8中的Consumer接口)

	@Test
public void test02(){
Consumer con01 = (x) -> System.out.println(x);
//若只有一个参数,小括号可以省略不写
Consumer con02 =x -> System.out.println(x);
//调用抽象方法
con01.accept("使用Lambda表达式,实现抽象方法,输出参数的值");
con02.accept("若只有一个参数,小括号可以省略不写");
}

 3. 语法格式三:有两个以上参数,有返回值,并且Lambda体中有多条语句,大括号必须写

	@Test
public void test03(){
Comparator<Integer> com = (x, y) -> {
System.out.println("函数式接口");
return Integer.compare(x,y);
};
int compare = com.compare(3, 6);
System.out.println(compare);//输出结果为:函数式接口 -1
}

 4. 语法格式四:若Lambda体中只有一条语句,return 和 大括号 都可以省略不写

    @Test
public void test04(){
Comparator<Integer> com = (x, y) -> Integer.compare(x,y);
int compare = com.compare(3, 6);
System.out.println(compare); // 输出结果为: -1
}

 5. 语法格式五:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即“类型推断”

    @Test
public void test05(){
Comparator<Integer> com = (Integer x,Integer y) -> Integer.compare(x,y);
int compare = com.compare(3, 6);
System.out.println(compare); // 输出结果为: -1
}

Lambad表达式需要“函数式接口“的支持

函数式接口:接口中只有一个抽象方法的接口,称为函数式接口,可以使用注解@FunctionalInterface修饰,检查是否是函数式接口

注意:在jdk1.8之前,在局部内部类中,使用了同级别的局部变量,该局部变量必须使用final修饰,JDK1.8之后,该局部变量被默认使用了final修饰,仍然不允许被修改,不需要我们手动去加了

Java8 内置的四大核心函数式接口

  • 消费型接口
@FunctionalInterface
public interface Consumer<T> {
//一个参数,无返回值
void accept(T t);
}
  • 供给型接口
@FunctionalInterface
public interface Supplier<T> {
//无参数,有返回值
T get();
}
  • 函数性接口
@FunctionalInterface
public interface Function<T, R> {
// T代表参数,R代表返回值
R apply(T t);
}
  • 断言型接口(用作一些判断操作)
@FunctionalInterface
public interface Predicate<T> {
//一个参数,返回值为boolean类型,常用来做一些判断操作
boolean test(T t);
}

下面对Java8提供四大核心函数式接口,进行简单的测试运用:

  • 消费型接口测试
    @Test
public void test06(){
//使用Lambda表达式,对Consumer接口中的accept()进行了具体实现
happy(10000.00,(money) -> System.out.println("今天用了10000元买了台Mac笔记本电脑"));
} /**
* 自定义方法调用Consumer接口的抽象方法
* @param money
* @param consumer
*/
public void happy(Double money,Consumer<Double> consumer){
consumer.accept(money);
}
  • 供给型接口测试
    @Test
public void test07(){
//获取10个100以内的随机数
List<Integer> numList = getNumList(10,() -> (int)(Math.random()*100));
for(Integer num: numList){
System.out.println(num);
}
} //需求:产生指定个数的整数,并放入集合中
public List<Integer> getNumList(int num,Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for(int i=0;i<num;i++){
Integer n = sup.get();
list.add(n);
}
return list;
}
  • 函数型接口测试
    //函数型接口:可以对参数进行一些操作,然后返回操作结果
@Test
public void test08(){
//由于Lambad体中只有一条语句,这里return 和 大括号 都省略了
String newStr = strHandler("函数型接口测试",(str) -> str.substring(3,str.length()));
System.out.println(newStr);// 输出结果为: 接口测试
} //需求:用于处理字符串
public String strHandler(String str,Function<String,String> fun){
return fun.apply(str);
}
  • 断言型接口
    @Test
public void test09(){
List<String> list = Arrays.asList("hello","Lambda","easy","OK");
//获取字符串长度大于4的集合
List<String> strList = filterStr(list,(s) -> {return s.length()>4;});
System.out.println(strList); // 输出结果为:[hello, Lambda]
} //将满足条件的字符串,放入集合中
public List<String> filterStr(List<String> list,Predicate<String> pre){
List<String> strList = new ArrayList<>();
for(String str:list){
//调用断言型接口中的方法,判断是否满足条件
if(pre.test(str)){
strList.add(str);
}
}
return strList;
}

方法引用

若Lambda 体中的内容有方法已经实现了,我们可以使用“方法引用”(可以理解为Lambda表达式的另一种表现形式)。

主要有三种语法格式:

  • 语法格式一: 对象::实例方法名
  • 语法格式二: 类名::静态方法名
  • 语法格式三: 类名::实例方法名

    条件:Lambda体中调用方法的参数列表和返回值类型,要与 函数式接口中抽象方法的参数列表和返回值类型保持一致

    下面我们对方法引用的三种语法格式,使用代码来看看是如何使用的吧:
    //对象::实例方法
@Test
public void test10(){
//使用Lambda表达式实现接口中的抽象方法
Consumer<String> con = (x) -> System.out.println(x);
con.accept("abcdef"); //使用 方法引用 的形式,实现接口中的抽象方法
//这里的 System.out 实际上是PrintStream的类型的匿名对象
//System.out::println; 也可以写成 PrintStream ps1 = System.out; ps1::println;
Consumer<String> con2 = System.out::println;
con2.accept("abcdef");
}

这里为了更好看方法引用的语法格式,我们可以创建一个Emp实体类:如下

public class Emp {

    private Integer id;

    private String name;

    public Emp() {
} public Emp(Integer id) {
this.id = id;
} public Emp(String name) {
this.name = name;
} public Emp(Integer id, String name) {
this.id = id;
this.name = name;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

接下来我们再使用Emp实体类的对象,通过 对象::实例方法 这种语法格式进行练习

    @Test
public void test11(){
Emp emp = new Emp();
//使用Lambda表达式实现Supplier接口中的抽象方法
Supplier<String> sup = () -> emp.getName();
String str = sup.get();
System.out.println(str); //使用方法引用代替Lambda表达式进行实现
//注意:这里的getName()的参数列表和返回值类型,和Supplier接口中的get()的参数列表和返回值类型是保持一致的
Supplier<String> sup2 = emp::getName;
String name = sup2.get();
System.out.println(name);
}

语法格式二:类名::静态方法名 的具体应用

    @Test
public void test12(){
Comparator<Integer> com01 = (x,y) -> Integer.compare(x,y);
int compare01 = com01.compare(10, 8);
System.out.println("通过Lambda表达式的比较结果为:"+compare01); //类名::静态方法名
Comparator<Integer> com02 = Integer::compare;
int compare02 = com02.compare(10, 8);
System.out.println("通过方法引用实现的比较结果为:"+compare02);
}

语法格式三:类名::实例方法名

使用该种语法格式时,必须要注意:若Lambda表达式参数列表中的第一个参数是 实例方法的调用者,而第二个参数是实例方法的参数时,则可以使用ClassName::method。

    @Test
public void test13(){
BiPredicate<String,String> bp01 = (x,y) -> x.equals(y);
boolean test01 = bp01.test("hello", "hello");
System.out.println("通过Lambda表达式的比较结果为:"+test01);//输出结果:通过Lambda表达式的比较结果为:true BiPredicate<String,String> bp02 = String::equals;
boolean test02 = bp02.test("hello", "hello");
System.out.println("通过方法引用实现的比较结果为:"+test02); //输出结果:通过方法引用实现的比较结果为:true
}

构造器引用

格式:ClassName::new

注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致

    @Test
public void test14(){
Supplier<Emp> sup = () -> new Emp();
//构造器引用方式
//调用的是无参构造:由于需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致,这里供给型结构Supplier中的get()是没有参数列表,所以调用的是无参构造
Supplier<Emp> sup02 = Emp::new;
Emp emp = sup02.get();
System.out.println(emp);
} @Test
public void test15(){
Function<Integer,Emp> fun = (x) -> new Emp(x);
//调用的是带一个参数的构造:因为函数型接口Function中的apply()有一个参数
Function<Integer,Emp> fun02 = Emp::new;
Emp emp = fun02.apply(101);
System.out.println(emp);
}

数组引用

语法格式:数组类型::new

    @Test
public void test16(){
//Lambda表达式实现
Function<Integer,String[]> fun01 = (x) -> new String[x];
String[] strs = fun01.apply(10);
System.out.println(strs.length); //输出结果: 10 //数组引用: 数组类型::new;
Function<Integer,String[]> fun02 = String[]::new;
String[] strs2 =fun02.apply(20);
System.out.println(strs2.length);//输出结果: 20
}

Lambda表达式学习笔记的更多相关文章

  1. C# Lambda表达式学习笔记

    本笔记摘抄自:https://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html,记录一下学习过程以备后续查用.     一.Lambda ...

  2. java lambda表达式学习笔记

    lambda是函数式编程(FP,functional program),在java8中引入,而C#很早之前就有了.在java中lambda表达式是'->',在C#中是‘=>’. 杜甫说:射 ...

  3. lambda 表达式学习笔记

    在Java中传递一个代码段并不容易,不能直接传递代码段.Java是一个面向对象语言,所以必须构造一个对象,这个对象的类需要一个方法能包含所需的代码.lambda的出现有效的解决这个问题,让代码变得更加 ...

  4. python函数和lambda表达式学习笔记

    1. python函数 不同于其他语言,python支持函数返回多个值 为函数提供说明文档:help(函数名)或者函数名.__doc__ def str_max(str1, str2): ''' 比较 ...

  5. C# Lambda 表达式学习之(三):动态构建类似于 c => c.Age == null || c.Age > 18 的表达式

    可能你还感兴趣: 1. C# Lambda 表达式学习之(一):得到一个类的字段(Field)或属性(Property)名,强类型得到 2. C# Lambda 表达式学习之(二):LambdaExp ...

  6. C# Lambda 表达式学习之(四):动态构建类似于 c => c.Age == 2 || c.Age == 5 || c => c.Age == 17 等等一个或多个 OrElse 的表达式

    可能你还感兴趣: 1. C# Lambda 表达式学习之(一):得到一个类的字段(Field)或属性(Property)名,强类型得到 2. C# Lambda 表达式学习之(二):LambdaExp ...

  7. Lamda表达式学习笔记二

    Lamda表达式学习笔记二 lamda表达式----方法引用 上一篇讲到Lamda体就是对函数式接口方法的实现 ,在方法体中我们可能会引用其他方法实现逻辑,所以在lamda体中我们可以直接引用器方法 ...

  8. Lamda表达式学习笔记一

    Lamda表达式学习笔记一 一.Lamda语法诠释 三傻大闹宝莱坞的主人公兰彻说的一句话让我映像深刻:用简单的语言来表达同样的意 我并不是说书上的定义怎么怎么不对,而是应该理解书本上的定义,并用简单的 ...

  9. java 8 中lambda表达式学习

    转自 http://blog.csdn.net/renfufei/article/details/24600507 http://www.jdon.com/idea/java/10-example-o ...

随机推荐

  1. List、Set、数组之间的转换

    数组转Collection 使用Apache Jakarta Commons Collections: import org.apache.commons.collections.Collection ...

  2. Redis-输入输出缓冲区

    一.client list id:客户端连接的唯一标识,这个id是随着Redis的连接自增的,重启Redis后会重置为0addr:客户端连接的ip和端口fd:socket的文件描述符,与lsof命令结 ...

  3. 安卓权威编程指南-笔记(第22章 深入学习intent和任务)

    本章,我们会使用隐式intent创建一个替换android默认启动器的应用.名为NerdLauncher. NerdLauncher应用能列出设备上的其他应用,点选任意列表项会启动相应应用. 1. 解 ...

  4. C++走向远洋——67(项目二、洗牌)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...

  5. python爬虫-提取网页数据的三种武器

    常用的提取网页数据的工具有三种xpath.css选择器.正则表达式 1.xpath 1.1在python中使用xpath必须要下载lxml模块: lxml官方文档 :https://lxml.de/i ...

  6. On Fixed-Point Implementation of Log-MPA for SCMA Signals

    目录 论文来源 摘要 基本概念 1.SCMA 2.SCMA编码器 研究内容 1.基于Log-MPA的SCMA解码器实现过程 论文创新点 借鉴之处 论文来源 本论文来自于IEEE WIRELESS CO ...

  7. 使用EventBus + Redis发布订阅模式提升业务执行性能

    前言 最近一直奔波于面试,面了几家公司的研发.有让我受益颇多的面试经验,也有让我感觉浪费时间的面试经历~因为疫情原因,最近宅在家里也没事,就想着使用Redis配合事件总线去实现下具体的业务. 需求 一 ...

  8. javascript常用工具函数总结(不定期补充)未指定标题的文章

    前言 以下代码来自:自己写的.工作项目框架上用到的.其他框架源码上的.网上看到的. 主要是作为工具函数,服务于框架业务,自身不依赖于其他框架类库,部分使用到es6/es7的语法使用时要注意转码 虽然尽 ...

  9. React官方脚手架不支持less问题解决

    create-react-app是由React官方提供,并推荐构建React单页应用程序的最佳方法,但是默认不支持less,需要手动集成: 1,必须手动安装less npm install less ...

  10. 05 JPAUtil工具类

    public final class JPAUtil { // JPA的实体管理器工厂:相当于Hibernate的SessionFactory private static EntityManager ...