Java Lambda表达式


Lambda表达式实际是只有一个方法的匿名内部类。


Lambda表达式的写法比较简洁。Lambda表达式常用来将功能当作参数传递给方法。

Lambda表达式的语法:

(方法参数列表) -> {方法体}

Lambda表达式的写法同方法一样,但没有方法名(即匿名方法)。Lambda表达式由三部分组成:

  • (方法参数列表),多个方法参数之间以逗号分隔,可以省略方法参数类型。如果只有一个方法参数,()可以省略。
  • ->,固定这样。
  • {方法体},方法体可以是单个表达式或语句块。如果方法体是单个表达式,运行时计算表达式,并返回结果值。如果是单个表达式或方法体没有返回值,{}可以省略。 例如s -> System.out.println(s)

Lambda表达式的类型由Java程序编译时根据方法参数的类型决定。例如:Stream.forEach(e -> System.out.println(e));,因为Stream.ForEach()方法的参数为Consumer类型,因此e -> System.out.println(e)类型为Consumer类型。

Lambda表达式常和Stream一起使用。

下面是Lambda表达式的例子:

import java.util.ArrayList;
import java.util.List;

public class Lambda {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("apple");
        list.add("orange");

        list.stream().forEach(e -> System.out.println(e));    // apple orange

        list.stream().filter(s -> s.startsWith("a")).forEach(System.out::println);    // apple
    }
}

方法引用(Method Reference)

Lambda表达式一般用于创建匿名类的匿名方法。Lambda表达式也可以调用已存在的方法,这时可以使用方法引用替代Lambda表达式。

方法引用有4种:

  • 引用一个静态方法。
  • 引用一个特定对象的实例方法。
  • 引用一个特定类的任意对象的实例方法。
  • 引用一个构造方法。

引用静态方法

下面是引用静态方法的例子:

import java.util.ArrayList;
import java.util.List;

public class MethodRef {
    public static void main(String[] args) {
        List<Pet> pets = new ArrayList<>();
        pets.add(new Pet("dog"));
        pets.add(new Pet("cat"));

        pets.stream().forEach(Pet::favorite);    // bone fish

        pets.stream().forEach(p -> Pet.favorite(p));    // bone fish
    }
}

class Pet {
    private String name;
    public Pet(String name) {
        this.name = name;
    }

    public static void favorite(Pet p) {
        switch(p.name) {
        case "dog":
            System.out.println("bone");
            break;
        case "cat":
            System.out.println("fish");
            break;
        default:
            System.out.println("unknown");
        }
    }
}

方法引用Pet::favorite和Lambda表达式p -> Pet.favorite(p)在语义上是一样的。方法参数都是Pet对象,方法体都是调用Pet.favorite方法。


引用特定对象的实例方法

下面是引用特定对象的实例方法的例子:

import java.util.ArrayList;
import java.util.List;

public class MethodRef2 {
    public static void main(String[] args) {
        List<Pet> pets = new ArrayList<>();
        Pet dog = new Pet("dog", "bones");
        pets.add(dog);
        pets.add(new Pet("cat", "fish"));

        pets.stream().forEach(dog::favorite);    // bones fish
        pets.stream().forEach(p -> dog.favorite(p));    // bones fish
    }
}

class Pet {
    private String name;
    private String food;

    public Pet(String name, String food) {
        this.name = name;
        this.food = food;
    }

    public void favorite(Pet p) {
        System.out.println(p.food);
    }
}

方法引用dog::favorite和Lambda表达式p -> p.favorite(p)一样。方法参数为Pet对象,方法体调用dog.favorite

引用特定类的任意对象的实例方法

下面是特定类的任意对象的实例方法的例子:

import java.util.ArrayList;
import java.util.List;

public class MethodRef3 {
    public static void main(String[] args) {
        List<Pet> pets = new ArrayList<>();
        pets.add(new Pet("dog"));
        pets.add(new Pet("cat"));

        pets.sort(Pet::compare);
        pets.stream().forEach(p -> System.out.println(p.name));    // cat dog

        pets.sort((a, b) -> a.compare(b));
        pets.stream().forEach(p -> System.out.println(p.name));    // cat dog
    }
}

class Pet {
    String name;

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

    public int compare(Pet other) {
        return this.name.compareTo(other.name);
    }
}

方法引用Pet::compare和Lambda表达式(a, b) -> a.compare(b)一样。方法参数列表(Pet a, Pet b),方法引用将调用a.compare(b)

引用构造方法

下面是引用构造方法的例子:

import java.util.function.Supplier;

public class MethodRef4 {
    public static void main(String[] args) {
        Supplier<Pet> s = Pet::new;
        Pet p = s.get();
        p.setName("dog");
        System.out.println(p.getName());    // dog

        Supplier<Pet> s2 = () -> { return new Pet(); };
        Pet p2 = s2.get();
        p2.setName("cat");
        System.out.println(p2.getName());    // cat
    }
}

class Pet {
    private String name;

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

    public String getName() {
        return this.name;
    }
}

方法引用Pet::new和Lambda表达式() -> { return new Pet(); }一样。方法参数列表(),方法引用将调用Pet的默认构造方法。