公子奇带你一步一步了解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-1959_简单枚举类型——植物与颜色
简单枚举类型--植物与颜色 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 请定义具有red, orange, yell ...
- React Native中pointerEvent属性
在React Native界面开发中, 如果使用绝对定位布局,在代码运行时的某个时刻有可能会遮盖住它的下方的某个组件.这是因为绝对定位只是说这个组件的位置由它父组件的边框决定. 绝对定位的组件可以被认 ...
- oracle函数 COALESCE(c1, c2, ...,cn)
[功能]返回列表中第一个非空的表达式,如果所有表达式都为空值则返回1个空值 [参数]c1, c2, ...,cn,字符型/数值型/日期型,必须类型相同或null [返回]同参数类型 [说明]从Orac ...
- vue-router2.0的用法
随着vue越来越火,而vue-router却是一个项目不可或缺的,所以在这里结合实例总结一下router的用法,也是给自己的一个总结. 1.首先第一步当然是安装vue-router依赖,当然也可直接s ...
- PyTorch 学习笔记(四):权值初始化的十种方法
pytorch在torch.nn.init中提供了常用的初始化方法函数,这里简单介绍,方便查询使用. 介绍分两部分: 1. Xavier,kaiming系列: 2. 其他方法分布 Xavier初始化方 ...
- laravel博客后台操作步骤
- log4js的简单配置
js记录日志工具log4js,参数请参考官网文档https://log4js-node.github.io/log4js-node/index.html const log4js = require( ...
- iptables [match] 常用封包匹配参数
参数 -p, --protocol 范例 iptables -A INPUT -p tcp 说明 匹配通讯协议类型是否相符,可以使用 ! 运算符进行反向匹配,例如: -p !tcp 意思是指除 tcp ...
- HDU 5463
题意:一个盒子有36个格子.每个格子可以装64个物品,搬运一个箱子是一次搬运,问最少到搬运次数 思路:直接求总需要多少个格子,然后去求盒子,这里求盒子呢有个小技巧,就是用ceil函数 #include ...
- [转]Redis和Memcache区别,优缺点对比
1. Redis和Memcache都是将数据存放在内存中,都是内存数据库.不过memcache还可用于缓存其他东西,例如图片.视频等等. 2.Redis不仅仅支持简单的k/v类型的数据,同时还提供li ...