Java Lambda表达式使用说明

122 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第23天,点击查看活动详情

前言

我们在解析Java 行为参数化后,对Java行为参数化的概念有一定了解后,我们来继续分析之前的例子,通过ApplePredicate的各种各样的实现类后,我们不再惧怕用户的各种各样的筛选需求了。但是有些需求只是一时的,你要为客户多种多样的需求创建各种各样的ApplePredicate的实现,并且只是使用一次,这样你的项目会充斥着一大堆只使用一次的ApplePredicate的实现类。这时候,假如客户再想要筛选香蕉呢,橙子呢。那么如何来解决这些问题?

Lambda表达式使用说明

这时候我们需要超越眼前的问题,将List类型和ApplePredicate抽象化,我们可以定义如下的代码块:


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


public static <T> List<T> filter(List<T> list, Predicate<T> predicate) {
    List<T> resultList = new ArrayList<>();
    for (T t : list) {
        if (predicate.test(t)) {
            resultList.add(t);
        }
    }

    return resultList;
}

这种时候我们就可以使用Java 8引入的Lambda表达式的功能了,比如我先想要筛选红色的苹果或者是50克以上的橙子。具体代码如下:

// 筛选红色苹果
FilterTest.filter(apples, apple -> Apple.Color.RED.equals(apple.getColor()));

// 筛选50克以上的橙子
FilterTest.filter(oranges, orange -> orange.getWeight() > 50);

通过行为参数化的抽象以及我们的Lambda表达式的帮助下,我们可以轻松的将代码扩展到橙子,香蕉的筛选,甚至是我们的整数集合,单词集合的筛选。通过书写Lambda表达式,整行代码更加符合我们的思维逻辑,以上的第一行代码,我们阅读过去:筛选苹果集合,筛选苹果颜色是红色的苹果。清晰易懂,而且扩展性极强。

Lambda表达式的定义为可以理解为一种简洁的可传递的匿名函数:它没有名称,但是它有参数列表,函数主体,返回类型。可能还有一个可以抛出的异常列表。通过Lambda表达式,我们不需要像匿名类那样书写模板式的代码。Lambda有两种表达式风格:

  • 表达式-风格Lambda (parameters)-> expression
  • 块-风格Lambda parameters)-> { statements;} 从这两种风格中,我们可以看到Lambda表达式由三个部分组成。参数列表,箭头,函数主体,箭头负责将参数列表和函数主体分隔开。

其实在我们之前定义的ApplePrecate接口不是必需的,因为在java.util.function中,Java的开发者们已经帮我们定义了适用大多数情况的函数式接口了。具体的参见如下表格:

使用案例Lambda的例子对应的函数式接口
布尔表达式(List list) -> list.isEmpty()Predicate<List<String>>
创建对象() -> new Apple(10)Supplier
消费一个对象(Apple a) -> System.out.println(a.getWeight())Consumer
从一个对象中选择/提取(String s) -> s.length()Function<String, Integer> 或者 ToIntFunction
合并两个值(Int a, int b) -> a * bIntBinaryOperator
比较两个对象(Apple a1, Apple a2) ->a1.getWeight().compareTo(a2.getWeight())Comparator 或者 BiFunction<Apple, Apple, Integer> ToIntBiFunction<Apple, Apple>

表格上已经举例子说明了每个函数式接口适应的一个场景。以及它的一个示例。

Predicate

java.util.function.Predicate接口定义了一个名为test的抽象方法,接受泛型的T对象,并返回boolean。与我们之前使用的ApplePredicate差不多的形式。

Consumer

java.util.function.Consumer接口定义了一个名叫accept的抽象方法,它接受泛型T的对象,没有返回(void)。我们如果需要对T类型的对象执行某些操作的时候,可以使用这个接口。比如,使用它来创建一个Foreach方法,接收一个Integers的列表。并对每个证书进行加2操作。或者打印整个整数集合。

Function

java.util.function.Function<T, R>接口定义了一个叫作apply的抽象方法,它接受泛型T的对象,并返回一个泛型R的对象。使用这个接口我们可以提取对象的某些有用的参数。比如苹果的重量,单词字符串的长度。

总结

java.util.function包中还有许多的函数式接口,但是大多数的接口都是表格中接口的变种,目的是为了节省资源,提高效率而产生的。那么,今天我们的Lambda表达式的学习就此完成了。