公子奇带你一步一步了解Java8中行为参数化

说明:因为本公子一直从事监狱软件开发,所以本系列博客的引入也以此为背景。问题做了简化,只是为了来讲解技术点。

一、问题提出

今日在好好的撸着代码,超哥(民警)找来了,让把监狱30岁以上的民警找给他。

二、功能实现

这个简单。什么也不用说,代码撸起来。首先定义实体类

package com.hz.pojo;

/**
 * 民警实体类
 */
public class Police {
    /**
     * 民警警号
     */
    private String policeNo;
    /**
     * 民警姓名
     */
    private String policeName;
    /**
     * 民警年龄
     */
    private Integer policeAge;
    /**
     * 民警籍贯
     */
    private String policeNativePlace;

    public Police(String policeNo, String policeName, Integer policeAge, String policeNativePlace) {
        this.policeNo = policeNo;
        this.policeName = policeName;
        this.policeAge = policeAge;
        this.policeNativePlace = policeNativePlace;
    }

    public String getPoliceNo() {
        return policeNo;
    }

    public void setPoliceNo(String policeNo) {
        this.policeNo = policeNo;
    }

    public String getPoliceName() {
        return policeName;
    }

    public void setPoliceName(String policeName) {
        this.policeName = policeName;
    }

    public Integer getPoliceAge() {
        return policeAge;
    }

    public void setPoliceAge(Integer policeAge) {
        this.policeAge = policeAge;
    }

    public String getPoliceNativePlace() {
        return policeNativePlace;
    }

    public void setPoliceNativePlace(String policeNativePlace) {
        this.policeNativePlace = policeNativePlace;
    }

    @Override
    public String toString() {
        return "Police{" +
                "policeNo=‘" + policeNo + ‘\‘‘ +
                ", policeName=‘" + policeName + ‘\‘‘ +
                ", policeAge=" + policeAge +
                ", policeNativePlace=‘" + policeNativePlace + ‘\‘‘ +
                ‘}‘;
    }
}

然后实现

 1 package com.hz;
 2
 3 import com.hz.pojo.Police;
 4
 5 import java.util.ArrayList;
 6 import java.util.Arrays;
 7 import java.util.List;
 8
 9 public class PoliceMain {
10     public static void main(String[] args) {
11         List<Police> polices = Arrays.asList(new Police("P001", "余警官", 27, "浙江"),
12                 new Police("P001", "李警官", 32, "安徽"),
13                 new Police("P001", "程警官", 25, "安徽"),
14                 new Police("P001", "杨警官", 35, "浙江"));
15
16         List<Police> result = new ArrayList<>();
17         for (Police police : polices) {
18             if (police.getPoliceAge() > 30) {
19                 result.add(police);
20             }
21         }
22
23         System.out.println("查询结果:" + result);
24     }
25 }

因为30是个随时会变化的值,我在这里还很明智的将其作为一个参数并提取为一个方法

package com.hz;

import com.hz.pojo.Police;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class PoliceMain {
    public static void main(String[] args) {
        List<Police> polices = Arrays.asList(new Police("P001", "余警官", 27, "浙江"),
                new Police("P001", "李警官", 32, "安徽"),
                new Police("P001", "程警官", 25, "安徽"),
                new Police("P001", "杨警官", 35, "浙江"));

        List<Police> result = filterPoliceAge(polices, 30);

        System.out.println("查询结果:" + result);
    }

    /**
     * 民警过滤器
     * @auth 公子奇
     * @date 2019-01-02
     * @param policeContainer 全部民警
     * @param age 年龄
     * @return 符合结果的民警列表
     */
    static List<Police> filterPoliceAge(List<Police> policeContainer, Integer age) {
        List<Police> result = new ArrayList<>();
        for (Police police : policeContainer) {
            if (police.getPoliceAge() > 30) {
                result.add(police);
            }
        }
        return result;
    }
}

写完后我还沾沾自喜,认为很好的代码,随你年龄怎么变,我都可以。看来我太天真了,很快问题就来了。

三、问题的进一步引入

没过多久,超哥又来了,问能不能把所有籍贯为浙江的民警给找出来。我一看,很容易啊,等我几分钟,马上就好,代码继续撸起来。

 1 package com.hz;
 2
 3 import com.hz.pojo.Police;
 4
 5 import java.util.ArrayList;
 6 import java.util.Arrays;
 7 import java.util.List;
 8
 9 public class PoliceMain {
10     public static void main(String[] args) {
11         List<Police> polices = Arrays.asList(new Police("P001", "余警官", 27, "浙江"),
12                 new Police("P001", "李警官", 32, "安徽"),
13                 new Police("P001", "程警官", 25, "安徽"),
14                 new Police("P001", "杨警官", 35, "浙江"));
15
16         List<Police> result = filterPoliceAge(polices, 30);
17         System.out.println("查询结果1: " + result);
18
19         System.out.println("-------------");
20
21         result = filterPoliceNativePlace(polices, "浙江");
22         System.out.println("查询结果2: " + result);
23     }
24
25     /**
26      * 民警年龄过滤器
27      * @auth 公子奇
28      * @date 2019-01-02
29      * @param policeContainer 全部民警
30      * @param age 年龄
31      * @return 符合结果的民警列表
32      */
33     static List<Police> filterPoliceAge(List<Police> policeContainer, Integer age) {
34         List<Police> result = new ArrayList<>();
35         for (Police police : policeContainer) {
36             if (police.getPoliceAge() > 30) {
37                 result.add(police);
38             }
39         }
40         return result;
41     }
42
43     /**
44      * 民警籍贯过滤器
45      * @auth 公子奇
46      * @date 2019-01-02
47      * @param policeContainer 全部民警
48      * @param nativePlace 籍贯
49      * @return 符合结果的民警列表
50      */
51     static List<Police> filterPoliceNativePlace(List<Police> policeContainer, String nativePlace) {
52         List<Police> result = new ArrayList<>();
53         for (Police police : policeContainer) {
54             if (nativePlace.equals(police.getPoliceNativePlace())) {
55                 result.add(police);
56             }
57         }
58         return result;
59     }
60 }

写完之后,我发现有点不太对劲啊,filterPoliceAge和filterPoliceNativePlace这两个方法存在大量重复的代码,这个很明显违背了DRY(Don‘t Repeat Yourself,不要重复自己)的软件工程原则。随着后面民警属性的越来越多,这不是要命嘛!

四、策略设计模式的引入

分析上述任务,代码重复/业务逻辑也差不多,既然如此,策略模式就是很好的解决方案啊!说改就改,代码继续。关于策略模式查看我的GitHub策略模式介绍。

首先定义一个过滤处理接口

 1 package com.hz.filter;
 2
 3 import com.hz.pojo.Police;
 4
 5 /**
 6  * 民警过滤条件
 7  */
 8 public interface PolicePredicate {
 9     boolean test(Police police);
10 }

然后针对这个接口,分别实现年龄和籍贯实现类

package com.hz.filter;

import com.hz.pojo.Police;

/**
 * 民警年龄筛选
 */
public class PoliceAgePredicate implements PolicePredicate {
    @Override
    public boolean test(Police police) {
        return police.getPoliceAge() > 30;
    }
}

package com.hz.filter;

import com.hz.pojo.Police;

/**
 * 民警籍贯筛选
 */
public class PoliceNativePlacePredicate implements PolicePredicate {
    @Override
    public boolean test(Police police) {
        return "浙江".equals(police.getPoliceNativePlace());
    }
}

调用

 1 package com.hz;
 2
 3 import com.hz.filter.PoliceAgePredicate;
 4 import com.hz.filter.PoliceNativePlacePredicate;
 5 import com.hz.filter.PolicePredicate;
 6 import com.hz.pojo.Police;
 7
 8 import java.util.ArrayList;
 9 import java.util.Arrays;
10 import java.util.List;
11
12 public class PoliceMain2 {
13     public static void main(String[] args) {
14         List<Police> polices = Arrays.asList(new Police("P001", "余警官", 27, "浙江"),
15                 new Police("P001", "李警官", 32, "安徽"),
16                 new Police("P001", "程警官", 25, "安徽"),
17                 new Police("P001", "杨警官", 35, "浙江"));
18
19         List<Police> result = filterPolice(polices, new PoliceAgePredicate());
20         System.out.println("结果1: " + result);
21
22         System.out.println("--------------");
23
24         result = filterPolice(polices, new PoliceNativePlacePredicate());
25         System.out.println("结果2: " + result);
26     }
27
28     /**
29      * 民警筛选器
30      * @param policeList
31      * @param predicate
32      * @return
33      */
34     static List<Police> filterPolice(List<Police> policeList, PolicePredicate predicate) {
35         List<Police> result = new ArrayList<>();
36
37         for (Police police : policeList) {
38             if (predicate.test(police)) {
39                 result.add(police);
40             }
41         }
42
43         return result;
44     }
45 }

到了这里我感觉已经很完美了,引入了设计模式,灵活性大大的增加了,以后不管他怎么变化,我这边只要添加一个实现类就可以了。到此大功告成,走,喝杯咖啡去。

五、设计模式后的进一步思考,匿名类的对比

咖啡喝完以后,把刚才的代码拿出来又欣赏了一篇,感觉真好。不对!后面筛选条件越来越多,我的实现类也会变的非常多,而且这些实现类都执行一步操作,这个实现类有必要去创建吗?如果不去创建这些实现类,我该怎么实现功能呢?我突然想到了匿名类。那就实现看看呗!

 1 package com.hz;
 2
 3 import com.hz.filter.PoliceAgePredicate;
 4 import com.hz.filter.PoliceNativePlacePredicate;
 5 import com.hz.filter.PolicePredicate;
 6 import com.hz.pojo.Police;
 7
 8 import java.util.ArrayList;
 9 import java.util.Arrays;
10 import java.util.List;
11
12 public class PoliceMain2 {
13     public static void main(String[] args) {
14         List<Police> polices = Arrays.asList(new Police("P001", "余警官", 27, "浙江"),
15                 new Police("P001", "李警官", 32, "安徽"),
16                 new Police("P001", "程警官", 25, "安徽"),
17                 new Police("P001", "杨警官", 35, "浙江"));
18
19         List<Police> result = filterPolice(polices, new PoliceAgePredicate());
20         System.out.println("结果1: " + result);
21
22         System.out.println("--------------");
23
24         result = filterPolice(polices, new PoliceNativePlacePredicate());
25         System.out.println("结果2: " + result);
26
27         System.out.println("----------------");
28
29         result = filterPolice(polices, new PolicePredicate() {
30             @Override
31             public boolean test(Police police) {
32                 return police.getPoliceAge() > 30;
33             }
34         });
35         System.out.println("结果3: " + result);
36     }
37
38     /**
39      * 民警筛选器
40      * @param policeList
41      * @param predicate
42      * @return
43      */
44     static List<Police> filterPolice(List<Police> policeList, PolicePredicate predicate) {
45         List<Police> result = new ArrayList<>();
46
47         for (Police police : policeList) {
48             if (predicate.test(police)) {
49                 result.add(police);
50             }
51         }
52
53         return result;
54     }
55 }

这样即实现了功能,也不需要创建大量的实现类,类增加的同时,也会增加我们的维护成本。后来仔细想了想,也不太好,类的维护是降低了,可是大量的匿名实现从代码可读性上也是存在很大缺陷的,还有更好的方案吗?

六、Lambda表达式的引入

以上匿名类,完全是可以通过Java8来进行简化的。话不多说,代码奉上。

package com.hz;

import com.hz.filter.PolicePredicate;
import com.hz.pojo.Police;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class PoliceMain3 {
    public static void main(String[] args) {
        List<Police> polices = Arrays.asList(new Police("P001", "余警官", 27, "浙江"),
                new Police("P002", "李警官", 32, "安徽"),
                new Police("P003", "程警官", 25, "安徽"),
                new Police("P004", "杨警官", 35, "浙江"));

        List<Police> result = filterPolice(polices, (Police police) -> police.getPoliceAge() > 30);
        System.out.println("结果1: " + result);

        System.out.println("---------------");

        result = filterPolice(polices, (Police police) -> "浙江".equals(police.getPoliceNativePlace()));
        System.out.println("结果2: " + result);
    }

    /**
     * 民警筛选器
     * @param policeList
     * @param predicate
     * @return
     */
    static List<Police> filterPolice(List<Police> policeList, PolicePredicate predicate) {
        List<Police> result = new ArrayList<>();

        for (Police police : policeList) {
            if (predicate.test(police)) {
                result.add(police);
            }
        }

        return result;
    }
}

这么一改,代码简洁了很多,也更加容易理解是什么意思了。

七、继续对类型进行抽象化

刚对民警筛选修改完,感觉不需要再改了,此时超哥带着“美丽的”笑容向我走来了。需要对监狱罪犯也做同样的筛选。我的天啊,难道要我把上面的代码再针对罪犯复制一遍吗?作为一名爱学习、求进步的新时代程序员,这怎么能难到我。

既然如此,看来要从接口上进行修改了,将接口修改为:

package com.hz.filter;

/**
 * 筛选器
 * @param <T>
 */
public interface Predicate<T> {
    boolean test(T t);
}

这样一改,你需要筛选类型,自己去传就可以了。

 1 package com.hz;
 2
 3 import com.hz.filter.Predicate;
 4 import com.hz.pojo.Police;
 5
 6 import java.util.ArrayList;
 7 import java.util.Arrays;
 8 import java.util.List;
 9
10 public class PoliceMain4 {
11     public static void main(String[] args) {
12         List<Police> polices = Arrays.asList(new Police("P001", "余警官", 27, "浙江"),
13                 new Police("P002", "李警官", 32, "安徽"),
14                 new Police("P003", "程警官", 25, "安徽"),
15                 new Police("P004", "杨警官", 35, "浙江"));
16
17         List<Police> result = filter(polices, (Police police) -> police.getPoliceAge() > 30);
18         System.out.println("结果1: " + result);
19
20         System.out.println("---------------");
21
22         result = filter(polices, (Police police) -> "浙江".equals(police.getPoliceNativePlace()));
23         System.out.println("结果2: " + result);
24     }
25
26     /**
27      * 筛选器
28      * @param container
29      * @param predicate
30      * @return
31      */
32     static <T> List<T> filter(List<T> container, Predicate<T> predicate) {
33         List<T> result = new ArrayList<>();
34
35         for (T e : container) {
36             if (predicate.test(e)) {
37                 result.add(e);
38             }
39         }
40
41         return result;
42     }
43 }

到此,即实现了行为参数化。关于Java8的一些概念和知识点我们再后续在去介绍。我们将开个系列去详细介绍Java8的使用。

原文地址:https://www.cnblogs.com/chuanqi1415583094/p/java8.html

时间: 2024-10-08 10:20:50

公子奇带你一步一步了解Java8中行为参数化的相关文章

公子奇带你一步一步了解Java8中Lambda表达式

在上一篇<公子奇带你一步一步了解Java8中行为参数化>中,我们演示到最后将匿名实现简写为 1 (Police police) -> "浙江".equals(police.getPoliceNativePlace()); 这是一个带有箭头的函数,这种写法在Java8中即为Lambda表达式.那么我们就来好好的讲讲Lambda表达式. 一 .什么是Lambda表达式 首先我们需要知道Lambda表达式时JDK8中提出的编码风格,它可以简洁地表示可作为参数传递的匿名函数的

公子奇带你进入Java8流的世界(二)

在上一篇中我们带领大家简单的了解流的概念及使用场景,知道了流的本质操作是将外部迭代转为了内部迭代,由此从程序并发性上得到了很大的优化.在本节我们就来好好的介绍流的常见用法. 一.筛选和切片 对于一串流,我们有时需要取出我们需要的流中某些元素,主要是通过谓词筛选.看代码: 首先定义一个POJO,后续操作都基于此来实例化元素. 1 package com.hz; 2 3 /** 4 * 民警实体类 5 */ 6 public class Police { 7 /** 8 * 民警警号 9 */ 10

【转】朱兆祺带你一步一步学习嵌入式(连载)

原文网址:http://bbs.elecfans.com/jishu_357014_2_1.html#comment_top  从最初涉及嵌入式Linux开始到现在,深深的知道嵌入式的每一步学习都是举步维艰.从去年11月份开始,我就着手整理各种学习资料,希望推动嵌入式学习的前进贡献自己微不足道的一份力量.从去年到现在,将C语言的学习经验整理成<攻破C语言笔试与机试陷阱及难点>(现在仍在更新),这份资料已经在电子发烧友论坛的单片机论坛连载(http://bbs.elecfans.com/jish

带你一步一步的解析ARouter 源码

ARouter 是阿里推出的一款页面路由框架.由于项目中采用了组件化架构进行开发,通过 ARouter 实现了页面的跳转,之前看它的源码时忘了写笔记,因此今天来重新对它的源码进行一次分析. (顺手留下GitHub链接,需要获取相关面试或者面试宝典核心笔记PDF等内容的可以自己去找)https://github.com/xiangjiana/Android-MS 本篇源码解析基于 ARouter 1.2.4 初始化 ARouter 在使用前需要通过调用 Arouter.init方法并传入 Appl

面试被问懵?带你一步一步深入Handler源码,不信还拿不下面试官?

Handler机制是Android中相当经典的异步消息机制,在Android发展的历史长河中扮演着很重要的角色,无论是我们直接面对的应用层还是FrameWork层,使用的场景还是相当的多. 很多朋友面试时问到了这里,一时被问懵.从哪里跌倒就从哪里爬起来,带大家一步一步深入Handler源码,就不信还拿不下面试官! BATJ.字节跳动面试专题,算法专题,高端技术专题,混合开发专题,java面试专题,Android,Java小知识,到性能优化.线程.View.OpenCV.NDK等已经上传到了的我的

带大家一步一步封装一个聊天键盘(二)

继上次写了封装聊天键盘(一)地址(http://www.cnblogs.com/bcblogs/p/4704046.html),今天有时间就继续写吧,哈哈,有什么问题可以在评论里发给我哦(红色字体是我当时怎么想的) 上次写到表情键盘,今天我们把余下的写完 首先,我们先把扩展的View写了,扩展的View我是用的自定义的View,其实也就是几张图片而已啦,继承UIView自定义一个View 我的想法是,封装一个view,传入一个数组,就能显示一排间隔相等的图片,我定义的时每一行有4个button,

一步一步跟我学习lucene(19)---lucene增量更新和NRT(near-real-time)Query近实时查询

这两天加班,不能兼顾博客的更新,请大家见谅. 有时候我们创建完索引之后,数据源可能有更新的内容,而我们又想像数据库那样能直接体现在查询中,这里就是我们所说的增量索引.对于这样的需求我们怎么来实现呢?lucene内部是没有提供这种增量索引的实现的: 这里我们一般可能会想到,将之前的索引全部删除,然后进行索引的重建.对于这种做法,如果数据源的条数不是特别大的情况下倒还可以,如果数据源的条数特别大的话,势必会造成查询数据耗时,同时索引的构建也是比较耗时的,几相叠加,势必可能造成查询的时候数据缺失的情况

一步一步跟我学习lucene(9)---lucene搜索之拼写检查和相似度查询提示(spellcheck)

suggest应用场景 用户的输入行为是不确定的,而我们在写程序的时候总是想让用户按照指定的内容或指定格式的内容进行搜索,这里就要进行人工干预用户输入的搜索条件了:我们在用百度谷歌等搜索引擎的时候经常会看到按键放下的时候直接会提示用户是否想搜索某些相关的内容,恰好lucene在开发的时候想到了这一点,lucene提供的suggest包正是用来解决上述问题的. suggest包联想词相关介绍 suggest包提供了lucene的自动补全或者拼写检查的支持: 拼写检查相关的类在org.apache.

loadrunner安装运行一步一步来(多图)

安装loadrunner 一路遇到很多坑,很多坑,坑,为什么呢? 因为这软件是收费的,他操作文档写的很详细,就是不写基础环境的配置,下面安装过程写详细一些,减少大家没必要时间上的浪费和对此的谩骂 现在loadrunner 12的版本已经出来了,不过还没有破解,所以先安装测试11的版本,不绕圈子,先下载, 链接: http://pan.baidu.com/s/1kT8CbVh 密码: v4br 加密码是怕被删 遇到的坑 下面是通用的安装说明: 1.下载loadrunner-11.zip文件,解压缩