Java8实战-总结35

Java8实战-总结35

  • 重构、测试和调试
    • 使用 Lambda 重构面向对象的设计模式
      • 工厂模式
    • 测试 Lambda 表达式
      • 测试可见 Lambda 函数的行为
      • 测试使用 Lambda 的方法的行为
      • 将复杂的 Lambda 表达式分到不同的方法
      • 高阶函数的测试

重构、测试和调试

使用 Lambda 重构面向对象的设计模式

工厂模式

使用工厂模式,你无需向客户暴露实例化的逻辑就能完成对象的创建。比如,假定你为一家银行工作,他们需要一种方式创建不同的金融产品:贷款、期权、股票,等等。通常,你会创建一个工厂类,它包含一个负责实现不同对象的方法,如下所示:

public class ProductFactory { public static Product createProduct(String name) { switch(name) { case "loan": return new Loan(); case "stock": return new Stock(); case "bond": return new Bond(); default: throw new RuntimeException("No such product " + name); } } 
} 

这里贷款(Loan)、股票(Stock)和债券(Bond)都是产品(Product)的子类。createProduct方法可以通过附加的逻辑来设置每个创建的产品。但是带来的好处也显而易见,在创建对象时不用再担心会将构造函数或者配置暴露给客户,这使得客户创建产品时更加简单:

Product p = ProductFactory.createProduct("loan"); 

使用Lambda表达式
可以像引用方法一样引用构造函数。比如,下面就是一个引用贷款(Loan)构造函数的示例:

Supplier<Product> loanSupplier = Loan::new; 
Loan loan = loanSupplier.get(); 

通过这种方式,可以重构之前的代码,创建一个Map,将产品名映射到对应的构造函数:

final static Map<String, Supplier<Product>> map = new HashMap<>(); static { map.put("loan", Loan::new); map.put("stock", Stock::new); map.put("bond", Bond::new); } 

现在,可以像之前使用工厂设计模式那样,利用这个Map来实例化不同的产品。

public static Product createProduct(String name) { Supplier<Product> p = map.get(name); if(p != null) return p.get(); throw new IllegalArgumentException("No such product " + name); 
} 

这是个全新的尝试,它使用Java 8中的新特性达到了传统工厂模式同样的效果。但是,如果工厂方法createProduct需要接收多个传递给产品构造方法的参数,这种方式的扩展性不是很好。不得不提供不同的函数接口,无法采用之前统一使用一个简单接口的方式。

比如,假设希望保存具有三个参数(两个参数为Integer类型,一个参数为String类型)的构造函数;为了完成这个任务,需要创建一个特殊的函数接口TriFunction。最终的结果是Map变得更加复杂。

public interface TriFunction<T, U, V, R> { R apply(T t, U u, V v); 
} Map<String, TriFunction<Integer, Integer, String, Product>> map = new HashMap<>(); 

已经了解了如何使用Lambda表达式编写和重构代码。接下来,会介绍如何确保新编写代码的正确性。

测试 Lambda 表达式

现在代码中已经充溢着Lambda表达式,看起来不错,也很简洁。但是,大多数时候,程序开发工作的要求并不是编写优美的代码,而是编写正确的代码。

通常而言,好的软件工程实践一定少不了单元测试,借此保证程序的行为与预期一致。编写测试用例,通过这些测试用例确保你代码中的每个组成部分都实现预期的结果。比如,图形应用的一个简单的Point类,可以定义如下:

	public class Point { private final int x; private final int y; private Point(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; }public int getY() { return y; } public Point moveRightBy(int x) { return new Point(this.x + x, this.y); } } 

下面的单元测试会检查moveRightBy方法的行为是否与预期一致:

@Test public void testMoveRightBy() throws Exception { Point p1 = new Point(5, 5); Point p2 = p1.moveRightBy(10); assertEquals(15, p2.getX()); assertEquals(5, p2.getY()); } 

测试可见 Lambda 函数的行为

由于moveRightBy方法声明为public,测试工作变得相对容易。可以在用例内部完成测试。但是Lambda并无函数名(毕竟它们都是匿名函数),因此要对代码中的Lambda函数进行测试实际上比较困难,因为无法通过函数名的方式调用它们。

有些时候,可以借助某个字段访问Lambda函数,这种情况,可以利用这些字段,通过它们对封装在Lambda函数内的逻辑进行测试。比如,假设在Point类中添加了静态字段compareByXAndThenY,通过该字段,使用方法引用可以访问Comparator对象:

public class Point { public final static Comparator<Point> compareByXAndThenY = comparing(Point::getX).thenComparing(Point::getY); 
}

Lambda表达式会生成函数接口的一个实例。由此,可以测试该实例的行为。这个例子中,可以使用不同的参数,对Comparator对象类型实例compareByXAndThenYcompare方法进行调用,验证它们的行为是否符合预期:

@Test 
public void testComparingTwoPoints() throws Exception { Point p1 = new Point(10, 15); Point p2 = new Point(10, 20); int result = Point.compareByXAndThenY.compare(p1 , p2); assertEquals(-1, result); 
} 

测试使用 Lambda 的方法的行为

但是Lambda的初衷是将一部分逻辑封装起来给另一个方法使用。从这个角度出发,不应该将Lambda表达式声明为public,它们仅是具体的实现细节。相反,需要对使用Lambda表达式的方法进行测试。比如下面这个方法moveAllPointsRightBy

	public static List<Point> moveAllPointsRightBy(List<Point> points, int x) { return points.stream().map(p -> new Point(p.getX() + x, p.getY())).collect(toList()); } 

没必要对Lambda表达式p -> new Point(p.getX() + x,p.getY())进行测试,它只是moveAllPointsRightBy内部的实现细节。更应该关注的是方法moveAllPointsRightBy的行为:

@Test 
public void testMoveAllPointsRightBy() throws Exception { List<Point> points = Arrays.asList(new Point(5, 5), new Point(10, 5)); List<Point> expectedPoints = Arrays.asList(new Point(15, 5), new Point(20, 5)); List<Point> newPoints = Point.moveAllPointsRightBy(points, 10); assertEquals(expectedPoints, newPoints); 
} 

上面的单元测试中,Point类恰当地实现equals方法非常重要,否则该测试的结果就取决于Object类的默认实现

将复杂的 Lambda 表达式分到不同的方法

可能会碰到非常复杂的Lambda表达式,包含大量的业务逻辑,比如需要处理复杂情况的定价算法。无法在测试程序中引用Lambda表达式,这种情况该如何处理呢?一种策略是将Lambda表达式转换为方法引用(这时往往需要声明一个新的常规方法)。

高阶函数的测试

接受函数作为参数的方法或者返回一个函数的方法(“高阶函数”,higher-order function)更难测试。如果一个方法接受Lambda表达式作为参数,

可以采用的一个方案是使用不同的Lambda表达式对它进行测试。比如,可以使用不同的谓词对filter方法进行测试。

@Test 
public void testFilter() throws Exception { List<Integer> numbers = Arrays.asList(1, 2, 3, 4); List<Integer> even = filter(numbers, i -> i % 2 == 0); List<Integer> smallerThanThree = filter(numbers, i -> i < 3); assertEquals(Arrays.asList(2, 4), even); assertEquals(Arrays.asList(1, 2), smallerThanThree); 
}

如果被测试方法的返回值是另一个方法,该如何处理呢?可以仿照之前处理Comparator的方法,把它当成一个函数接口,对它的功能进行测试。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/87916.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JSON数据获取指南!

在互联网时代&#xff0c;数据是金钱的来源。然而&#xff0c;要从海量的网页中提取需要的数据并不容易。本文将带你了解如何使用Node.js编写简易爬虫程序&#xff0c;帮助你轻松获取并处理JSON数据&#xff0c;让你不再为数据发愁。 一、准备工作 安装Node.js&#xff1a;确保…

如何在控制台打印sql语句

步骤一&#xff1a; log4j2.xml中做以下配置 <logger name"xxx.infrastructure.mysql.mapper"level"debug" additivity"false"><appender-ref ref"Console"/></logger>步骤二&#xff1a;IDEA下载Free Mybatis Plu…

9、JavaSE总结

9、JavaSE总结 9.1 Java语言 9.1.1 MarkDown语法 9.1.2 简单的Dos命令 9.1.3计算机语言发展 9.1.4 Java的诞生 1995年诞生&#xff1a;JavaSE、JavaME、JavaEE 2006年Hadoop大数据系列 9.1.5 JDK、JRE JDK&#xff1a;开发者工具包、配置环境变量&#xff08;配置Java…

Vue Mock.js介绍和使用与首页导航栏左侧菜单搭建

前言&#xff1a; 因为使用Vue开发&#xff0c;组件写的太多&#xff0c;组件与组件之间的传递数据复杂&#xff0c;所以要用到Mock和Bus事件 一&#xff0c;关于Mock 1.1.什么是Mock.js Mock.js是一个模拟数据的生成器&#xff0c;用来帮助前端调试开发、进行前后端的原型分离…

upload-labs靶场未知后缀名解析漏洞

upload-labs靶场未知后缀名解析漏洞 版本影响&#xff1a; phpstudy 版本&#xff1a;5.2.17 ​ 1 环境搭建 1.1 在线靶场下载&#xff0c;解压到phpstudy的www目录下&#xff0c;即可使用 https://github.com/c0ny1/upload-labs1.2 已启动&#xff1a;访问端口9000&…

似然和概率

前言 高斯在处理正态分布的首次提出似然&#xff0c;后来英国物理学家&#xff0c;费歇尔 概率是抛硬币之前&#xff0c;根据环境推断概率 似然则相反&#xff0c;根据结果推论环境 P是关于x的函数&#xff0c;比如x为正面朝上的结果&#xff0c;或者反面朝上的结果&#xf…

数据大爆炸:大数据分析如何改变我们的世界

文章目录 大数据分析的基本概念数据的三个V大数据分析的技术 大数据分析在商业中的应用1. 个性化营销2. 风险管理3. 供应链优化4. 客户服务 大数据分析在医疗保健中的应用1. 疾病预测2. 患者治疗3. 医疗设备监控 大数据分析在科学研究中的应用1. 天文学2. 生物学3. 气象学 大数…

如何搭建自己的gitlab服务器

这里使用Termus工具连接服务器&#xff0c;然后根据步骤走即可&#xff01; 安装 1.配置yum源安装gitlab vim /etc/yum.repos.d/gitlab-ce.repo修改或新增下面配置并保存 [gitlab-ce] nameGitlab CE Repository baseurlhttps://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum…

pycharm中配置torch

在控制台cmd中安装好torch后&#xff0c;在pycharm中使用torch&#xff0c;需要进行简单设置即可。 在pycharm中新建一个工程&#xff0c;在file文件中打开setting 在setting中找到project interpreter编译器 找到conda environment的环境配置&#xff0c;设置好相应的目录 新…

2023年蓝帽杯取证复现

案件介绍 2021 年 5 月&#xff0c;公安机关侦破了一起投资理财诈骗类案件&#xff0c;受害人陈昊民向公安机关报案称其在微信上认识一名昵称 为 yang88 的网友&#xff0c;在其诱导下通过一款名为维斯塔斯的 APP &#xff0c;进行投资理财&#xff0c;被诈骗 6 万余万元。接警…

华为OD机考算法题:篮球比赛

目录 题目部分 解读与分析 代码实现 题目部分 题目篮球比赛难度难题目说明篮球(5V5)比赛中&#xff0c;每个球员拥有一个战斗力&#xff0c;每个队伍的所有球员战斗力之和为该队伍的总体战斗力。现有 10 个球员准备分为两队进行训练赛&#xff0c;教练希望 2 个队伍的战斗力…

如何搭建VUE项目开发环境?

搭建Vue.js项目的开发环境通常包括以下主要步骤&#xff1a; 1、安装Node.js和npm&#xff1a; Vue.js项目需要Node.js和npm&#xff08;Node Package Manager&#xff09;作为基础环境。你可以从Node.js官网下载并安装它们&#xff1a;Node.js官网 安装完成后&#xff0c;你…

Java深入理解线程的三大特性

目录 1 CPU缓存导致可见性问题2 线程切换导致原子性问题3 性能优化导致有序性问题4 JMM(Java Memory Model)5 volatile6 synchronized 1 CPU缓存导致可见性问题 线程的三大特性&#xff1a; 可见性&#xff1a;Visibility有序性&#xff1a;Ordering原子性&#xff1a;Atomic…

谈谈最近招人的感受!

最近折腾新的项目&#xff0c;面试了很多实习生小伙伴&#xff0c;我说说我的一些「面试」感受&#xff0c; 虽然是一个老生常谈的话题&#xff0c;但是依然提一下。 准时很重要&#xff1a;提前一点时间&#xff0c;踩个点&#xff0c;别迟到&#xff0c;面试的过程中由于每个…

2023年前端流行什么技术和框架了?

Web前端三大主流框架有React、Vue.js和Angular&#xff0c;由于接触过Vue.js&#xff0c;接下来主讲最新的Vue3.0&#xff01; Vue3.0作为最新版本的Vue.js框架&#xff0c;拥有更强大的性能和更丰富的功能&#xff0c;为低代码开发平台注入了全新的活力。而JNPF快速开发平台作…

Go业务开发常用关注点

本文对实际开发场景中面对高频的场景&#xff0c;总结出来的一些处理方案&#xff0c;希望能对业务开发的同学提供帮助&#xff01; 1. 结构体转换 实际开发中会面对一个相似的数据结构&#xff0c;由于引用不同的包&#xff0c;需要开发转换到对应的结构上&#xff0c;本质上…

浅谈xss

XSS 简介 XSS,全称Cross Site Scripting,即跨站脚本攻击,是最普遍的Web应用安全漏洞。这类漏洞能够使得攻击者嵌入恶意脚本代码到正常用户会访问到的页面中,当正常用户访问该页面时,则可导致嵌入的恶意脚本代码的执行,从而达到恶意攻击用户的目的。需要强调的是,XSS不仅…

setTimeout,setInterval,setImmdeiate的区别

setTimeout, setInterval, 和 setImmediate 是 JavaScript 中用于执行异步操作的定时器函数&#xff0c;它们之间有一些重要的区别&#xff1a; 1. setTimeout: - setTimeout 用于在一定的延迟时间后执行一个函数。 - 它接受两个参数&#xff1a;要执行的函数和延迟的毫…

webpack、vue.config.js

一、webpack学习 简述 webpack是一个静态资源打包工具&#xff0c;它会以一个或多个文件作为打包的入口&#xff0c;将我们整个项目的文件编译组合成一个或多个文件输出出去。输出的文件就是编译好的文件&#xff0c;可以运行在浏览器中。一般的我们将webpack输出的文件叫做b…

使用ElementUI结合Mock完成主页的搭建

目录 一、Mock ( 1 ) 讲述 ( 2 ) 作用 二、引用 三、主页搭建 学习后带来的收获 一、Mock ( 1 ) 讲述 Mock.js是一个用于前端开发中模拟数据的库。它可以帮助开发人员在前端开发过程中模拟接口返回的数据&#xff0c;从而实现前后端分离开发。Mock.js提供了一套简单易…