公子奇带你一步一步了解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 ...
随机推荐
- Java练习 SDUT-3106_小鑫数数儿
小鑫数数儿 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 某天小鑫忽然得到了许多的数字,他很好学,老师给他布置了一个任 ...
- deepin 安装golang protobuf
1.安装库文件protobuf,地址:https://github.com/protocolbuffers/protobuf/releases 我电脑是deepin 64位的,所以我直接下载https ...
- 「BZOJ1005」[HNOI2008] 明明的烦恼
「BZOJ1005」[HNOI2008] 明明的烦恼 先放几个prufer序列的结论: Prufer序列是一种对有标号无根树的编码,长度为节点数-2. 具体存在无根树转化为prufer序列和prufe ...
- Jquery常用方法汇总(转)
https://blog.csdn.net/lucky___star/article/details/87883888
- Linux 端口进程查看
netstat -lnp|grep 80
- 2015-2016 ACM-ICPC Southwestern Europe Regional Contest (SWERC 15)
C. Canvas Painting 合并果子. E. Wooden Signs \(dp(i,l,r)\)表示第\(i\)块木板的长度区间为\([l,r]\)的方案数,根据题意,\(l\)或\(r\ ...
- .net Framework 源代码 · ScrollViewer
本文是分析 .net Framework 源代码的系列,主要告诉大家微软做 ScrollViewer 的思路,分析很简单. 看完本文,可以学会如何写一个 ScrollViewer ,如何定义一个 IS ...
- yii框架不输出头文件和尾文件
控制器: public function actionCat(){ return $this->renderPartial('cat');} 在进行页面输出渲染的时候. 1.render 输出父 ...
- Python--day24--多继承
如果本生没有func方法的话就调用距离自己最近的基类的方法 钻石继承: 查找方法的顺序:如下例的找func方法(广度优先) 例1: 例2: 漏斗继承: 小乌龟继承问题:(最顶端的节点F是最后查找的) ...
- java 集合之Arraylist的遍历及排序
最近培训是先学习java基础 从最基本的开始学起 因为今天刚刚开博客 要把上周的一些重点内容归纳一下 1.Arraylist常用遍历以及排序 import java.util.ArrayList; i ...