JAVA Lambda表达式教程

Lambda教程

OverView

想象一下,有这样的一个需求,需要从List<Person>队列中查找出特定的Person成员


public class Person {

    public enum Sex {
        MALE, FEMALE
    }

    String name;
    LocalDate birthday;
    Sex gender;
    String emailAddress;

    public int getAge() {
        // ...
    }

    public void printPerson() {
        // ...
    }
}

创建方法用来匹配指定特点的成员

public static void printPersonsOlderThan(List<Person> roster, int age) {
    for (Person p : roster) {
        if (p.getAge() >= age) {
            p.printPerson();
        }
    }
}

创建更加通用的方法

public static void printPersonsWithinAgeRange(
    List<Person> roster, int low, int high) {
    for (Person p : roster) {
        if (low <= p.getAge() && p.getAge() < high) {
            p.printPerson();
        }
    }
}

在类中指定搜索条件

public static void printPersons(
    List<Person> roster, CheckPerson tester) {
    for (Person p : roster) {
        if (tester.test(p)) {
            p.printPerson();
        }
    }
}

CheckPerson接口定义

interface CheckPerson {
    boolean test(Person p);
}

CheckPerson实现

class CheckPersonEligibleForSelectiveService implements CheckPerson {
    public boolean test(Person p) {
        return p.gender == Person.Sex.MALE &&
            p.getAge() >= 18 &&
            p.getAge() <= 25;
    }
}

使用

public static void printPersons(
    roster, new CheckPersonEligibleForSelectiveService());

使用匿名内部类指定搜索条件

public static void printPersons(
    roster,
    new CheckPerson() {
        public boolean test(Person p) {
            return p.getGender() == Person.Sex.MALE
                && p.getAge() >= 18
                && p.getAge() <= 25;
        }
    }
);

使用匿名内部类现对上面来说减少了不少代码,因为不用每次查找的时候都要新建一个类,然而考虑这个接口只有一个方法,这样看起来有点臃肿,这种情况下就可以考虑使用Lambda表达式来替代匿名内部类

使用lambda表达式搜索条件

CheckPerson只是一个功能性接口,功能性接口通常只有一个抽象方法(功能性接口可以包含多个默认方法或者静态方法)。因为这样,所以可以在实现的时候省略方法名。
如下使用lambda表达式来代替匿名内部类:

public static void printPersons(
    roster,
    (Person p) -> p.getGender() == Person.Sex.MALE
        && p.getAge() >= 18
        && p.getAge() <= 25
);

使用lambda表达式实现标准的功能性接口

重新考虑下接口CheckPerson

interface CheckPerson {
    boolean test(Person p);
}

这个功能性接口只有一个方法,并且参数也只有一个和返回一个Boolean的结果。这样的接口好简单,JDK默认提供了几个功能性接口,可以在java.util.function下找到。
例如,可以使用Predicate<T>接口替代CheckPerson

interface Predicate<T> {
    boolean test(T t);
}

方法定义

public static void printPersonsWithPredicate(
    List<Person> roster, Predicate<Person> tester) {
    for (Person p : roster) {
        if (tester.test(p)) {
            p.printPerson();
        }
    }
}

使用Lambda表达式

printPersonsWithPredicate(
    roster,
    p -> p.getGender() == Person.Sex.MALE
        && p.getAge() >= 18
        && p.getAge() <= 25
);

在你的应用中使用Lambda

重新考虑如下方法,想想可以在哪些地方使用Lambda表达式

public static void printPersonsWithPredicate(
    List<Person> roster, Predicate<Person> tester) {
    for (Person p : roster) {
        if (tester.test(p)) {
            p.printPerson();
        }
    }
}

记住要使用Lambda表达式, 一定 要实现带一个抽象方法的功能性接口
下面的方法,使用Consumer<Person>接口的实例的accept方法替代printPerson方法来打印Person:

public static void processPersons(
    List<Person> roster,
    Predicate<Person> tester,
    Consumer<Person> block) {
        for (Person p : roster) {
            if (tester.test(p)) {
                block.accept(p);//简单地代替打印方法
            }
        }
}

以下方法使用Lambda表达式打印

processPersons(
     roster,
     p -> p.getGender() == Person.Sex.MALE
         && p.getAge() >= 18
         && p.getAge() <= 25,
     p -> p.printPerson()
);

假设你想验证Person的有效性或者获取它的联系方式?你可以需要一个这样功能性接口Function<T,R>并有一个方法R apply(T t)

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); //打印信息
        }
    }
}

如下则是使用Lambda表达式的效果

processPersonsWithFunction(
    roster,
    p -> p.getGender() == Person.Sex.MALE
        && p.getAge() >= 18
        && p.getAge() <= 25,
    p -> p.getEmailAddress(),
    email -> System.out.println(email)
);

广泛地使用泛型

processPersonsWithFunction的泛型化版本

public static <X, Y> void processElements(
    Iterable<X> source,
    Predicate<X> tester,
    Function <X, Y> mapper,
    Consumer<Y> block) {
    for (X p : source) {
        if (tester.test(p)) {
            Y data = mapper.apply(p);
            block.accept(data);
        }
    }
}

使用Lambda表达式的方式和上一节一样

Lambda语法

1.一个在括号内已逗号分隔的形式参数

例如CheckPerson接口的test方法包含一个参数,p代表Person类的一个实例。
注意:在Lambda表达式中可以省略数据类型,另外如果只有一个参数,可以省略括号
例如:

p -> p.getGender() == Person.Sex.MALE
    && p.getAge() >= 18
    && p.getAge() <= 25

2.->标志

3.Body,只有一句表达式或语句块

例如:
p.getGender() == Person.Sex.MALE
    && p.getAge() >= 18
    && p.getAge() <= 25

如果你使用一个表达式,JVM会计算表达式的值并返回。当然,你还是可以使用return,
return声明并不是一个表达式,在Lambda中,你必须使用{}来围绕声明。

p -> {
    return p.getGender() == Person.Sex.MALE
        && p.getAge() >= 18
        && p.getAge() <= 25;//可以去掉return,{}也可以去掉
}

如果返回类型是Void,可以忽略{},如:

email -> System.out.println(email)

完整实例

public class Calculator {

    interface IntegerMath {
        int operation(int a, int b);   
    }

    public int operateBinary(int a, int b, IntegerMath op) {
        return op.operation(a, b);
    }

    public static void main(String... args) {

        Calculator myApp = new Calculator();
        IntegerMath addition = (a, b) -> a + b; //一个在括号内已逗号分隔的形式参数和一个表达式
        IntegerMath subtraction = (a, b) -> a - b;
        System.out.println("40 + 2 = " +
            myApp.operateBinary(40, 2, addition));
        System.out.println("20 - 10 = " +
            myApp.operateBinary(20, 10, subtraction));    
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值