lambda表达式是JDK8的一个重要的特性,它使用了一个清晰简洁的表达式来表达一个接口,同时lambda表达式也简化了对集合以及数组的遍历,过滤和提取等操作。

1.lambda表达式入门

在匿名内部类中存在一个问题,如果匿名内部类的实现非常复杂,例如只包含一个抽象方法的接口,那么匿名内部类的语法仍然显得比较冗余。 在Java JDK8中增加了一个特性的lambda表达式,这种表达式这针对有一个抽象方法的接口实现,以简介的形式实现接口功能来作为方法参数。

一个lambda表达式由三个部分组成,分别为参数列表,“->”和表达式主体,其语法如下。

([数据参数 参数名,数据参数 参数名....])->{表达式主体}

(1)([数据参数 参数名,数据参数 参数名....]):用来向表达式主体传递接口方法需要的参数,多个参数名中间必须要使用逗号隔开。在编写表达式的时,可以省略参数的数据类型,后面的表达式主体会自动校验和匹配。同时,如果只有一个参数,则可以省略括号()。

(2)->:表示lambda表达式箭牌,用来指定数据指向,不能省略。

(3){表达式主体}:由单个表达式或语句组成的主体,本质就是接口中抽象方法的实现。

interface Animal{
    public void shout();
}

public class test {
    public static void main(String[] args) {
        String name="小花";

        //使用lambda表达式作为参数传递给shoutAnimal()方法
        shoutAnimal(()-> System.out.println("lambda表达式"+"喵喵喵..."));

        //使用匿名表达式的形式作为参数传递给shoutAnimal()方法
        shoutAnimal(new Animal() {
            @Override
            public void shout() {
                System.out.println("匿名内部类"+"喵喵喵...");
            }
        });
    }
    public static void shoutAnimal(Animal animal){
        animal.shout();
    }
}

alt

2.函数式接口

在使用lambda表达式可以实现匿名内部类的时候,他在使用的时候有一个局限,即接口中只有一个抽象方法时才能使用lambda表达式来代替匿名内部类的实现。这是因为lambda表达式是一个基于函数式接口的实现。函数式接口是指有且只有一个抽象方法的接口。Lambda表达式就是Java中函数式编程的体现,只有确保接口中有且只有一个抽象方法,lambda表达式才能顺利的推导出实现的这个接口中的方法。

在jdk8中,专门为函数式接口引入了一个@FunctionalInterface注解,可以注解只是显式的标注的接口是一个函数式接口,并强制编译器进行更严格的检查,确保该接口是函数式接口,如果不是函数式接口,那么编译器就会报错,而对程序运行并没有实质性的影响。

@FunctionalInterface
interface Animal{
    public void shout();
}
@FunctionalInterface
interface Calculate{
    int sum(int a,int b);
}
public class test {
    public static void main(String[] args) {
        String name="小花";

        //使用lambda表达式作为参数传递给shoutAnimal()方法
        shoutAnimal(()-> System.out.println("lambda表达式"+"喵喵喵..."));
        showSum(10,20,(x,y)->x+y);
    }
    public static void shoutAnimal(Animal animal){
        animal.shout();
    }
    public static void showSum(int x,int y,Calculate calculate){
        System.out.println("x+y="+calculate.sum(x,y));
    }
}

alt

3.方法引用和构造器的引用

3.1 类名引用静态方法

类名引用静态方法就是通过类名对静态方法的引用,该类可以式Java自带的特殊类,也可以是自己定义的普通类。

@FunctionalInterface
interface Calcable{
    int calc(int num);
}
class Math{
    public static int abs(int num){
        if(num<0){
            return -num;
        }else {
            return num;
        }
    }
}
public class test {
    public static void pringtAbs(int num,Calcable calcable){
        System.out.println(calcable.calc(num));
    }
    public static void main(String[] args) {
        //使用Lambda表达式的方式:    (x,y,...)->类名.类静态方法名(x,y,...)
        pringtAbs(-10,n->Math.abs(n));
        //使用方法引用的方式:     类名::类静态方法名
        pringtAbs(-11,Math::abs);
    }
}

alt

@FunctionalInterface
interface Calcable{
    int calc(int x,int y);
}
class Math{
    public static int add(int x, int y){
        return x+y;
    }
}
public class test {
    public static void pringtAbs(int x,int y,Calcable calcable){
        System.out.println(calcable.calc(x,y));
    }
    public static void main(String[] args) {
        //使用Lambda表达式的方式
        pringtAbs(111,-1015,(x,y)->Math.add(x,y));
        //使用方法引用的方式
        pringtAbs( 12,-11,Math::add);  //不用写参数,注意两者的区别
    }
}

alt

2. 类名引用普通方法

类名引用普通方法指的是通过一个普通类的类名来对其普通方法进行的引用

@FunctionalInterface
interface Printable{
    void print(StringUtils stringUtils,String str);
}
class StringUtils{
    public void printUpperCase(String str){
        System.out.println(str.toUpperCase());
    }
}
public class test {
    public static void printUpper(StringUtils stringUtils,String str,Printable printable){
        printable.print(stringUtils,str);
    }
    public static void main(String[] args) {
        //使用lambda表达式:    (x,y,...)->对象名x.类普通方法名(y,...)
        printUpper(new StringUtils(),"hello",(object,t)->object.printUpperCase(t));

        //使用方法引用的方式:    类名:类普通方法名
        printUpper(new StringUtils(),"hello",StringUtils::printUpperCase);
    }
}

alt

3. 构造器引用方法

构造器引用指的是对类自带的构造器的引用

@FunctionalInterface
interface PersonBuilder{
    Person buildPerson(String name);
}
class Person{
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
public class test {
    public static void printName(String name,PersonBuilder builder){
        System.out.println(builder.buildPerson(name).getName());
    }
    public static void main(String[] args) {
        //使用lambda表达式:			(x,y,...)->new 类名(x,y...)
        printName("张三",name -> new Person(name));
        
        //使用构造器的引用方式:			类名::new
        printName("张三",Person::new);

    }
}

alt

4. 对象名引用方法

对象名引用方法指的是通过实例化对象的名称来对其方法进行的引用

@FunctionalInterface
interface Printable{
    void print(String str);
}
class StringUtils{
    public void printUpperCase(String str){
        System.out.println(str.toUpperCase());
    }
}
public class test {
    public static void printUpper(String str,Printable pt){
        pt.print(str);
    }
    public static void main(String[] args) {
        StringUtils stringUtils = new StringUtils();

        //使用lambda表达式:			(x,y,...)->对象名.实例化方法名(x,y..)
        printUpper("hello",str -> stringUtils.printUpperCase(str));
        
        //使用方法引用的方式:			对象名::实例化方法名
        printUpper("hello",str -> stringUtils.printUpperCase(str));
    }
}

alt