1、lambda表达式

       使用lambda表达式设计的代码更加简洁,通过lambda表达式可以代替匿名内部类来实现接口,本质就是一个匿名函数。

2、lambda表达式的语法:

(int a, int b)->{return a+b};

本质是一个函数:有返回值,方法名,参数列表,方法体

int add(int a, int b){
    return a+b;
}

而lambda只有参数列表和方法体。

3、语法细节:接口方法参数,无参,单个参数,两个参数,有返回值,无返回值等情况

public static void main(String[] args){
    If1 if1=()->{
        System.out.println("无参数无返回值");
    };
    if1.test();

    If2 if2=(int a)->{
        System.out.println("单个参数无返回值,a="+a);
    };
    if2.test(3);

    If3 if3=(int a, int b)->{
        System.out.println("多个参数无返回值,a+b="+(a+b));
    };
    if3.test(3,4);

    If4 if4=()->{
        return 21;
    };
    System.out.println("无参数有返回值"+if4.test());

    If5 if5=(int a)->{
        return a;
    };
    System.out.println("单参数有返回值"+if5.test(5));

    If6 if6=(int a, int b)->{
        return a+b;
    };
    System.out.println("多参数有返回值"+if6.test(5,10));
}   
    
interface If1{
    //无参无返回值
    void test();
}

interface If2{
    //单个参数,无返回值
    void test(int a);
}

interface If3{
    //两个参数无返回值
    void test(int a, int b);
}

interface If4{
    //无参数有返回值
    int test();
}

interface If5{
    //单个参数有返回值
    int test(int a);
}

interface If6{
    //两个参数有返回值
    int test(int a, int b);
}

4、lambda表达式精简语法

(1)参数类型可以省略。

(2)如果只有一个参数,()可以省略。

(3)如果方法体只有有一条语句,{}可以省略。

(4)如果方法体中唯一的语句是return,则省略大括号的同时也要省略return。

public static void main(String[] args){
    If1 if1=()->System.out.println("无参数无返回值");
    if1.test();

    If2 if2=a-> System.out.println("单个参数无返回值,a="+a);
    if2.test(3);

    If3 if3=(a, b)->System.out.println("多个参数无返回值,a+b="+(a+b));
    if3.test(3,4);

    If4 if4=()-> 21;
    System.out.println("无参数有返回值"+if4.test());

    If5 if5=a-> a;
    System.out.println("单参数有返回值"+if5.test(5));

    If6 if6=(a, b)-> a+b;
    System.out.println("多参数有返回值"+if6.test(5,10));
}   
    
interface If1{
    //无参无返回值
    void test();
}

interface If2{
    //单个参数,无返回值
    void test(int a);
}

interface If3{
    //两个参数无返回值
    void test(int a, int b);
}

interface If4{
    //无参数有返回值
    int test();
}

interface If5{
    //单个参数有返回值
    int test(int a);
}

interface If6{
    //两个参数有返回值
    int test(int a, int b);
}

5、方法引用:

有时候多个lambda表达式的实现函数是一样的,就可以封装成通用方法,便于维护。

这时候可以用方法引用实现。

语法是    对象::方法

假如是static方法,可以直接  类名::方法

public class Program{
    public static void main(String[] args){
        Program program = new Program();
        
        If5 if5=program::testA;
        System.out.println(if5.test(5));

        If52 if52=program::testA;
        System.out.println(if52.test(10));

        If53 if53=Program::testB;
        System.out.println(if53.test(3));

        If54 if54=Program::testB;
        System.out.println(if54.test(5));

    } 

    public int testA(int a){
        return a-2;
    }
    public static int testB(int a){
        return a-2;
    }

    interface If5{
        //单个参数有返回值
        int test(int a);
    }
}

6、构造方法引用:

如果函数式接口的实现恰好可以通过调用一个类的构造方法来实现,那么就可以使用构造方法引用。

语法: 类名::new

定义一个Dog实体,实现无参和有参构造方法。

public class Dog{
    public static void main(String[] args){
        
    }
    private String name;

    private int age;

    public Dog(){
        System.out.println("无参构造方法");
    } 
    public Dog(String name, int age){
        System.out.println("有参构造方法");
        this.name = name;
        this.age = age;
    }

    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }
    public void setAge(int age){
        this.age = age;
    }
    public int getInt(){
        return age;
    }

    @Override
    public String toString(){
        return "Dog:{" +
                "name=" + name +
                ",age=" + age +
                "}"
    }

}

 再定义两个接口

interface DogService1{
    Dog getDog();
}

interface DogService2{
    Dog getDog(String name, int age);
}

测试:

public class Test(){
    public static void main(String[] args){
        //普通方式
        DogService dogService = () -> {
            return new Dog();
        }
        System.out.println(dogService.getDog());

        //简化方式
        DogService dogService2 = () -> new Dog();
        System.out.println(dogService2.getDog());

        //构造方法引用
        DogService dogService3 = Dog::new;
        System.out.println(dogService3.getDog());

        //构造方法引用有参
        DogService2 dogService21 = Dog::new;
        System.out.println(dogService21.getDog("小米", 11));
    }
}

7、综合实例:

public class program{
    public static void main(String[] args){
        List<Dog> list = new ArrayList<>();
        list.add(new Dog("aa", 1));
        list.add(new Dog("bb", 8));
        list.add(new Dog("cc", 4));
        list.add(new Dog("dd", 6));
        list.add(new Dog("ee", 7));
        list.add(new Dog("ff", 9));
        
        System.out.println("lambda表达式集合排行");
        list.sort((o1, o2)-> o1.getAge()-o2.getAge());

        System.out.println("lambda表达式遍历集合");
        System.out.println(System.out::println);
    }
}

8、@FunctionInterface注解

我们常用的一些接口Callable、Runnable、Comparator等在JDK8中都添加了@FunctionalInterface注解。

1、该注解只能标记在”有且仅有一个抽象方法”的接口上。
2、JDK8接口中的静态方法和默认方法,都不算是抽象方法。
3、接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
4、该注解不是必须的,如果一个接口符合”函数式接口”定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。