java1.8中的新函数_JavaSE高级 -JDK1.8新特性-Lambda表达式-函数式接口

一、Lambda表达式:

标准格式由三个部分组成:

一些参数

一个箭头

一段代码

Lambda表达式的标准格式:

(参数类型 参数名称)->{ 代码语句 }

格式说明:

小括号的语法与传统方法参数列表一致:无参数则留空,多个参数就用逗号隔开

-> 新引入的语法格式,代表指向动作

大括号内的语法和传统方法体的要求一致

总结:Lambda表达式简化匿名内部类,首先要求是接口,其次是该接口只有一个抽象方法。

无参数:

无参数:不需要任何条件即可执行该方案

无返回值:该方案不产生任何结果

代码块(方法体):该方案的具体执行步骤

同样的语义体现在Lambda中更简单:

()-> System.out.println("多线程执行!");

前面的一对小括号即run方法的参数(无),代表不需要任何条件。

中间的箭头代表将前面的参数传递给后面的代码。

后面的输出语句是业务逻辑代码。

有参数和返回值:

例如:Arrays.sort()

传统写法:

实际上只有参数和方法体是重要的

Lambda写法:

// Lambda

Arrays.sort(array, (Person a, Person b) -> {

return a.getAge() - b.getAge();

});

省略格式:

省略规则:

在Lambda标准格式基础上,使用省略的写法规则是:

小括号内的参数类型可省略;

如果小括号内有且仅有一个参数,则小括号可以省略;

如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、语句分号,必须省略return关键字。

可推导即可省略:

Lambda强调的是“做什么”而不是“怎么做”,所以凡是可以根据上下文推导得知的信息,都可以省略。

//Runnable接口简化:

() -> System.out.println("多线程任务执行!")

//Comparator接口简化:

2. Arrays.sort(array, (a, b) -> a.getAge() - b.getAge());

//ActionListener接口简化:

3.button.addActionListener(e -> System.out.println("按钮被点击了!"));

Lambda的前提条件:

Lambda的语法非常简洁,完全没有面向对象的束缚。但是使用时有几个问题需要特别注意:

使用Lambda 必须具有接口,且要求接口中有且仅有一个抽象方法。

无论时JDK内置的Runnable 、comparator 接口还是自定义接口,只有当接口中的抽象方法 存在且唯一时,才可以使用Lambda。

使用Lambda必须具有上下文推断。

也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。

ps:有且仅有一个抽象方法的接口,称为:函数式接口。

二、函数式接口

1.概念:

函数式接口(Funtional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。注解:@FuntionalInterface 可以检测接口是否是一个函数式接口。(在合作开发中,避免同事修改此接口造成错误)。

2.函数的定义和使用

定义一个函数式接口:

//问候

@FunctionalInterface

public interface GreetingService {

void sayMessage();

}

定义此函数式接口的实现类:

public class GreetingServiceImpl implements GreetingService {

@Override

public void sayMessage() {

System.out.println("say hello!");

}

}

函数式接口一般作为方法的参数和返回值类型:

public class Demo {

//定义一个方法,参数使用函数式接口GreetingService

public static void show(GreetingService greetingService){

greetingService.sayMessage();

}

public static void main(String[] args) {

//调用show方法,方法的参数是一个接口,所以可以传递接口的实现类

show(new GreetingServiceImpl());

//调用show方法,方法的参数是一个接口,所以可以传递接口的匿名内部类

show(new GreetingService() {

@Override

public void sayMessage() {

System.out.println("使用匿名内部类重写接口中的抽象方法");

}

});

}

}

Lambda表达式的写法:

public class Demo {

//定义一个方法,参数使用函数式接口GreetingService

public static void show(GreetingService greetingService){

greetingService.sayMessage();

}

public static void main(String[] args) {

//调用show方法,使用lambda表达式

show(()->System.out.println("使用lambda重写接口中的抽象方法"));

}

}

3.Lambda表达式的好处:

优势:1.简化代码,更为简洁 2.延迟加载

有些场景的代码执行后,结果不一定会被使用,从而造成性能的浪费。而Lambda表达式是延迟执行的,这正好可以作为解决方案,提升性能。

例如:性能浪费的日志案例:

ps: 日志可以帮助我们快速定位问题,记录程序运行中的情况,以便项目的监控和优化。

一种典型的场景就是对参数进行有条件使用,例如对日志消息进行拼接后,在满足条件的情况下打印输出:

public class Test {

public static void main(String[] args) {

String msgA = "hello";

String msgB = "world";

String msgC = "java";

showLog(1, msgA + msgB + msgC);

}

private static void showLog(int level, String msg) {

//当日志级别为1时,打印日志

if (level == 1) {

System.out.println(msg);

}

}

}

这段代码存在的问题是:无论级别是否满足要求,作为showLog方法的第二个参数,三个字符串一定会首先被拼接并传入方法内,然后才会进行级别判断。如果级别不符合要求,那么字符串的拼接操作就白做了,存在性能的浪费。

使用Lambda 必然先定义一个函数式接口:

@FunctionalInterface

interface MessageBuilder{

String buildMessage();

}

对showLog方法进行改造:

public class Test {

public static void main(String [] ags){

String msgA = "hello";

String msgB = "world";

String msgC = "java";

//lambda实现显示日志

showLogLambda(1,()->msgA+msgB+msgC);

//证明lambda表达式的延迟执行

showLogLambda(1,()->{

System.out.println("Lambda执行!");

return msgA+msgB+msgC;

});

}

private static void showLogLambda(int level,MessageBuilder builder){

if(level==1){

System.out.println(builder.buildMessage());

}

}

}

这样一来,只有当级别满足要求的时候,才会进行三个字符串的拼接;否则三个字符串将不会拼接。

三、常用的函数式接口:

四大核心函数接口:

函数式接口 参数类型 返回类型 用途

Supplier接口,供给型接口 无 T 返回的类型为T的对象,T get()

Consumer 接口,消费型接口 T void 对类型为T的对象应用操作,void accept(T t)

Function 函数型接口 T R 根据类型T的参数获取类型R的结果,R apply(T t)

Predicate< T>接口,断定型接口 T boolean 用于条件判断的场景,boolean test(T t)

Supplier< T>接口: 函数式接口

T get();

供给型

特点:使用其get(),可以返回一个与接口泛型一致的数据。

Consumer< T>接口:函数式接口

accept(T t)

消费型

default andThen() 默认方法

特点:提供一个与泛型一致数据类型的参数。

Function接口:函数式接口

R apply(T t)

default andThen(Function

根据泛型的类型,将前者的T类型转化为R类型。

Predicate接口:函数式接口

boolean test(T t); 返回true、false。

default Predicateand (Predicate super T> other ) 与

default Predicatenegate() 非

default Predicateor (Predicate super T> other) 或

对某种类型的数据进行判断,从而得到一个boolean值结果。

四、方法的引用:

方法的引用的概述:

方法引用使得开发者可以直接引用现存的方法,Java类的构造方法或者实例对象。方法的引用和Lambda表达式配合使用,使得Java类的构造方法看起来紧凑而简洁,没有很多复杂的模板代码。

静态方法的引用:

引用格式:

类名::静态方法

简化步骤:

定义一个静态方法,把需要简化的代码放到一个静态方法中。

注意事项:

被引用的方法的参数列表,要和函数式接口中的抽象方法的参数列表一致。

如果函数式接口中的抽象方法有返回值,则被引用的方法必须也有相同返回值。

如果函数式接口中的抽象方法没有返回值,则被引用的方法可以有返回值,也可以没有返回值。

实例方法的引用:

引用格式:

对象::实例方法

简化步骤:

定义一个实例方法,把需要的代码放到实例方法中。

注意事项:

被引用的方法的参数列表,要和函数式接口中的抽象方法的参数列表一致。

特定类型的方法引用:

引用格式:

特定类型::方法

特点类型:

String,任何类型

注意事项:

如果函数式接口中的抽象方法的参数列表中,第一个参数作为了后面的方法的调用者,并且

其余参数作为后面方法的形参,那么就可以用特定类型的方法引用了。

构造器的引用:

引用格式:

类名::new

注意事项:

函数式接口的抽象方法的形参列表和构造器的形参列表一致,抽象方法返回值类型即为构造器所属的类的类型。

类似于 s->new Student(s) =>Student::new

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值