Java8_01.Lambda表达式(一)

Lambda表达式

商家采购苹果,对每一个苹果都进行了编号,并记录其颜色和重量,用下面的结构表示

Apple {id, color, weight}

需求1:从所有的苹果中筛选出绿颜色的苹果

so easy,代码张手就来。

public static List<Apple> filterGreenApples(List<Apple> inventory) {
    List<Apple> result = new ArrayList<>();
    for (Apple apple: inventory) {
        if ( "green".equals(apple.getColor())) {
            result.add(apple);
        }
    }
    return result;
}

需求2:从所有苹果中筛选出红颜色的苹果
再写一个filterRedApples方法呗,代码与filterGreenApples几乎一样,只是green改成red,这种做法明显太不优雅,要是再加一种颜色,难道要再加一个几乎一样的方法吗?

于是,我们对上面的方法改装一下,将颜色提取成参数,这样想找什么颜色的苹果都可以,由调用者自己决定,问题就轻松解决。

public static List<Apple> filterApples(List<Apple> inventory, String color) {
    List<Apple> result = new ArrayList<>();
    for (Apple apple: inventory) {
        if ( color.equals(apple.getColor())) {
            result.add(apple);
        }
    }
    return result;
}

需求3:从所有苹果中筛选重量小于100g的绿色的苹果
**,刚把颜色的问题解决好,居然使用其它属性,更关键的问题是,未来是不是还会有更多的属性加入,思之极恐。

看来,我们必须把这个方法写得更加通用一点。

分析一下代码:

这个方法的作用是筛选,每次的循环操作都是不变的,变化的部分就是判断的条件。

那我们把不变的部分固定下来,把变化的部分抽离出来,把这个条件判断用一个固定的方法来代替。

Let’s go!

使用策略模式进行改造

创建一个筛选器接口,入参为Apple对象(这样就包含了Apple的所有属性),出参为boolean。

interface AppleFilter {
    boolean test(Apple apple);
}

public static List<Apple> filterApples(List<Apple> inventory, AppleFilter filter) {
    List<Apple> result = new ArrayList<>();
    for (Apple apple: inventory) {
        if ( filter.test(apple) ) {
            result.add(apple);
        }
    }
    return result;
}

需要绿苹果,就创建一个绿苹果筛选器

static class GreenAppleFilter implements AppleFilter {
    @Override
    public boolean test(Apple apple) {
        return "green".equals(apple.getColor());
    }
}

需要红苹果,就创建一个红苹果筛选器

static class GreenAppleFilter implements AppleFilter {
    @Override
    public boolean test(Apple apple) {
        return "green".equals(apple.getColor());
    }
}

想要什么样的条件,就自行创建一个相应的筛选器即可,需求完美解决。这其实就是一个策略模式的诞生。

但是这样的代码有没有什么缺点?

没错,就是会多出来一堆的筛选器类,让整个项目变得臃肿。

使用匿名内部类进行改造

JDK不是有匿名内部类嘛,这样就可以避免上面的问题了。改造不能停。

List<Apple> greenApples = filterApples(list, new AppleFilter() {
    @Override
    public boolean test(Apple apple) {
        return "green".equals(apple);
    }
});
List<Apple> redApples = filterApples(list, new AppleFilter() {
    @Override
    public boolean test(Apple apple) {
        return "red".equals(apple);
    }
});

一切似乎烟消云散,至于内部类所存在的缺点,似乎也不是我们力所能及能够改变得了的,故事该大结局了。

的确,在JDK1.8之前,这就是终极状态了,但现在一切又有了新的转机。

将简化进行到底

匿名内部类中的代码还有什么是可以简化的?

这里的匿名内部类所实现的接口(AppleFilter),只有一个方法(test),所以在这里创建这个内部类的意义就是为了调用它的实现方法。

我们关注的不是 AppleFilter 接口的定义,也不是 test 方法的定义,因为这些都已经定义好了,我们关注的只是 test 方法的实现。

使用 Lambda 表达式

List<Apple> greenApples = filterApples(list, apple -> "green".equals(apple));
List<Apple> redApples = filterApples(list, apple -> "red".equals(apple));

第一次看这样的代码也许并不能马上理解,这并不要紧,后面的章节会详细解释,但请记住这个写法。

通用实现

现在,我们实现了苹果的筛选,那么香蕉,菠萝呢?是不是可以实现一个更通用的方法?答案当然是肯定的。

使用泛型进行方法改造

interface Filter<T> {
    boolean test(T apple);
}

public static <T> List<T> filter(List<T> inventory, Filter<T> filter) {
    List<T> result = new ArrayList<>();
    for (T item: inventory) {
        if ( filter.test(item) ) {
            result.add(item);
        }
    }
    return result;
}

猜你喜欢

转载自blog.csdn.net/gongm24/article/details/79444302