Java8Lambda表达式使用总结

前言

Lambda表达式极大程度上简化了java代码的编写,提高了编程效率,“一时用一时爽,一直用一直爽!”下面就总结一下Lambda基本使用攻略吧!(以下内容根据个人学习笔记内容整理而来)

正片开始

先来体验一波Lambda表达式使用场景

#常规方式:  
Runnable r1 = new Runnable() {
        @Override
        public void run() {
            System.out.println("newBoys");
        }
    };
#Lambda表达式
     Runnable r2 = () -> System.out.println("newBoys");

#常规方式:
        Comparator<Integer> com1 = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1,o2);
        }
    };
    int compare1 = com1.compare(12,21);
#Lambda表达式
    Comparator<Integer> com2 = (o1,o2) -> Integer.compare(o1,o2);
    int compare2 = com2.compare(32,21);

Lambda表达式格式

  • 例:(o1,o2) -> Integer.compare(o1,o2)
  • 格式:
  • lambda操作符 或 箭头操作符。
  • 左边:lambda形参列表 (其实就是接口中的抽象方法的形参列表)。
  • 右边:lambda体 (其实就是重写的抽象方法的方法体)。

Lambda表达式语法(这里分为六种情况)

  • 语法一:无参,无返回值
#常规:      
Runnable r1=new Runnable() {
            @Override
            public void run() {
                System.out.println("我觉得你说得对");
            }
        };
#Lambda表达式
    Runnable r2=()-> System.out.println("我觉得你说的太对了");
  • 语法二:Lambda需要一个参数,但是没有返回值(消费者类型)
#常规:
        Consumer<String> con=new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println("我大概是吃饱了,我吃的是:"+s);
            }
        };
        con.accept("鸡肉块");
#Lambda表达式
Consumer<String> con1=(String s)->{System.out.println("我大概是吃饱了,我吃的是:"+s);};
  • 语法三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
#常规:
        Consumer<String> con=new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println("我大概是吃饱了,我吃的是:"+s);
            }
        };
        con.accept("鸡肉块");
#Lambda表达式
Consumer<String> con2=(s)->{System.out.println("我大概是吃饱了,我吃的是:"+s);};
  • 语法四:Lambda若只需要一个参数时,参数的小括号可以省略
#常规:
        Consumer<String> con=new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println("我大概是吃饱了,我吃的是:"+s);
            }
        };
        con.accept("鸡肉块");
#Lambda表达式
Consumer<String> con3=s->System.out.println("我大概是吃饱了,我吃的是:"+s);
  • 语法五:Lambda需要两个或以上的参数,多条执行语句,并且可以有返回值。
#常规:      
Comparator<Integer> com1=new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };
        System.out.println(com1.compare(24, 12));
#Lambda表达式
        Comparator<Integer> com2=(o1,o2)->{
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
        System.out.println(com2.compare(31, 44));
  • 语法格式六:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
#常规:      
Comparator<Integer> com1=new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };
	System.out.println(com1.compare(24, 12));
#Lambda表达式
	Comparator<Integer> com3=(o1,o2)->o1.compareTo(o2);
	System.out.println(com3.compare(1, 2));

->左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也可以省略。

->右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句),省略这一对{}和return关键字。

函数式接口

  • 什么是函数式接口呢?
  • 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。
  • 我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口。

所以Lambda表达式的本质其实就是作为函数式接口的实例,因此以前用的匿名实现类表示的现在都可以用Lambda表达式来写。

  • java内置4大核心函数式接口

java中Lambda的distinct java comparator lambda_函数式接口

可以说,日常编码使用lambda表达式简直不要太爽,那么在哪种情况下才能准确使用lambda表达式呢?正如之前所说,lambda表达式就是作为函数式接口的实例,所以当需要对一个函数式接口实例化时,可以大胆准确的使用lambda表达式。

当然,lambda还有更深层次的使用,可能会稍有难度:方法引用

方法引用

方法引用就是Lambda表达式,也就是函数式接口的一个实例。

  • 使用场景:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
  • 格式:类(或对象) :: 方法名
  • 具体使用分为以下三种情况
  • 情况一:对象 :: 实例方法
//Consumer中的void accept(T t)
//PrintStream中的void println(T t)
#lambda表达式
    Consumer<String> con1=str-> System.out.println(str);
    con1.accept("北京");
#对象 :: 实例方法
    PrintStream ps=System.out;
    Consumer<String> con2=ps::println;
    con2.accept("beijing");

//Supplier中的T get()
//Employee中的String getName()
#lambda表达式
    Employee emp=new Employee(1001,"Tom",23,5600);
    Supplier<String> sup1=()->emp.getName();
    System.out.println(sup1.get());
#对象 :: 实例方法
    Supplier<String> sup2=emp::getName;
    System.out.println(sup2.get());
  • 情况二:类 :: 静态方法
//Comparator中的int compare(T t1,T t2)
//Integer中的int compare(T t1,T t2)
#lambda表达式
    Comparator<Integer> com1=(t1,t2)->Integer.compare(t1, t2);
#类 :: 静态方法
    Comparator<Integer> com2=Integer::compare;

//Function中的R apply(T t)
//Math中的Long round(Double d)
#lambda表达式
    Function<Double,Long> func1=d->Math.round(d);
    System.out.println(func1.apply(12.3));
#类 :: 静态方法
    Function<Double,Long> func2=Math::round;
    System.out.println(func2.apply(12.6));
  • 情况三:类 :: 实例方法 (有点小难)
// Comparator中的int comapre(T t1,T t2)
// String中的int t1.compareTo(t2)
#lambda表达式
    Comparator<String> com1=(s1,s2)->s1.compareTo(s2);
    System.out.println(com1.compare("abc", "abd"));
#类 :: 实例方法
    Comparator<String> com2=String::compareTo;
    System.out.println(com2.compare("abd", "abm"));

//BiPredicate中的boolean test(T t1, T t2)
//String中的boolean t1.equals(t2)
#lambda表达式
    BiPredicate<String,String> pre1=(s1,s2)->s1.equals(s2);
    System.out.println(pre1.test("abc", "abc"));
#类 :: 实例方法
    BiPredicate<String,String> pre2=String::equals;
    System.out.println(pre2.test("abc", "abd"));
    
// Function中的R apply(T t)
// Employee中的String getName();
#lambda表达式
    Employee employee = new Employee(1001, "Jerry", 23, 6000);
    Function<Employee,String> func1=Employee::getName;
    System.out.println(func1.apply(employee));
#类 :: 实例方法
    Function<Employee,String> func2=Employee::getName;
    System.out.println(func2.apply(employee));
使用方法引用时要注意两点:
  • 要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同!(针对于情况1和情况2)
  • 当函数式接口方法的第一个参数是需要引用方法的调用者,并且第二个参数是需要引用方法的参数(或无参数)时:ClassName::methodName(针对于情况3)

和方法引用类似的还有两种方式:构造器引用数组引用

构造器引用

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

//Supplier中的T get()
//Employee的空参构造器:Employee()
#常规
Supplier<Employee> sup = new Supplier<Employee>() {
           @Override
           public Employee get() {
               return new Employee();
           }
       };
#lambda表达式
    Supplier<Employee>  sup1 = () -> new Employee();
    System.out.println(sup1.get());
#构造器引用
    Supplier<Employee>  sup2 = Employee :: new;
    System.out.println(sup2.get());

数组引用

可以把数组看做是一个特殊的类,则写法与构造器引用一致。

//Function中的R apply(T t)
#lambda表达式
    Function<Integer, String[]> func1=length->new String[length];
    String[] arr1=func1.apply(5);
    System.out.println(Arrays.toString(arr1));
#数组引用
    Function<Integer, String[]> func2=String[]::new;
    String[] arr2=func2.apply(10);
    System.out.println(Arrays.toString(arr2));

以上是我所了解的lambda表达式的使用基本方法,如有错误烦请指正哈。