JAVA8实战-(2)行为参数化传递代码

1. 应对不断变化的需求

该篇将讲述如何应对不断变化的需求,逐渐优化代码,以展示代码更灵活的最佳做法。

1.1 初试牛刀:筛选红苹果

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

实现一个filter方法对List做遍历,筛选出所有的红苹果,那现在农民又有了新的想法,他想筛选出绿苹果,那是不是要再写一个filterGreenApple(List<Apple> inventory)来实现呢?那如果还想筛选其他颜色呢,显然我们不能每次都定义一个新的方法,这个时候我们可以把颜色color作为参数传递进去,这样就不用写重复的代码。

1.2 将颜色作为参数传递

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

这样做你就能筛选出你想要的的任意颜色,但这是,农民又想筛选出不同重量的苹果,你肯定会想将重量作为参数传递给方法filterWeightApples(List<Apple> inventory, String color)。但是如果有多个条件,就会考虑将尽可能多的条件包含在一个过滤发放中。

1.3 对你想到的每一个属性做筛选

public static List<Apple> filterColorApples(List<Apple> inventory, String color, int weight, boolean flag) {
    List<Apple> result = new ArrayList<>();
    for(Apple apple: inventory){
        if(flag && apple.getColor().equals(color) || !flag && apple.getWeight() > weight){
            result.add(apple);
        }
    }
    return result;
}

显然这样的代码是糟糕的,因为用户根本不知道true和false代表什么意思,并且想要将所有属性都包含进去显然是不现实的,万一又对形状,大小有要求呢?

从下面开始我们就会介绍行为参数化怎么更简便的实现筛选。

1.4 行为参数化 - 根据抽象条件筛选

public interface ApplePredicate{  //定义接口
    public boolean test(Apple apple);
}
public class AppleRedPredicate implements ApplePredicate{
    @override
    public boolean test(Apple apple){
        return "red".equals(apple.getColor());
    }
}
public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p){
    List<Apple> result = new ArrayList<>();
    for(Apple apple: inventory){
        if(p.test()){
            result.add(apple);
        }
    }
    return result;
}
ApplePredicate p = new AppleRedPredicate();
filterApples(inventory, p)  //筛选出红苹果

这样显然比之前要简单许多,公用同一个filter方法,将筛选的数据集与筛选的逻辑分开来,但是每增加一次筛选就要实现一次ApplePredicate接口,显然有些麻烦,这个时候就想起了匿名类。

1.5 使用匿名类

public interface ApplePredicate{
    public boolean test(Apple apple);
}
public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p){
    List<Apple> result = new ArrayList<>();
    for(Apple apple: inventory){
        if(p.test(apple)){
            result.add(apple);
        }
    }
    return result;
}
filterApples(inventory, new ApplePredicate(){
    @override
    public boolean filterRedApple(Apple, apple){
        return "red".equals(apple.getColor());
    }
})

显然使用内部类,不用再显示定义实现接口的类,但是仍有很多模板代码,其实我们关心的只有return的那一行。如果只需要传递不同的部分就好了。

1.6 使用Lambda表达式

public interface ApplePredicate{
    public boolean test(Apple apple);
}
public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p){
    List<Apple> result = new ArrayList<>();
    for(Apple apple: inventory){
        if(p.test(apple)){
            result.add(apple);
        }
    }
    return result;
}
filterApples(inventory, (Apple apple) -> "red".equals(apple.getColor()));

除了Lambda表达式之外,我们还可以使用方法引用来传递代码。但是我们之前提到过对于复杂的代码块与匿名函数更方便,简单的代码块使用Lambda更方便。下面展示匿名函数:

public static boolean isRedApple(Apple apple){
    return "red".equals(apple.getColor());
}
public interface ApplePredicate{
    public boolean test(Apple apple);
}
public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p){
    List<Apple> result = new ArrayList<>();
    for(Apple apple: inventory){
        if(p.test(apple)){
            result.add(apple);
        }
    }
    return result;
}
filterApples(inventory, Apple::isRedApple);

现在我们已经得到了我们想要的,只传递必要的代码块,下面就是进一步的抽象化,filter目前只适用于Apple,我们还可以针对其他类型。

1.7 抽象化List列表

public interface Predicate<T>{
    public boolean test(T t);
}
public static List<T> filter(List<T> inventory, Predicate p){
    List<T> result = new ArrayList<>();
    for(T t: inventory){
        if(p.test(t)){
            result.add(t);
        }
    }
    return result;
}
filter(inventory, (Apple apple) -> "red".equals(apple.getColor()));
filter(inventory, (Integer i) -> i == 1);

2.其他真实应用

2.1 用Comparator进行排序

我们都知道在JAVA8中List自带了sort方法,你也可以自定义sort。sort的行为可以用java.util.Comparator对象来参数化,它的接口如下:

//java.util.Comparator
public interface Comparator<T>{
    public int compare(T o1, T o2);
}

你可以随时创建Comparator的实现,进行不同的sort行为。

inventory.sort(new Comparator<Apple>(){
    @override
    public int compare(Apple p1, Apple p2){
        return p1.getWeight().compareTo(p2.getWeight());
    }
});

使用Lambda表达式的话,就是

inventory.sort((Apple p1, Apple p2) -> p1.getWeight().compareTo(p2.getWeight()));

2.2 用Runnable执行代码块

在JAVA中我们可以用线城执行代码块。

//java.lang.Runnable
public interface Runnable{
    public void run();
}
Thread t = new Thread(new Runnable(){
    @override
    public void run(){
        System.out.println("Hello world!");
    }
});

用Lambda表达式的话

Thread t = new Thread(() -> System.out.println("Hello world!"));

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值