Java8新特性 2020版 Lambda表达式
1.Lambda表达式的简介:
1.1Lambda表达式的概念:
lambda表达式,是java8的一个新特性,也是java8中最值得学习的新特性之一;
lambda表达式,从本质上来讲,是一个匿名函数,可以使用这个匿名函数,实现接口中的方法,对接口进行非常简洁的实现,从而简化代码。
1.2Lambda表达式使用的场景:
通常来讲,使用lambda表达式,是为了简化接口实现的;关于接口的实现,可以有很多方式来实现,例如:设计接口的实现类、使用匿名内部类。但是lambda表达式,比这两种方式都简单。
//项目源码:www.1b23.com
package
lambda;public interface SingleReturnSingleParameter {
public abstract int test(int a);}
//项目源码:www.1b23.com
package
lambda;public class LambdaDemo01 {
public static void main(String[] args) {
//无参数、无返回值的函数式接口
interfaceImpl();
}
private static void interfaceImpl(){
//1.使用显式的实现类对象
SingleReturnSingleParameter parameter1 = new Impl();
//2.使用匿名内部类实现
SingleReturnSingleParameter parameter2 = new SingleReturnSingleParameter() {
@Override
public int test(int a) {
return a * a;
}
};
//3.使用lambda表达式实现
SingleReturnSingleParameter parameter3 = a -> a * a;
System.out.println(parameter1.test(10));
System.out.println(parameter2.test(10));
System.out.println(parameter3.test(10));
}
}class Impl implements SingleReturnSingleParameter{
public int test(int a){
return a * a;
}}
1.3 Lambda表达式对接口的要求:
虽然说,lambda表达式可以在一定程度上简化接口的实现。但是,并不是所有的接口都可以使用lambda表达式来简洁实现的,lambda表达式毕竟只是一个匿名方法。当实现的接口中的方法过多或者过少的时候,lambda表达式都是不适用的,lambda表达式只能实现函数式接口,当且仅当接口中需要实现的方法有且只有一个的时候才能使用Lambda表达式。
1.4函数式接口:
1.4.1 基础概念:
如果说,一个接口中,要求实现类必须实现的抽象方法,有且只有一个!这样的接口,就是函数式接口。
//这个接口中,有且只有一个方法,是实现类必须实现的,因此是一个函数式接口interface Test1{
void test();}//这个接口中,实现类必须要实现的方法,有两个!因此不是一个函数式接口interface Test2{
void test1();
void test2();}//这个接口中,实现类必须要实现的方法,有零个,因此不是函数式接口interface Test3{
}//这个接口中,虽然没有定义任何的方法,但是可以从父接口中继承到一个抽象方法的,是一个函数式接口interface Test4 extends Test1{
}//这个接口,虽然里面定义了两个方法,但是default方法子类不是必须实现的,因此实现类实现这个接口的时候,必须实现的方法只有一个!是一个函数式接口。interface Test5{
void test5();
default void test(){}}//这个接口汇总的toString方法,是Object类中定义的方法;//此时,实现类在实现接口的时候,toSting可以不重写的!因为可以从父类Object中继承到!//此时,实现类在实现接口的时候,有且只有一个方法是必须要重写的,是一个函数式接口!interface Test6{
void test6();
String toString();}
1.4.2.@FunctionalInterface
是一个注解,用在接口之前,判断这个接口是否四一个函数式接口;如果是函数式接口,没有任何问题,如果不是函数式接口,则会报错,功能类似于@Override.
//项目源码:www.1b23.com
@FunctionalInterface
public interface SingleReturnSingleParameter {
public abstract int test(int a);}
2. Lambda表达式的语法:
2.1 Lambda表达式的基础语法:
Lambda表达式,其实本质来讲,就是一个匿名函数,因此在写lambda表达式的时候,不需要关心方法名是什么;实际上,我们在写lambda表达式的时候,也不需要关心返回值类型。
我们在写lambda表达式的时候,只需要关注两部分内容即可:参数列表 和方法体
lambda表达式的基础语法:
(参数) -> {
方法体
};
**参数部分:**方法的参数列表,要求和实现的接口中的方法参数部分一致,包括参数的数量和类型。
**方法体部分:**方法的实现部分,如果接口中定义的方法有返回值,则在实现的时候,注意返回值的返回。
-> : 分隔参数部分和方法体部分(Lambda运算符)
package lambda;/**
* 无参数无返回值的方法
*/@FunctionalInterfacepublic interface NoneReatureNoneParamter {
void test();}//项目源码:www.1b23.compackage lambda;/**
* 无返回值,多个参数的函数式接口
*/@FunctionalInterfacepublic interface NoneReturnMutipuleParameter {
void test (int a, int b);}package lambda;/**
* 无返回值有一个参数
*/@FunctionalInterfacepublic interface NoneReturnSingleParameter {
void test(int a);}package lambda;/**
* 有返回值且有参数列表的函数式接口
*/@FunctionalInterfacepublic interface SingleReturnMutipulParameter {
int test(int a,int b);}package lambda;/**
* 单个返回值,无参数的函数式接口
*/@FunctionalInterfacepublic interface SingleReturnNoneParameter {
int test();}package lambda;/**
* 一个参数,有返回值的函数式接口
*/@FunctionalInterfacepublic interface SingleReturnSingleParameter {
/*public abstract*/ int test(int a);}
package lambda.syntax;
import lambda.NoneReatureNoneParamter;
import lambda.NoneReturnMutipuleParameter;
import lambda.NoneReturnSingleParameter;
import lambda.SingleReturnMutipulParameter;
import lambda.SingleReturnNoneParameter;
import lambda.SingleReturnSingleParameter;
/**
* lambda基础语法//项目源码:www.1b23.com
*/
public class BasicSyntax {
public static void main(String[] args) {
//1.实现无参、无返回值的函数式接口
NoneReatureNoneParamter lambda1 = () -> {
System.out.println("这是一个无参数、无返回值的方法!!!");
};
lambda1.test();
//2.实现有一个参数无返回值的函数式接口
NoneReturnSingleParameter lambda2 = (int a) -> {
a += a;
System.out.println("这是一个有一个参数无返回值的函数式接口!!!a的值为:" + a);
};
lambda2.test(5);
//3.实现有多个参数无返回值的函数式接口
NoneReturnMutipuleParameter lambda3 = (int a,int b) -> {
int c = a + b;
System.out.println("这是有多个参数无返回值的函数式接口!!!c的值为:" + c);
};
lambda3.test(5, 4);
System.out.println("=========================================");
//4.实现函数有返回值没有参数的函数式接口
SingleReturnNoneParameter lambda4 = () -> {
int a = 45;
return a;
};
System.out.println("有返回值没有参数的函数式接口返回的值为:" + lambda4.test());
//5.实现函数有返回值有一个参数的函数式接口
SingleReturnSingleParameter lambda5 = (int a) -> {
a = a + 5;
return a;
};
System.out.println("有返回值有一个参数的函数式接口返回的值为:" + lambda5.test(5));
//6.实现函数有返回值有多个参数的函数式接口
SingleReturnMutipulParameter lambda6 = (int a,int b) -> {
return a + b;
};
System.out.println("有返回值有多个参数的函数式接口返回的值为:" + lambda6.test(4, 5));
}}
2.2 Lambda表达式的语法进阶
在上述代码中,的确可以使用lambda表达式实现接口,但是依然不够简洁,有简化的空间。
2.2.1 参数部分的精简
参数的类型
由于在接口的方法中,已经定义了每一个参数的类型是什么。而且在使用lambda表达式实现接口的时候,必须要保证参数的数量和类型需要和接口中方法保持一致,因此,此时Lambda表达式中的参数的类型可以省略不写。
注意事项:如果省略参数的类型,要保证:要省略,每一个参数的类型都必须省略不写;绝对不能出现:有的参数类型省略了,有的参数类型没有省略。
//多个参数、无返回值的方法实现NoneReturnMutipuleParameter lambda7 = (a, b) -> { int c = a + b; System.out.println("这是有多个参数无返回值的函数式接口!!!c的值为:" + c); }; lambda7.test(5, 4);
参数的小括号
只有当参数的数量是一个的时候,多了、少了都不能省略;
省略掉小括号的同时,必须要省略参数的类型。
//有一个参数、无返回值的方法实现NoneReturnSingleParameter lambda8 = a -> { a += a; System.out.println("这是一个有一个参数无返回值的函数式接口!!!a的值为:" + a); };lambda2.test(5);
如果方法的参数列表中的参数数量 有且只有一个,此时,参数列表的小括号是可以省略不写的;
注意事项:
参数的大括号
当大括号中是一条返回语句的时候,省略大括号的同时我们需要把return关键字也一并省略;
如果大括号里面的逻辑有且只有一条语句的时候,大括号可以省略不写;
注意事项:
当大括号里面是一条输出语句的时候大括号可以直接省略不写;
NoneReturnSingleParameter lambda2 = a -> System.out.println("这是一个有一个参数无返回值的函数式接口!!!a的值为:" + a); lambda2.test(5); System.out.println("============================");//实现函数有返回值有参数的函数式接口 SingleReturnSingleParameter lambda4 = (int a) -> a; System.out.println("有返回值有参数的函数式接口返回的值为:" + lambda4.test(10));
3.函数引用(项目源码:www.1b23.com
):
lambda表达式是为了简化接口的实现的,在lambda表达式中,不应该出现比较复杂的逻辑;如果在lambda表达式中出现了过于复杂的逻辑,会对程序的可读性造成非常大的影响,如果在lambda表达式中需要处理的逻辑比较复杂,一般情况会单独的写一个方法。在lambda表达式中直接引用这个方法即可。
**函数引用:**引用已经存在的方法,使其替代lambda表达式完成接口的实现。
3.1静态方法的引用:
语法:
类::静态方法
注意事项:
在引用的方法后面,不要添加小括号;
引用的这个方法,参数(数量、类型)和返回值,必须要跟接口中定义的一致。
示例:
import lambda.SingleReturnMutipulParameter;public class Syntax1 { //静态方法的引用 public static void main(String args[]){ //实习一个多个参数的、一个返回值的接口 //对一个静态方法的引用 //类::静态方法 SingleReturnMutipulParameter lambda1 = Calculator::calculate; System.out.println(lambda1.test(10, 10)); } private static class Calculator{ public static int calculate(int a,int b){ //稍微复杂的逻辑,计算a和b的差值的绝对值 if(a > b){ return a - b; } return b-a; } }}
3.2非静态方法的引用:
语法:
对象::非静态方法
注意事项:
在引用的方法后面,不要添加小括号;
引用的这个方法,参数(数量、类型)和返回值,必须要跟接口中定义的一致。
示例:
import lambda.SingleReturnMutipulParameter;public class Syntax2 { public static void main(String[] args) { // 对非静态方法的引用,需要使用对象来完成 SingleReturnMutipulParameter lambda = new Calculator() :: calculator; System.out.println(lambda.test(10, 30)); } private static class Calculator{ public int calculator(int a,int b){ return a > b ? a - b: b - a; } }}
3.3 构造方法的引用:
使用场景:
如果一个函数式接口中定义的方法,仅仅是俄日了得到一个类的对象,此时我们就可以使用构造方法的引用,简化这个方法的实现。
语法:
类名::new
注意事项:
可以通过接口中的方法的参数,区分引用不同的构造方法;
示例:
public class Lambda2 { private static class Person{ private String name; private int age; public Person(String name, int age) { super(); this.age = age; this.name = name; System.out.println("Person的两个参数的构造方法执行"); } public Person() { System.out.println("Person的无参数的构造方法执行"); } public Person(String name){ this.name = name; System.out.println("Person的一个参数的构造方法执行"); } } @FunctionalInterface private interface GetPersonWithNoneParameter{ Person get(); } @FunctionalInterface private interface GetPersonWithSingleParameter{ Person get(String name); } @FunctionalInterface private interface GetPersonWithMutipleParameter{ Person get(String name,int age); } public static void main(String[] args) { //使用lambda表达式,实现GetPersonWithNoneParameter接口 GetPersonWithNoneParameter getPerson = Person :: new; //使用lambda表达式,实现GetPersonWithSingleParameter接口 GetPersonWithSingleParameter getPerson1 = Person :: new; //使用lambda表达式,实现GetPersonWithMutipleParameter接口 GetPersonWithMutipleParameter getPerson2 = Person :: new; Person person = getPerson.get(); Person person1 = getPerson1.get("在路上"); Person person2 = getPerson2.get("在路上", 23); }}
3.4 对象方法(非静态方法)的特殊引用:
如果在使用lambda表达式,实现某些接口的时候,lambda表达式汇总包含了某一个对象,此时方法体中,直接使用这个对象调用他的某一个方法就可以完成整体的逻辑。其他的参数,可以作为调用方法的参数;此时,可以对这种实现进行简化。
示例:
public class Lambda3 { private static class Person{ private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } } @FunctionalInterface private interface MyInterface{ //String get(Person person); void set(Person person,String name); } public static void main(String[] args) { Person person = new Person(); person.setName("xiaoming"); //MyInterface lambda = x -> x.getName(); //MyInterface lambda1 = Person :: getName; //System.out.println(lambda1.get(person)); MyInterface lambda1 = (x,n) -> x.setName(n); MyInterface lambda2 = Person :: setName; lambda2.set(person, "xiaohua"); System.out.println(person.getName()); }}