公子奇带你一步一步了解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 + '\'' +
'}';
}
}
然后实现
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 = new ArrayList<>();
for (Police police : polices) {
if (police.getPoliceAge() > 30) {
result.add(police);
}
} System.out.println("查询结果:" + result);
}
}
因为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;
}
}
写完后我还沾沾自喜,认为很好的代码,随你年龄怎么变,我都可以。看来我太天真了,很快问题就来了。
三、问题的进一步引入
没过多久,超哥又来了,问能不能把所有籍贯为浙江的民警给找出来。我一看,很容易啊,等我几分钟,马上就好,代码继续撸起来。
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("查询结果1: " + result); System.out.println("-------------"); result = filterPoliceNativePlace(polices, "浙江");
System.out.println("查询结果2: " + 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;
} /**
* 民警籍贯过滤器
* @auth 公子奇
* @date 2019-01-02
* @param policeContainer 全部民警
* @param nativePlace 籍贯
* @return 符合结果的民警列表
*/
static List<Police> filterPoliceNativePlace(List<Police> policeContainer, String nativePlace) {
List<Police> result = new ArrayList<>();
for (Police police : policeContainer) {
if (nativePlace.equals(police.getPoliceNativePlace())) {
result.add(police);
}
}
return result;
}
}
写完之后,我发现有点不太对劲啊,filterPoliceAge和filterPoliceNativePlace这两个方法存在大量重复的代码,这个很明显违背了DRY(Don't Repeat Yourself,不要重复自己)的软件工程原则。随着后面民警属性的越来越多,这不是要命嘛!
四、策略设计模式的引入
分析上述任务,代码重复/业务逻辑也差不多,既然如此,策略模式就是很好的解决方案啊!说改就改,代码继续。关于策略模式查看我的GitHub策略模式介绍。
首先定义一个过滤处理接口
package com.hz.filter; import com.hz.pojo.Police; /**
* 民警过滤条件
*/
public interface PolicePredicate {
boolean test(Police police);
}
然后针对这个接口,分别实现年龄和籍贯实现类
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());
}
}
调用
package com.hz; import com.hz.filter.PoliceAgePredicate;
import com.hz.filter.PoliceNativePlacePredicate;
import com.hz.filter.PolicePredicate;
import com.hz.pojo.Police; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; public class PoliceMain2 {
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 = filterPolice(polices, new PoliceAgePredicate());
System.out.println("结果1: " + result); System.out.println("--------------"); result = filterPolice(polices, new PoliceNativePlacePredicate());
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; import com.hz.filter.PoliceAgePredicate;
import com.hz.filter.PoliceNativePlacePredicate;
import com.hz.filter.PolicePredicate;
import com.hz.pojo.Police; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; public class PoliceMain2 {
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 = filterPolice(polices, new PoliceAgePredicate());
System.out.println("结果1: " + result); System.out.println("--------------"); result = filterPolice(polices, new PoliceNativePlacePredicate());
System.out.println("结果2: " + result); System.out.println("----------------"); result = filterPolice(polices, new PolicePredicate() {
@Override
public boolean test(Police police) {
return police.getPoliceAge() > 30;
}
});
System.out.println("结果3: " + 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;
}
}
这样即实现了功能,也不需要创建大量的实现类,类增加的同时,也会增加我们的维护成本。后来仔细想了想,也不太好,类的维护是降低了,可是大量的匿名实现从代码可读性上也是存在很大缺陷的,还有更好的方案吗?
六、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);
}
这样一改,你需要筛选类型,自己去传就可以了。
package com.hz; import com.hz.filter.Predicate;
import com.hz.pojo.Police; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; public class PoliceMain4 {
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 = filter(polices, (Police police) -> police.getPoliceAge() > 30);
System.out.println("结果1: " + result); System.out.println("---------------"); result = filter(polices, (Police police) -> "浙江".equals(police.getPoliceNativePlace()));
System.out.println("结果2: " + result);
} /**
* 筛选器
* @param container
* @param predicate
* @return
*/
static <T> List<T> filter(List<T> container, Predicate<T> predicate) {
List<T> result = new ArrayList<>(); for (T e : container) {
if (predicate.test(e)) {
result.add(e);
}
} return result;
}
}
到此,即实现了行为参数化。关于Java8的一些概念和知识点我们再后续在去介绍。我们将开个系列去详细介绍Java8的使用。
公子奇带你一步一步了解Java8中行为参数化的更多相关文章
- 公子奇带你一步一步了解Java8中Lambda表达式
在上一篇<公子奇带你一步一步了解Java8中行为参数化>中,我们演示到最后将匿名实现简写为 (Police police) -> "浙江".equals(poli ...
- 公子奇带你进入Java8流的世界(二)
在上一篇中我们带领大家简单的了解流的概念及使用场景,本节我们就来好好的介绍流的常见用法. 一.筛选和切片 对于一串流,我们有时需要取出我们需要的流中某些元素,主要是通过谓词筛选.看代码: 首先定义一个 ...
- 公子奇带你进入Java8流的世界(一)
在说流之前,我们先来看看集合,为什么呢?作为Java8中的新成员,它和集合有很多相似之处,同时它们也是可以互相转化的.集合不仅仅是Java语言,任何一门高级开发语言都有集合的概念,集合顾名思义,就是很 ...
- 3、带你一步一步学习ASP.NET Core中的配置之Configuration
如果你是刚接触ASP.NET Core的学习的话,你会注意到:在ASP.NET Core项目中,看不到.NET Fraemwork时代中的web.config文件和app.config文件了.那么你肯 ...
- C#进阶系列——一步一步封装自己的HtmlHelper组件:BootstrapHelper(三:附源码)
前言:之前的两篇封装了一些基础的表单组件,这篇继续来封装几个基于bootstrap的其他组件.和上篇不同的是,这篇的有几个组件需要某些js文件的支持. 本文原创地址:http://www.cnblog ...
- 【新手出发】从搭虚拟机开始,一步一步在CentOS上跑起来.Net Core程序
文章背景 微软6月26号发布core 1.0版本后,园子里关于这方面的文章就更加火爆了,不管是从文章数量还是大家互动的热情来看,绝对是最热门的技术NO.1.我从去年底开始接触.net core到现在也 ...
- 一步一步学ROP之linux_x64篇
一步一步学ROP之linux_x64篇 一.序 **ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术可以用来绕过现代操作系统的各种通用防 ...
- 一步一步来做WebQQ机器人-(五)(发送消息||完结)
× 本篇主要是: 发送QQ消息(to:好友,群),以及对小黄鸡抓包利用它的语言库 本文是WebQQ流程的最后一章 最后一章内容不多但我还是啰嗦,可能对大部分人都已知晓的流程方法我也会介绍一下 前面几个 ...
- 一步一步搭框架(asp.netmvc+easyui+sqlserver)-02
一步一步搭框架(asp.netmvc+easyui+sqlserver)-02 我们期望简洁带前台代码,如下: <table id="dataGrid" class=&quo ...
随机推荐
- laravel setxxAttribute和getxxAttribute的使用
setxxAttribute 在设置(sql: insert update) 的时候 会将$obj->xx = 'value'的时候, 操作数据库之前 自动转化一下 getxxAttribute ...
- Oracle包utl_inaddr
作用:用于取得局域网或Internet环境中的主机名和IP地址. 1.utl_inaddr.get_host_address 环境中IP地址 如果查询失败,则提示系统错误 查询www.qq.com的I ...
- 【[Offer收割]编程练习赛9 D】 矩阵填数
[题目链接]:http://hihocoder.com/problemset/problem/1480 [题意] [题解] 这是一道杨氏矩阵的题; 一个固定形状的杨氏矩阵的种类个数; 等于这个杨氏矩阵 ...
- linux更新系统时间
查看时间 date 更新时间 yum install ntpdate ntpdate time.windows.com
- 使用模块定义AngularJS组件
一.模块创建/查找 module 当创建一个模块时,必须指定name和requires参数,即使你的模块并不存在依赖 var myApp=angular.module("exampleApp ...
- 理解和实现分布式TensorFlow集群完整教程
手把手教你搭建分布式集群,进入生产环境的TensorFlow 分布式TensorFlow简介 前一篇<分布式TensorFlow集群local server使用详解>我们介绍了分布式Ten ...
- supersockets命令过滤器
关键字: 命令过滤器, 命令, 过滤器, OnCommandExecuting, OnCommandExecuted SuperSocket 中的命令过滤器看起来有些像 ASP.NET MVC 中的 ...
- js中的数据类型及常用属性和方法
JavaScript 字符串 字符串(或文本字符串)是一串字符(比如 "Bill Gates").字符串被引号包围.您可使用单引号或双引号您可以在字符串内使用引号,只要这些引号与包 ...
- 基于jquery读取input上传的文件内容
<script src="/static/js/jquery.js"></script> // 前端页面实现头像预览 // 当用户选中文件之后,也就是头像的 ...
- HDU 1372
题意:模拟国际象棋马的走棋方式,和中国象棋一样马走日,8X8的棋盘,问从起点到终点的最短步数,国际象棋中数字代表行row,字母代表列column, 思路:记忆化深搜. #include<cstd ...