Java Lambda 表达式

  • Post author:
  • Post category:java


Lambda 表达式是 Java 8 提供的一种语法,主要用来替代匿名内部类,传递函数式接口代码。

函数式接口:只有一个抽象方法的接口,还允许定义静态方法和默认方法。



基本语法

Lambda 表达式由

->

分隔为两部分,前面是方法的参数部分,后面

{}

内是方法的实现代码。

import java.io.File;

public class Test1 {

    public static void main(String[] args) {
        File file = new File(".");

        File[] fileArr = file.listFiles((File dir, String name) -> {
            return null != name && name.endsWith(".txt");
        });
    }

}

当主体代码只有一条语句的时候,

{}

括号 和

return

语句 可以省略。

此时,主体代码是一个表达式,表达式的值就是函数的返回值,结尾不能加分号

;

,也不能加

return

语句。

import java.io.File;

public class Test1 {

    public static void main(String[] args) {
        File file = new File(".");

        File[] fileArr = file.listFiles((File dir, String name) -> null != name && name.endsWith(".txt"));
    }

}

方法的参数类型声明也可以省略。

File file = new File(".");

File[] fileArr = file.listFiles((dir, name) -> null != name && name.endsWith(".txt"));

当参数只有一个的时候,参数部分的括号可以省略,参数为空或者多个的时候,括号不能省略。

File file = new File(".");

File[] files = file.listFiles(path -> path.getName().endsWith(".txt"));

Lambda 表达式通过推断的方式实现,与匿名内部类相似,它可以访问定义在主体代码外部的变量,对于局部变量,只能访问 final 类型的变量或者事实上只赋值一次的变量赋值。

File file = new File(".");
String msg = "消息";

File[] files = file.listFiles(path -> {
	System.out.println(msg);
	return path.getName().endsWith(".txt");
});

Java 会为每个匿名内部类生成一个类,但 Lambda 表达式不会生成类,也不会引入接口,不用担心会生成太多类的问题。



函数式接口

函数式接口:只有一个抽象方法的接口,还允许定义静态方法和默认方法。都有一个注解:@FunctionalInterface 。

Lambda 表达式可以赋值给函数式接口。

FileFilter filter = path -> path.getName().endsWith(".txt");

FilenameFilter fileNameFilter = (dir, name) -> name.endsWith(".txt");

Java 8 在 java.util.function 包中定义了大量的预定义函数式接口,用于常见类型的代码传递。

在这里插入图片描述

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class Test1 {

    public static void main(String[] args) {
        List<Student> students = Arrays.asList(new Student[]{
                new Student("张三", 89),
                new Student("李四", 94),
                new Student("王五", 90)
        });

        students = filter(students, t -> t.getScore() >= 90);

        for (Student student: students) {
            System.out.println(student.name + ":" + student.getScore());
        }
    }

    public static<E> List<E> filter(List<E> list, Predicate<E> pred) {
        List<E> retList = new ArrayList<>();
        for(E ele : list) {
            if (pred.test(ele)) {
                retList.add(ele);
            }
        }
        return retList;
    }

}

class Student {
    String name;
    double score;

	public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    public Student(String name, double score) {
        this.name = name;
        this.score = score;
    }
}



方法引用

Lambda 表达式经常用于调用对象的某个方法,比如:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class Test1 {

    public static void main(String[] args) {
        List<Student> students = Arrays.asList(new Student[]{
                new Student("张三", 89),
                new Student("李四", 94),
                new Student("王五", 90)
        });

        List<String> names = getNameList(students, t -> t.getName());

        for(String name: names) {
            System.out.println(name);
        }
    }

    public static<T, R> List<String> getNameList(List<T> list, Function<T, R> mapper) {
        List<String> retList = new ArrayList<>(list.size());
        for(T ele : list){
            retList.add((String) mapper.apply(ele));
        }
        return retList;
    }
}

class Student {
    String name;
    double score;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    public Student(String name, double score) {
        this.name = name;
        this.score = score;
    }

    public static String getCollegeName(){
        return "xxx School";
    }
}

对于

List<String> names = getNameList(students, t -> t.getName());

,可以进一步简化:

List<String> names = getNameList(students, Student::getName);

形如

Student::getName

称为方法引用,由

::

分隔为两部分,前面是类名或变量名,后面是方法名。

当 Lambda 表达式的操作仅仅是调用某个存在的方法时,可以使用方法引用。

此外,方法引用的方法的参数类型和返回值类型必须和接口一致。


  • 类名::类方法名
Supplier<String> s1 = () -> Student.getCollegeName();
Supplier<String> s2 = Student::getCollegeName;

  • 类名::实例方法名

在调用实例作为参数传入时使用。

Function<Student, String> f1 = (Student t) -> t.getName();
Function<Student, String> f2 = Student::getName;

  • 实例名::实例方法名
for (Student student: students) {
    Supplier<String> s2 = () -> student.getName();
    Supplier<String> s1 = student::getName;
}

  • 构造方法引用

对于构造方法,方法引用的语法是

<类名>::new

,比如:Student::new。

BiFunction<String, Double, Student> s1 = (name, score) -> new Student(name, score);
BiFunction<String, Double, Student> s2 = Student::new;
IntFunction<int[]> arrayMaker = int[]::new;
int[] array = arrayMaker.apply(10) // 创建数组 int[10]

参考:《Java 编程的逻辑》马俊昌



版权声明:本文为weixin_47076538原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。