您的位置:首页 > 编程语言 > Java开发

Java8——初探函数式接口

2018-02-28 14:37 295 查看
这里我们来以筛选苹果举例,如何逐步优化代码,实现函数式编程。

首先,我们的第一个方案可能是下面这样的:

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


上面代码对绿色的苹果进行过滤,如果我们想根据其他颜色进行过滤,我们可以将颜色作为参数进行传递,代码如下:

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


以上代码实现了根据苹果的颜色进行筛选,但是当需求更改需要根据苹果重量进行筛选之后怎么办呢?在以前肯定是再写一个方法,通过重量进行筛选,但是这样也就形成了代码重复,显得笨拙。

让我们来看一下更高层次的抽象。一种可能的解决方案是对你的选择标准建模:你考虑的是苹果,需要根据Apple的某些属性来返回一个boolean值。我们把它称为谓词(即返回boolean值的函数),让我们定义一个接口来对选择标准建模,代码如下:

ApplePredicate接口类:

public interface ApplePredicate {
boolean test(Apple apple);
}


实现该接口之后编写具体的过滤条件,你可以把这些标准看做filter方法的不同行为

public class AppleHeaveWeightPredicate implements ApplePredicate {
@Override
public boolean test(Apple apple) {
return apple.getWeight() > 150;
}
}

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


以上通过通过不同的策略模式来进行筛选,但是这样也存在问题,每个新的筛选条件都需要实现一次接口,显得繁琐,该怎么只利用ApplePredicate来实现不同的实现呢?你需要filterApples方法接受ApplePredicate对象,对Apple做条件测试。这就是行为参数化:让方法接受多种行为作为参数,并在内部使用,来完成不同的行为。

在这里给filterApples方法添加一个参数,让他接受ApplePredicate对象,代码如下:

public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p ){
List<Apple> result = new ArrayList<>();
for(Apple apple : inventory) {
if(p.test(apple)) //谓词对象封装了测试苹果的条件
System.out.println(apple.toString());
result.add(apple);
}
return result;
}


在这里一种方式是通过匿名类实现ApplePredicate对象,重写筛选的例子实现过滤:

List<Apple> redApples = filterApples(inventory, new ApplePredicate() { public boolean test(Apple apple){
return "red".equals(apple.getColor());
}
});


但是我们可以通过更简单的方式实现筛选,通过filterApples(inventory, (apple -> apple.getWeight() < 150))使用。

如此便实现了一个参数多种行为,我们可以通过传递不同的行为打到不同的目的。



对于上面的函数还可以更进一步抽象化,引入泛型,将list的参数抽象化

public static <T> List<T> filter(List<T> list, Predicate<T> p) {//这里使用了Java8提供的Predicate方法
List<T> result = new ArrayList<T>();
for(T e : list) {
if(p.test(e)) {
result.add(e);
}
}
return result;
}


以上便是使用函数式接口的一个简单例子。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: