java8-重构、测试、调试

8.1.1 改善代码的可读性
改善代码的可读性到底意味着什么?我们很难定义什么是好的可读性,因为这可能非常主观。通常的理解是,“别人理解这段代码的难易程度”。改善可读性意味着你要确保你的代码能非常容易地被包括自己在内的所有人理解和维护。为了确保你的代码能被其他人理解,有几个步骤可以尝试,比如确保你的代码附有良好的文档,并严格遵守编程规范。跟之前的版本相比较,Java8的新特性也可以帮助提升代码的可读性:
口使用Java8,你可以减少冗长的代码,让代码更易于理解口通过方法引用和StreamAPI,你的代码会变得更直观这里我们会介绍三种简单的重构,利用Lambda表达式、方法引用以及Stream改善程序代码的可读性:
口重构代码,用amnbda表达式取代匿名类
口用方法引用重构Lammbda表达式
口用StreamAPI重构命令式的数据处理

改善可读性和灵活性重构代码

8.1.4 从命令式的数据处理切换到 Stream

  我们建议你将所有使用迭代器这种数据处理模式处理集合的代码都转换成Stream API的方式。为什么呢?Stream API能更清晰地表达数据处理管道的意图。除此之外,通过短路和延迟载人以及利用第7章介绍的现代计算机的多核架构,我们可以对Streamn进行优化。
比如,下面的命令式代码使用了两种模式:筛选和抽取,这两种模式被混在了一起,这样的代码结构迫使程序员必须彻底搞清楚程序的每个细节才能理解代码的功能。此外,实现需要并行运行的程序所面对的困难也多得多(具体细节可以参考7.2节的分支/合并框架):

List<gtring> dishNames =new rrayList<>()ifor(Dish dish:menu){
if(dish.getCalories()>300){
dishNames.add(dish.getName());

替代方案使用Steam API,采用这种方式编写的代码读起来更像是问题陈述,并行化也非常容易:

menu.parallelStream()
filter(d ->d.getCalories)>300).map(Dish::getName)collectitoList())

不幸的是,将命令式的代码结构转换为Stream API的形式是个困难的任务,因为你需要考虑控制流语句,比如break、continue、return,并选择使用恰当的流操作。好消息是已经有一些工具可以帮助我们完成这个任务.

8.1.5 增加代码的灵活性
第2章和第3章中,我们曾经介绍过Lambda表达式有利于行为参数化。你可以使用不同的Lambda表示不同的行为,并将它们作为参数传递给函数去处理执行。这种方式可以帮助我们淡定从容地面对需求的变化。比如,我们可以用多种方式为Predicate创建筛选条件,或者使用Comparator对多种对象进行比较。现在,我们来看看哪些模式可以马上应用到你的代码中,让你享受Lammbda表达式带来的便利。
1 采用函数接口
首先,你必须意识到,没有函数接口,你就无法使用Lambda表达式。因此,你需要在代码中引人函数接口。听起来很合理,但是在什么情况下使用它们呢?这里我们介绍两种通用的模式你可以依照这两种模式重构代码,利用Lambda表达式带来的灵活性,它们分别是:有条件的延迟执行和环绕执行。除此之外,在下一节,我们还将介绍一些基于面向对象的设计模式,比如策略模式或者模板方法,这些在使用Lammbda表达式重写后会更简洁
2.有条件的延迟执行
我们经常看到这样的代码,控制语句被混杂在业务逻辑代码之中。典型的情况包括进行安全性检查以及日志输出。比如,下面的这段代码,它使用了Java语言内置的Logger类:

if (logger.isLoggable(Log.FINER)){
logger.finer("Problem:"+ generateDiagnostic()) 

这段代码有什么问题吗?其实问题不少。
口日志器的状态(它支持哪些日志等级)通过isLoggable方法暴露给了客户端代码。
口为什么要在每次输出一条日志之前都去查询日志器对象的状态?这只能搞砸你的代码。

更好的方案是使用1og方法,该方法在输出日志消息之前,会在内部检查日志对象是否已经设置为恰当的日志等级:

logger.log(Level.FINER,"Problem:"+ generateDiagnostic());

这种方式更好的原因是你不再需要在代码中插人那些条件判断,与此同时日志器的状态也不再被暴露出去。不过,这段代码依旧存在一个问题。目志消息的输出与否每次都需要判断,即伸你已经传递了参数,不开启日志。
这就是Lambda表达式可以施展拳脚的地方。你需要做的仅仅是延迟消息构造,如此一来日志就只会在某些特定的情况下才开启(以此为例,当日志器的级别设置为FINER时)。显然,Java8的API设计者们已经意识到这个问题,并由此引人了一个对1og方法的重载版本,这个版本的1og方法接受一个supplier作为参数。这个替代版本的1og方法的函数签名如下:
public void log(Level level,supplier<string> msgSupplier)
你可以通过下面的方式对它进行调用:
logger.1og(Level.FINER,()->"Problem:+ateiagnosti))
如果日志器的级别设置恰当,1og方法会在内部执行作为参数传递进来的Lambda表达式。这里介绍的Log方法的内部实现如下:

public void log(Level level,supplier<String> msgSupplier){if(logger.isLoggable(level)){1og(level,msgSupplier.get())


执行Lambda表达式
从这个故事里我们学到了什么呢?如果你发现你需要频繁地从客户端代码去查询一个对象的状态(比如前文例子中的日志器的状态),只是为了传递参数、调用该对象的一个方法(比如输出一条日志),那么可以考虑实现一个新的方法,以Lambda或者方法表达式作为参数,新方法在检查完该对象的状态之后才调用原来的方法。你的代码会因此而变得更易读(结构更清晰)封装性更好(对象的状态也不会暴露给客户端代码了)。
3.环绕执行
第3章中,我们介绍过另一种值得考虑的模式,那就是环绕执行。如果你发现虽然你的业务代码千差万别,但是它们拥有同样的准备和清理阶段,这时,你完全可以将这部分代码用Lambda实现。这种方式的好处是可以重用准备和清理阶段的逻辑,减少重复冗余的代码。下面这段代码你在第3章中已经看过,我们再回顾一次。它在打开和关闭文件时使用了同样的逻辑,但在处理

文件时可以使用不同的Lambda进行参数化:
 
传入一个Lambda表达式processFile((BufferedReader b)->b.readLine());String twoLines =
String oneine
传入另一个Lambda表达式

processFile((BufferedReader b)->b.readLine()+ b.readLine());
public static String processFile(BufferedReaderProcessor p) throwsIOException{
try (BufferedReader br = new BufferedReader (new FileReader ("java8inact ion/chap8/data.txt"))){return p.process(br);
}


将BufferedReaderprocessor作为return p.process(br):执行参数传入使用Lambda表达式的函数接口,该接口能够抛出一个IOException
public interface BufferedReaderProcessori4String process(BufferedReader b)throws IException;
这一优化是凭借函数式接口BufferedReaderProcessor达成的,通过这个接口,你可以传

使用Lambda表达式的函数接口,该接口能够抛出一个IOException
public interface BufferedReaderProcessor{String process(BufferedReader b)throws IOException;
这一优化是凭借函数式接口BufferedReaderProcessor达成的,通过这个接口,你可以传递各种La1mba表达式对BufferedReader对象进行处理。通过这一节,你已经了解了如何通过不同方式来改善代码的可读性和灵活性。接下来,你会了解Lammbada表达式如何避免常规面向对象设计中的僵化的模板代码。

Validator numericValidator = new Validator(new IsNumeric());
boolean bl =numericValidator.validate("aaaa");
Validator lowerCaseValidator = new Validator(new IsAllLowerCase());
boolean b2 =lowerCaseValidator.validate("bbbb");


返回true
使用Lambda表达式
到现在为止,你应该已经意识到validationstrategy是一个函数接口了(除此之外,它还与Preaicate<string>具有同样的函数描述)。这意味着我们不需要声明新的类来实现不同的策略,通过直接传递Lambda表达式就能达到同样的目的,并且还更简洁:

Validator numericvalidatornew Validator((String s)-> s.matches("[a-z]+"));
boolean bl=numericValidator.validate("aaaa");
Validator lowerCaseValidator =new Validator((string s)-> s.matches("\\d+"));
boolean b2 =lowerCaseValidator.validate("bbbb");

直接传递Lambda表达式
正如你看到的,Lambda表达式避免了采用策略设计模式时僵化的模板代码。如果你仔细分析一下个中缘由,可能会发现,Lambda表达式实际已经对部分代码(或策略)进行了封装,而这就是创建策略设计模式的初衷。因此,我们强烈建议对类似的问题,你应该尽量使用Lambda表达式来解决。

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

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

相关文章

php基础学习之函数

基本概念 是一种语法结构&#xff0c;将实现某一个功能的代码块封装到一个结构中&#xff0c;从而实现代码的重复利用 php函数的定义语法 &#xff08;与C/Java很类似&#xff0c;区别在于没有数据类型&#xff0c;因为php是弱类型语言&#xff09; function 函数名(参数){ //…

问题:内存时序参数 CASLatency 是() #学习方法#微信#微信

问题&#xff1a;内存时序参数 CASLatency 是&#xff08;&#xff09; A&#xff0e;行地址控制器延迟时间 B&#xff0e;列地址至行地址延迟时间 C&#xff0e;列地址控制器预充电时间 D&#xff0e;列动态时间 参考答案如图所示

HTML-多媒体嵌入-MDN文档学习笔记

HTML-多媒体与嵌入 查看更多学习笔记&#xff1a;GitHub&#xff1a;LoveEmiliaForever MDN中文官网 HTML-中的图片 将图片放入网页 可以使用<img/>来将图片嵌入网页&#xff0c;它是一个空元素&#xff0c;最少只需src属性即可工作 <img src"图片链接"…

图像卷积、步长、填充、特征图、多通道卷积、权重共享、感受野、池化

图像卷积、步长、填充、特征图、多通道卷积、权重共享、感受野、池化 卷积神经网络的一些基本概念&#xff1a;图像卷积、步长、填充、特征图、多通道卷积、权重共享、感受野、池化 1.图像卷积、步长、填充 图像卷积&#xff1a;卷积核矩阵在一个原始图像矩阵上 “从上往下、…

CF1845 D. Rating System [思维题+数形结合]

传送门:CF [前题提要]:自己在做这道题的时候思路完全想错方向,导致怎么做都做不出来,看了题解之后感觉数形结合的思考方式挺好的(或者这种做法挺典的),故写篇题解记录一下 题目很简单,不再解释.先不考虑 k k k,想想是一种什么情况?很显然应该是跟下图一样是一个折线图的变化.…

ubuntu 22.04.3 live serveran图文安装

ubuntu 22.04.3 live server图文安装 一、在Vmware里安装ubuntu 22.04.3 live server操作系统 选择第一个选项开始安装 选择English语言 选择中间选项不更新安装&#xff0c;这是因为后续通过更换源之后再更新会比较快 键盘设计继续选择英文&#xff0c;可以通过语言选择…

TenorFlow多层感知机识别手写体

文章目录 数据准备建立模型建立输入层 x建立隐藏层h1建立隐藏层h2建立输出层 定义训练方式建立训练数据label真实值 placeholder定义loss function选择optimizer 定义评估模型的准确率计算每一项数据是否正确预测将计算预测正确结果&#xff0c;加总平均 开始训练画出误差执行结…

Spring Boot 笔记 012 创建接口_添加文章分类

1.1.1 实体类添加校验 package com.geji.pojo;import jakarta.validation.constraints.NotEmpty; import lombok.Data;import java.time.LocalDateTime;Data public class Category {private Integer id;//主键IDNotEmptyprivate String categoryName;//分类名称NotEmptypriva…

【MySQL】多表关系的基本学习

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-3oES1ZdkKIklfKzq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

【Linux】Framebuffer 应用

# 前置知识 LCD 操作原理 在 Linux 系统中通过 Framebuffer 驱动程序来控制 LCD。 Frame 是帧的意思&#xff0c; buffer 是缓冲的意思&#xff0c;这意味着 Framebuffer 就是一块内存&#xff0c;里面保存着一帧图像。 Framebuffer 中保存着一帧图像的每一个像素颜色值&…

17.3.1.3 灰度

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 灰度的算法主要有以下三种&#xff1a; 1、最大值法: 原图像&#xff1a;颜色值color&#xff08;R&#xff0c;G&#xff0c;B&a…

【python】网络爬虫与信息提取--requests库

导学 当一个软件想获得数据&#xff0c;那么我们只有把网站当成api就可以 requests库:自动爬取HTML页面&#xff0c;自动网络请求提交 robots协议&#xff1a;网络爬虫排除标准&#xff08;网络爬虫的规则&#xff09; beautiful soup库&#xff1a;解析HTML页面 工具&…

nginx2

mkdir /usr/local/develop cd /usr/local/develop 下载 wget http://nginx.org/download/nginx-1.17.4.tar.gz yum install git git clone https://github.com/arut/nginx-rtmp-module.git 解压文件 tar zxmf nginx-1.17.4.tar.gz 进入解压目录 cd nginx-1.17.4/ 安装编译…

《Go 简易速速上手小册》第9章:数据库交互(2024 最新版)

文章目录 9.1 连接数据库 - Go 语言的海底宝藏之门9.1.1 基础知识讲解安装数据库驱动数据库连接 9.1.2 重点案例&#xff1a;用户信息管理系统准备数据库Go 代码实现连接数据库添加新用户查询用户信息用户登录验证主函数 9.1.3 拓展案例 1&#xff1a;批量添加用户准备数据库Go…

【刷题】牛客— NC21 链表内指定区间反转

链表内指定区间反转 题目描述思路一&#xff08;暴力破解版&#xff09;思路二&#xff08;技巧反转版&#xff09;思路三&#xff08;递归魔法版&#xff09;Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&#xff01;&#xff01;&#xff01;下一篇文章见&…

IIC--集成电路总线

目录 一、IIC基础知识 1、设计IIC电路的原因&#xff1a; 2、上拉电阻阻值怎么确定 3、IIC分类 4、IIC协议 二、单片机使用IIC读写数据 1、 IIC发送一个字节数据&#xff1a; 2、IIC读取一个字节数据&#xff1a; 一、IIC基础知识 1、设计IIC电路的原因&#xff1a; (…

【机器学习案例5】语言建模 - 最常见的预训练任务一览表

自监督学习 (SSL) 是基于 Transformer 的预训练语言模型的支柱,该范例涉及解决有助于建模自然语言的预训练任务 (PT)。本文将所有流行的预训练任务放在一起,以便我们一目了然地评估它们。 SSL 中的损失函数 这里的损失函数只是模型训练的各个预训练任务损失的加权和。 以BE…

selenium定位元素报错:‘WebDriver‘ object has no attribute ‘find_element_by_id‘

Selenium更新到 4.x版本后&#xff0c;以前的一些常用的代码的语法发生了改变 from selenium import webdriver browser webdriver.Chrome() browser.get(https://www.baidu.com) input browser.find_element_by_id(By.ID,kw) input.send_keys(Python)目标&#xff1a;希望通…

IP地址+子网掩码+CIDR学习笔记

目录 一、IP地址 1、表示方法&#xff1a; 2、特殊IP地址 二、子网掩码 1、判断网络位和主机位 2、子网划分 三、无分类编址CIDR 1、CIDR路由汇聚 汇聚规则&#xff1a; 汇聚ID&#xff1a; 2、最佳路由匹配原则 一、IP地址 1、表示方法&#xff1a; 机器中存放的…

STM32F1 - 中断系统

Interrupt 1> 硬件框图2> NVIC 中断管理3> EXTI 中断管理3.1> EXTI与NVIC3.2> EXTI内部框图 4> 外部中断实验4.1> 实验概述4.2> 程序设计 5> 中断向量表6> 总结 1> 硬件框图 NVIC&#xff1a;Nested Vectored Interrupt Controller【嵌套向量…