高效开发:JDK1.8的Lambada表达式

Posted Java架构师(公众号:毛奇志)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高效开发:JDK1.8的Lambada表达式相关的知识,希望对你有一定的参考价值。

一、 lambada表达式简介

我们知道对于Java变量可以赋给其一个值,而如果想将"一块代码(一个完整的方法)"赋给一个Java变量,如下所示,怎么做呢?

在这里插入图片描述

你可能认为就是下面的方式来实现

在这里插入图片描述

很显然,这个并不是一个很简洁的写法,我们采用Java8的Lambada表达式来实现,那么如何简化呢?

整个过程:去掉修饰符(public等)、去掉函数的名字(因为已经赋给变量,变量知道此方法名–往后知道抽象方法唯一,不需要

方法名了)、去掉返回值类型(编译器可以推断)、去掉参数类型(编译器可以推断参数类型),最终的结果是下面的形式:

在这里插入图片描述

分析:这样的最终结果就是把"一块代码赋给一个变量"。或者说是"这个被赋给一个变量的函数"就是一个Lambada表达式,由于Lambada可以直接赋给一个"变量",我们可以把Lambda(这里表示为变量)作为参数传递给函数。

但是变量(Lambada表达式)的类型是什么呢?所有的Lambada的类型都是一个接口,而Lambada表达式本身(“那段代码”)就是一个接口的实现,这是理解Lambada的一个关键所在,理解上可以这样认为:Lambada表达式就是产生 一个实现接口中唯一的抽象方法的子实现类的对象,因此最终结果:

在这里插入图片描述

Lambda 与函数式接口的关系:Lambda 依赖于函数式接口,Lambda 需要函数式接口的支持。

函数式接口:接口中只有一个需要被实现的抽象函数

说明:为了避免后来的人在接口中增加新的接口函数,导致其有多个接口函数需要被实现,变成非函数式接口,引入了一个新的Annotation(注解):@FunctionalInterface。可以把他它放在一个接口前,表示这个接口是一个函数式接口,加上它的接口不会被编译,如果加上此标记就不能再添加其他的抽象方法,否则会报错。它有点像@Override,都是声明了一种使用意图,避免你把它用错。

总结:lambda表达式本质是匿名方法

二、 Lambda 表达式的结构

2.1 Lambada表达式的语法

Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “ ->”,该操作符被称为 Lambda 操作符或箭头操作符。它将 Lambda 分为两个部分:

即:(参数列表)—>{express或statements}

左侧: 指定了 Lambda 表达式需要的方法参数列表

右侧: 指定了 Lambda 体,即 Lambda 表达式要执行的功能

2.2 使用说明

(1)一个 Lambda 表达式可以有零个或多个参数,参数的类型既可以明确声明,也可以根据上下文来推断

(2)圆括号内,方法参数列表之间用逗号相隔

(3)当只有一个参数,且其类型可推导时,圆括号()可省略

(4)Lambda 表达式的主体,如果有返回值,return也可以省略,同时body中的“;”也可以省略。匿名函数(这里指lambda表达式)的返回类型与该主体表达式一致,若没有返回值则为空;

lambda表达式本质是匿名方法

(5)Lambda 表达式的主体可包含零条或多条语句。如果 Lambda 表达式的主体只有一条语句,花括号{}可省略;如果 Lambda 表达式的主体包含一条以上语句,则表达式必须包含在花括号{}中(形成代码块)。

三、简单应用

对比匿名内部类做为参数传递和Lambda表达式作为参数来传递–Runnable,Callable接口(具体看例子)

3.1 常见的函数式接口-Runnable接口-方法没有参数没有返回值(匿名内部类作为参数传递和Lambda表达式作为参数来传)

public class LamadaDemo0 {
    public static void main(String[] args) {

        //匿名内部类的形式开启一个线程   需要一个Runnable接口的实现类
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类:我爱你!");
            }
        }).start();

        //Lambada表达式创建匿名内部类开启一个线程
        new Thread(() -> System.out.println("Lambda表达式:我爱你!")).start();
    }
}

输出:

匿名内部类:我爱你!
Lambda表达式:我爱你!

3.2 常见的函数式接口-Comparable接口-方法一个参数一个返回值(匿名内部类作为参数传递和Lambda表达式作为参数来传)

 public class LamadaDemo0 {
    public static void main(String[] args) {
        // 常见的函数式接口:Runnable、 Comparable--排序
        // 需要不是一个接口实现类作为实参,需要不是一个接口实现类中的方法调用,无法用匿名内部类
        Comparable<Integer> comparable=new Comparable<Integer>() {
            @Override
            public int compareTo(Integer o) {
                return 0;
            }
        };
        int res0 = comparable.compareTo(3);
        System.out.println(res0);


        //Lambada表达式的方法  去掉访问修饰符、去掉返回值、去掉方法名、只要实参和方法体和返回值
        // 实参为a,返回为a
        Comparable<Integer> com=(a)->a;    
        int res2 = com.compareTo(3);
        System.out.println(res2);
    }
}

输出:

0
3

3.3 Comparator接口实现类

import java.util.Comparator;
import java.util.TreeSet;

public class LamadaDemo0 {
    public static void main(String[] args) {

        //TreeSet排序新高度---Comparator本身有泛型
        // 这里是一个接口实现类作为实参,所以可以用匿名内部类
        TreeSet treeSet1 = new TreeSet<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer a, Integer b) {
                return b - a;
            }
        });
        treeSet1.add(1);
        treeSet1.add(2);
        System.out.println(treeSet1);

        //Lambada表达式的形式  实参为a,b,返回a-b
        TreeSet treeSet2 = new TreeSet<Integer>((a, b) -> a - b);
        treeSet2.add(1);
        treeSet2.add(2);
        System.out.println(treeSet2);
    }
}

输出:

[2, 1]
[1, 2]

3.4 自定义一个函数式接口(接口里面只有一个需要实现的抽象方法,接口上加上@FunctionalInterface函数式接口注解)

public class LamadaDemo0 {
    public static void main(String[] args) {
        //匿名内部类
        new A(new MyFunctionalInterface<String>() {
            @Override
            public void method(String s) {
                System.out.println(s);
            }
        });


        //Lamada表达式的用法  匿名方法
        new A((s) -> System.out.println(s));

        MyFunctionalInterface myFunctionalInterface = new MyFunctionalInterface<String>() {
            @Override
            public void method(String s) {
                System.out.println(s);
            }
        };
        myFunctionalInterface.method("您好好");

        MyFunctionalInterface myFunctionalInterface1 =  (s) -> System.out.println(s);
        myFunctionalInterface1.method("我哈哈");
    }
}

@FunctionalInterface
interface MyFunctionalInterface<T> {
    void method(T s);//自定义函数式接口---注意其定义
    //用一个注解 @FunctionalInterface 去检测这个接口是不是一个函数式接口
}

class A {
    MyFunctionalInterface myFunctionalInterface;

    public A(MyFunctionalInterface myFunctionalInterface) {
        this.myFunctionalInterface = myFunctionalInterface;
    }
}

输出:

您好好
我哈哈

3.5 使用function包中已有的函数式接口

import java.util.function.Supplier;

public class LamadaDemo0 {
    public static void main(String[] args) {
        // 匿名内部类
        new A(new Supplier<Double>() {
            @Override
            public Double get() {
                return 3.1;
            }
        });

        //Lambda表达式 匿名方法
        new A(() -> 3.1);

        Supplier supplier = new Supplier<Double>() {
            @Override
            public Double get() {
                return 3.1;
            }
        };
        System.out.println(supplier.get());
        Supplier supplier1 = () -> 3.2;
        System.out.println(supplier1.get());
    }
}

class A {  // 新建一个类,使用Supplier作为参数
    Supplier supplier;

    public A(Supplier supplier) {
        this.supplier = supplier;
    }
}

输出:

3.1
3.2

以上是关于高效开发:JDK1.8的Lambada表达式的主要内容,如果未能解决你的问题,请参考以下文章

java lambada表达式

lambada表达式

JDK1.8新特性Lambda表达式简化if-else里都有for循环的优化方式

JDK1.8中的stream的操作总结

JDK1.8新特性

一篇文章带你总结 Lambada 表达式常见使用