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());
    	}}


09-09 07:49