JAVA——官方lambda表达式经典教程

本文内容针对于oracle的JAVA教程中,lambda表达式章节

教程围绕“ 如何从 输出所有大于某年龄的职工信息,到 针对性筛选对象并提取信息的通用性函数” 而展开,阅读完整个教程不光能学习到lambda表达式的用法,还可深入体会到所谓 抽象泛化 的概念。

  1. 最直接简单的实现如下,代码思路很简单,依次遍历表中所有职工,逐个判断年龄,符合条件则输出。

    这里有一个特殊遍历方法,python里也有类似的概念。由于List是Iterable的子类,故可使用For-Each Loop

public static void printPersonsOlderThan(
	List<Person> roster, int age) {
    for (Person p : roster) {
        if (p.getAge() >= age) {
            p.printPerson();
        }
    }
}
printPersonsOlderThan(roster, 20);
  1. 那如果想筛选出小于某年龄的呢?重新写一个会显得很麻烦,能否将上一个函数改进一下,让它更general?考虑大于a等价于大于a小于max,小于a等价于大于min小于a,则可将两者抽象合并为某年龄段
public static void printPersonsWithinAgeRange(
    List<Person> roster, int low, int high) {
    for (Person p : roster) {
        if (low <= p.getAge() && p.getAge() < high) {
            p.printPerson();
        }
    }
}
printPersonsWithinAgeRange(roster, 14, 30);
  1. 更进一步,如果我们筛选(filter)的判断标准并不局限于年龄呢?比如性别?总不能又重新写一个函数吧?这里将筛选职工这一逻辑进行抽象,从主调函数中剥离,另定义一个接口CheckPerson作为主调函数的形参类型。这样在实际调用主调函数时,只要根据需求实现并实例化接口的一个Local class作为实参传入
interface CheckPerson {
    boolean test(Person p);
}
public static void printPersons(
    List<Person> roster, CheckPerson tester) {
    for (Person p : roster) {
        if (tester.test(p)) {
            p.printPerson();
        }
    }
}
class CheckPersonEligibleForSelectiveService implements CheckPerson {
    public boolean test(Person p) {
        return p.gender == Person.Sex.MALE &&
            p.getAge() >= 18 &&
            p.getAge() <= 25;
    }
}
printPersons(
    roster, new CheckPersonEligibleForSelectiveService());
  1. 既然已经引入了新的接口,那比Local class更简洁的方式自然是Anonyous class
printPersons(
        roster,
        new CheckPerson() {
            public boolean test(Person p) {
                return p.getGender() == Person.Sex.MALE
                        && p.getAge() >= 18
                        && p.getAge() <= 25;
            }
        }
);
  1. Lambda表达式的引入:CheckPerson由于只含有一个abstract method,故是functional interface(functional interface可能同时含有其他的 非abstract method),因此可以使用lambda表达式。

    lambda表达式具体语法查看此处

printPersons(
    roster,
    (Person p) -> p.getGender() == Person.Sex.MALE
        && p.getAge() >= 18
        && p.getAge() <= 25
);
  1. JDK中的java.util.function包内预先定义了很多Standard Functional Interfaces ,我们无需自己再定义CheckPerson。
interface Predicate<T> {
    boolean test(T t);
}
import java.util.function.Predicate;

public static void printPersonsWithPredicate(
    List<Person> roster, Predicate<Person> tester) {
    for (Person p : roster) {
        if (tester.test(p)) {
            p.printPerson();
        }
    }
}
  1. 至此,我们完成了“筛选”这一逻辑整个剥离过程,而在筛选出特定对象后,我们直接调用了 printPerson() 方法,获取姓名并打印。实际上,我们也可将其抽象成“析取信息”以及“行为”逻辑。
interface Consumer<T> {
	void accept(T t);
}
interface Function<T, R> {
	R apply(T t);
}
import java.util.function.Consumer;
import java.util.function.Function;

public static void processPersonsWithFunction(
        List<Person> roster,
        Predicate<Person> tester,
        Function<Person, String> mapper,
        Consumer<String> block) {
    for (Person p : roster) {
        if (tester.test(p)) {
            String data = mapper.apply(p);
            block.accept(data);
        }
    }
}
processPersonsWithFunction(
        roster,
        p -> p.getGender() == Person.Sex.MALE
                && p.getAge() >= 18
                && p.getAge() <= 25,
        p -> p.getEmailAddress(),
        email -> System.out.println(email)
);
  1. 我们可以还可以使用 Aggregate 操作来简化上述流程。
roster
    .stream()
    .filter(
        p -> p.getGender() == Person.Sex.MALE
            && p.getAge() >= 18
            && p.getAge() <= 25)
    .map(p -> p.getEmailAddress())
    .forEach(email -> System.out.println(email));
上一篇:Java自学习day10-封装类练习-用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。


下一篇:【Java基础】Java8中的方法引用“双冒号”——走进Java Lambda