java8学习:通过行为参数化传递代码

内容来自《 java8实战 》,本篇文章内容均为非盈利,旨为方便自己查询、总结备份、开源分享。如有侵权请告知,马上删除。
书籍购买地址:java8实战

  • 如下一段代码请看

    @Test
    public void test() throws Exception {
        List<Apple> list = new ArrayList<>();
        for (Apple apple : list) {
            if (apple.getWeight() > 1000){
                System.out.println("...");
            }
        }
    }
    • 这段代码再简单不过了,并且完成了该完成的判断条件,但是如果现在并不是想判断重量weight了,而是需要判断color是不是红色的了,那么就只能代码复制然后改条件了,如下
    @Test
    public void test() throws Exception {
        List<Apple> list = new ArrayList<>();
        for (Apple apple : list) {
            if ("red".equals(apple.getColor())){
                System.out.println("...");
            }
        }
    }
    • 此时发现,除了更改了if条件,其他地方是没有动的,但是如果我又需要更改别的条件呢,无奈只好再次变换if条件,针对这一的情况,java8的行为参数化就可以处理频繁的变更
  • 行为参数化

    • 如上的筛选苹果颜色的代码,这时候我突然想要绿色的或者彩虹色可咋办难道还要拷贝?
            public void getAppleByColor(List<Apple> apples,String color){
                for (Apple apple : apples) {
                    if (color.equals(apple.getColor())){
                        System.out.println("...");
                    }
                }
            }
    //getAppleByColor(lists,"red");     //调用
    • 上面这段代码就解决了一直变更的颜色的问题,任他来的是透明颜色都没问题,并且调用方法时,也可以清晰的看出来我们需要的是什么苹果
    • 苹果大卖钱就多,那么如果按照重量筛选呢?代码已经给出来了,那么就是开篇的第二段代码,仔细想一下虽然解决了我们的问题,但是是不是代码重复的太多了,并且这样的编程风格十分不好,违反了DRY(don't repeat yourself),这时候我们就可能想到了进一步的解决办法来应对重量和颜色的不同选择,那就是立flag,如下
public void getAppleByColor(List<Apple> apples,String color,Integer weight,boolean isColor){
    for (Apple apple : apples) {
        if ((isColor && color.equals(apple.getColor())) ||
            !isColor && weight > apple.getWeight()){
            System.out.println("...");
        }
    }
}
getAppleByColor(lists,"red",0,true);       //调用
getAppleByColor(lists,"",123,false);       //调用
  • 如上,调用简直不能再糟了,如果不让调用者看到方法的方法签名和解释,那么他肯定不会知道true代表啥false代表啥,所以这种方法解决此问题是十分不可取的,那么我们肯定就需要更好的解决方案
  • 思路:建立一个接口,那么就有类去实现接口,那么每个实现类不就代表一种行为吗?比如这样改
interface FilterApple{
    boolean filter(Apple apple);
}
class FilterRedApple implements FilterApple{
    @Override
    public boolean filter(Apple apple) {
        return "red".equals(apple.getColor());
    }
}
class FilterAppleByWeight implements FilterApple{
    @Override
    public boolean filter(Apple apple) {
        return apple.getWeight() > 1000;
    }
}
public class Java8 {
    @Test
    public void test() throws Exception {
        List<Apple> apples = Arrays.asList();
        getAppleByColor(apples,new FilterAppleByWeight());
        getAppleByColor(apples,new FilterRedApple());
    }

    public void getAppleByColor(List<Apple> apples,FilterApple filter){
        for (Apple apple : apples) {
            if (filter.filter(apple)) {
                System.out.println("....");
            }
        }
    }
}
  • 如上代码有点长但是十分的简单,在上面我们可以看到,我们利用了多态的特性来用不同的实现类来实现不同需求的过滤,如果以后把苹果分男女,那么我们只需要增加一个FilterAppleByJJ就可以了
  • 引出:如上就是一种行为参数化,让方法接受多种行为作为参数,并在内部使用,来完成不同的行为
  • 在上面的例子中,唯一重要的也就是filter的实现,但是我们写的方法只能接受一个FilterApple对象,所以必须把不同的实现代码包裹在此对象中。这就好像你借别人钱还要拿纸包起来,不仅老套而且人家关心的只是钱的问题,纸随便就给扔掉了,在这我们不同实现类中的实现的不同逻辑就是借的钱,就比如下面这样

java8学习:通过行为参数化传递代码

  • 但是对于上面的写法有点太啰里啰嗦的了,实现一个过滤就要实现一个接口?这时候就应该能想到匿名内部类了把~
@Test
public void test() throws Exception {
    List<Apple> apples = Arrays.asList();
    getAppleByColor(apples, new FilterApple() {
        @Override
        public boolean filter(Apple apple) {
            return apple.getWeight() > 1000;
        }
    });
}
public void getAppleByColor(List<Apple> apples,FilterApple filter){
    for (Apple apple : apples) {
        if (filter.filter(apple)) {
            System.out.println("....");
        }
    }
}
  • 但是匿名内部类还是存在很多的问题,1.就是样本代码太多,2.那么就是不清楚,比如下面这个,你来看看输出什么,答案在最下面
public class Java8 {
    private final int value = 4;
    public void doIt(){
        int value = 6;
        Runnable runnable = new Runnable() {
            public final int value = 5;
            @Override
            public void run() {
                int value = 10;
                System.out.println(this.value);
            }
        };
        runnable.run();
    }

    public static void main(String[] args) {
        new Java8().doIt();
    }
}
  • 匿名内部类的弊端:在只需要传递一段简单的代码时,还是需要创建一个对象,明确的实现一个方法来定义一个新的行为
  • 上面的问题来充实Lambda表达式解决

    @Test
    public void test() throws Exception {
        List<Apple> apples = Arrays.asList();
        getAppleByColor(apples,(apple) -> apple.getWeight() > 1000);
    }
    
    public void getAppleByColor(List<Apple> apples,FilterApple filter){
        for (Apple apple : apples) {
            if (filter.filter(apple)) {
                System.out.println("....");
            }
        }
    }
    • 爽的一批,对于lambda以后会继续说的
    • 但是还有个问题,这个只能是过滤Apple把,如果我还有西瓜之类的呢,那么代码就可以引入泛型T
interface Filter<T>{
    boolean filter(T t);
}
public class Java8 {
        @Test
        public void test() throws Exception {
            List<Apple> apples = Arrays.asList();
            getAppleByColor(apples,apple -> apple.getWeight() > 1000);
        }

        public <T> void getAppleByColor(List<T> ts,Filter<T> filter){
            for (T t : ts) {
                if (filter.filter(t)){
                    System.out.println("...");
                }
            }
        }
}
  • 这时候就想过滤什么就过滤什么了
Comparator排序
@Test
public void test() throws Exception {
    List<Apple> apples = Arrays.asList();
    apples.sort(Comparator.comparing(Apple::getWeight));
}
or
@Test
public void test() throws Exception {
    List<Apple> apples = Arrays.asList();
    apples.sort((a1,a2) -> a1.getWeight().compareTo(a2.getWeight()));
}
  • Runnable
@Test
public void test() throws Exception {
    Runnable runnable = ()->{
        System.out.println("run");
    };
    runnable.run();
}
  • 好了上面是两个例子仅供参考
  • 答案:5
上一篇:《网络安全法》强化关键信息基础设施保护


下一篇:git生成密钥