编程技巧:小技巧,大作用,一招提高代码的可读性

目录

1.引言

2.将复杂的代码模块化

3.避免函数的参数过多

4.移除函数中的 flag 参数

5.移除嵌套过深的代码

6.学会使用解释性变量


1.引言

        本节介绍一些实用的编程技巧。编程技巧比较琐碎、比较多。在本节中,作者仅列出了一些个人认为非常实用的编程技巧,更多的技巧需要读者在实践中慢慢积累。

2.将复杂的代码模块化

        在编写代码时,我们要有模块化思维,善于将大块的复杂的代码封装成类或函数,让阅读代码的人不会迷失在代码的细节中,这样能极大地提高代码的可读性。我们结合示例代码进行说明。

//重构前的代码
public void invest(long userId, long financialProductId){
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);    
    calendar.set(Calendar.DATE(calendar.get(Calendar.DATE)+1));
    if(calendar.get(Calendar.DAY OF MONTH)==1){
        return;
    }
    ...
}

//原构后的代码:封装成isLastDayofMonth()函数之后,逻辑更加清晰
public void invest(long userId, long fnancialProductId){
    if(isLastDayofMonth(new Date())){
        return;
    }
    public boolean isLastDayOfMonth(Date date){
        Calendar calendar=Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, (calendar.get(Calendar.DATE)+ 1));        
        if(calendar.get(Calendar.DAY_OF_MONTH)==1){
            return true;
        }
        return false,
    }
}

        在重构前,imvest()函数中的关于时间处理的代码比较难理解。重构之后,我们将其抽象成isLastDayOfMonth函数,从该函数的命名,我们就能清晰地了解它的功能:判断某天是不是当月的最后一天。

3.避免函数的参数过多

        如果函数的参数过多,那么我们在阅读或使用该函数时都会感到不方便。函数包含多少参数才算过多呢?当然,这也没有固定标准。根据作者的经验,函数的参数一般超过5个就算过多了,因为函数参数超过5个之后,在调用函数时,调用语句容易超出一行代码的长度,要将其分为两行甚至多行,导致代码的可读性降低。除此之外,参数过多也增加了传递出错风险。

        如果导致函数的参数过多的原因是函数的职责不单一,那么我们可以通过将这个函数拆分成多个函数的方式来减少参数。示例代码如下。

public User getUser(String id,String username, String telephone, String email,String udid,     
                    String uuid);//拆分成多个函数
public User getUserById(String id);
public User getUserByUsername(String username);
public User getUserByTelephone(String telephone);
public User getUserByEmail(String email);
public User getUserByUdid(String udid);
public User getUserByUuid(string uuid);

        针对函数参数过多的问题,我们还可以通过将参数封装为对象的方式来解决。这种处理式不仅可以减少参数的个数,还能提高函数的兼容性。在向函数中添加新的参数时,只需要问对象中添加成员变量,不需要改变函数定义,原来的调用代码不需要修改。示例代码如下。

public void postBlog(String title, String summary, String keywords, String content
            String category,long authorId);//将参数封装成对象
public class Blog{
    private String title;
    private String summary;
    private String keywords;
    private Strint content;
    private String category;
    private long authorId; 
}
public void postBlog(Blog blog);

4.移除函数中的 flag 参数

        我们不应该在函数中使用布尔类型的 fag(标识)参数来控制内部逻辑(hag为me时执行一个代码逻辑,fag为alse 时执行另一个代码逻辑),这违背单一职贵原则和接口隔离原则。我们建议将包含 flag参数的函数拆分成两个函数。示例代码如下,其中,isVip是 flag参数。

public void buyCourse(long userId, long courseId, boolean isVip) ;
//将其拆分成两个函数
public void buyCourse(long userId, long courseId);
public void buyCourseForVip(long userId, long courseId);

        不过,如果函数是私有(private)函数,其影响范围有限,或者拆分之后的两个函数经常同时被调用,那么我们可以考虑保留 flag 参数。示例代码如下。

//拆分成两个函数之后的调用方式
boolean isVip=false;
...
if(isVip){
    buyCourseForVip(userId,courseId)
}else (
    buyCourse(userId,courseId);
}
//保留flag参数调用方式,代码更加简洁
boolean isVip = false;
...
buyCourse(userId,courseId,isVip);

        实际上,在函数中,除使用布尔类型的 flag参数来控制内部逻辑以外,还有人喜欢使用参数是否为 null 来控制内部逻辑。对于后一种情况,我们也应该将这个函数拆分成多个函数。拆分之后的函数的职责明确。示例代码如下,其中,selectTransactions()函数根据参数startDate、endDate 是否为 null,执行不同的代码逻辑。

public list<Transaction> selectTransactions(Long userId, Date startDate, Date endDate){
    if(startDate != null && endDate != null){
        //查询两个时间之间的交易
    }
    if(startDate != null && endDate == null){
        //查询startDate之后的所有交易
    }
    if(startDate ==null && endDate != null){
        //查询endDate之前的所有交易
    }
    if (startDate == null && endDate == null){
        //查询所有的交易
    }
}
public List<Transaction> selectTransactionsBetween(Long userId, Date startDate, Date endDate) {
    //拆分成多个公共(public)函数,代码变得清晰、易用
    return selectTransactions(userId, startDate, endDate);
}
Public list<Transaction> selectTransactionsStartWith(Long userId, Date startDate) 
    return selectTransactions(userId, startDate, null);
}

Public list<Transaction> selectTransactionsEndWith(Long userld, Date endDate){
    return selectTransactions(userId,null,endDate);
}
public List<Transaction> selectAllTransactions(Long userId){
    return selectTransactions(userId,null,null);
}
private list<Transaction> selectTransactions(Long userId, Date startDate, Date endDate){
    ...
}

5.移除嵌套过深的代码

        代码嵌套过深往往是因为if-else、switch-case和for 循环过度嵌套。作者建议嵌套最好不超过两层,如果嵌套超过两层,就要想办法减少嵌套层数。嵌套过深导致代码语句多次缩进大量代码语句超过一行的长度而被分成两行或多行,影响代码的可读性。

        针对嵌套过深的问题,作者总结了下列4种常见的处理思路。

        1)去掉几余的 if、else 语句,示例代码如下:

//示例一
public double caculateTotalAmount(List<Order> orders){
    if(orders == null || orders.isEmpty()){
        return 0.0;
    }else{ //if内部使用return,因此,此处的else可以去掉
        double amount = 0.0;
        for(Order order:orders){
        if(order != null){
            amount += (order.getCount()*order.getPrice());      
        }
    }
    return amount;
}
//示例二
Public List<String> matchStrings(List<string> strList, String substr){
    List<String> matchedStrings = new ArrayList<>();
    if(strList != null && substr != null){
        for (String str : strList){
            if(str != nu11){//此处的if可以与下一行的if语句合并for(String str:strList)            
               if(str.contains(substr)){
                    matchedStrings.add(str);
                }
            }
        }
    }
    return matchedStrings;
}

        2)使用 continue、break和retum 关键字提前退出嵌套,示例代码如下。

 //重构前的代码
public List<String> matchStrings(List<String> strList, String substr){
    List<String> matchedStrings = new List<>();
    if(strList != null && substr != null){
        for(String str : strList){
            if(str != null && str.contains(substr)){
                matchedStrings.add(str);
                ...
            }
        }
    }
    return matchedStrings;
}
//重构后的代码:使用continue提前退出嵌套
public List<string> matchstrings(List<string> strlist,String substr){
    List<String> matchedStrings = new ArrayList<>();
    if(strList !=null && substr !=null){
        for(String str:strList){
            if(str==null || !str.contains(substr)){
                continue;
            }
            matchedStrings.add(str);
            ...
        }
    return matchedStrings;
}

        3)通过调整执行顺序来减少嵌套层数,示例代码如下。

//重构前的代码
public list<String> matchStrings(List<String> strlist,String substr){
    List<String> matchedstrings = new ArrayList<>();
    if(strList != null && substr != null){
        for (String str:strlist){
            if(str!=null){
                if(str.contains(substr)){
                    matchedStrings.add(str);
                }
            }
        }
    return matchedStrings;
}
//重构后的代码:先执行判断是否为空逻辑,再执行正常逻辑
public list<string> matchstrings(List<string> strlist,String substr){
    if(strList != nu11 && substr != nu1l){//先判断是否为空
        return Collections.emptyList();
    }
    List<String> matchedStrings = new ArrayList<>();
    for(String str:strList){
        if(str!=null){
            if(str.contains(substr)){
                matchedStrings.add(str);
            }
        }
    }
    return matchedstrings;
}

        4)我们可以将部分嵌套代码封装成函数,以减少嵌套层数,示例代码如下。


//重构前的代码
public List<string> appendSalts(List<string> passwords){
    if(passwords == null || passwords.isEmpty()){
        return Collections.emptylist();
    }
    List<String> passwordsWithSalt = new rrayList<>();
    for(String password:passwords){
        if(password==null){
            continue;
        }
        if(password.length()<8){
            ...
        }else {
            ...
        }
    }
    return passwordswithSalt;
}

//重构后的代码:将部分代码封装为函数
public List<String> appendSalts(List<String> passwords){
    if(passwords == null || passwords.isEmpty()){
        return Collections.emptyiist();
    }
    List<String> pasowordanithSalt = new ArrayList<>();
    for(String password :Passwords){
        if(password == null){
            continue;
        }
        passwordsWithSolt.add(appendSalt(password));
    }
    return passwordsWithSolt;
}
private String appendSalt(String password) {
    String passwordWithSalt = password;
    if(paasword.length()<8){
        ...
    }else{
        ...
    }
    return passwordwithSalt;
}

6.学会使用解释性变量

        解释性变量可以提高代码的可读性,也可以减少不必要的注释。常用的解释性变量有以下两种。

        1)使用常量取代魔法数字,示例代码如下。

public double CalculatecircularArea(double radius) {
    return (3.1415)*radius*radius;
}

//常量替代魔法数字
public static final Double PI =  3.1415;

public double CalculateCircularArea(double radius){
    return PI * radius * radius;
}

        2)使用解释性变量来解释复杂表达式,示例代码如下。

if (date.after(SUMMER_START) && date.before(SUMMER_END)){
    ...
}else {
    ...
}

//引入解释性变量后,代码更易被人理解
boolean isSummer = date.after(SUMMER START)&&date.before(SUMMER END);
if(isSummer){
    ...
}else {
    ...
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Latent Guard、Tokenization in LLM、​3D Human Scan、FusionPortableV2

本文首发于公众号&#xff1a;机器感知 https://mp.weixin.qq.com/s/HlVV3VnqocBI4XBOT6RFHg A Multi-Level Framework for Accelerating Training Transformer Models The fast growing capabilities of large-scale deep learning models, such as Bert, GPT and ViT, are r…

微软开源 WizardLM-2,70B优于GPT4-0613,7B持平阿里最新的Qwen1.5-32B

当地时间4月15号&#xff0c;微软发布了新一代大语言模型 WizardLM-2&#xff0c;新家族包括三个尖端型号:WizardLM-2 8x22B, WizardLM-2 70B&#xff0c;和WizardLM-2 7B&#xff0c;作为下一代最先进的大型语言模型&#xff0c;它在复杂聊天、多语言、推理和代理方面的性能有…

算法打卡day37

今日任务&#xff1a; 1&#xff09;1049. 最后一块石头的重量 II 2&#xff09;494. 目标和 3&#xff09;474.一和零 4&#xff09;复习day12 1049. 最后一块石头的重量 II 题目链接&#xff1a;1049. 最后一块石头的重量 II - 力扣&#xff08;LeetCode&#xff09; 题目难…

B1100 校庆

输入样例&#xff1a; 5 372928196906118710 610481197806202213 440684198612150417 13072819571002001X 150702193604190912 6 530125197901260019 150702193604190912 220221196701020034 610481197806202213 440684198612150417 370205198709275042 输出样例&#xff1a;…

LINUX中使用cron定时任务被隐藏,咋回事?

一、问题现象 线上服务器运行过程中&#xff0c;进程有莫名进程被启动&#xff0c;怀疑是有定时任务自动启动&#xff0c;当你用常规方法去查看&#xff0c;比如使用crontab去查看定时器任务&#xff0c;提示no crontab for root 或者使用cat到/var/spool/cron目录下去查看定时…

python使用uiautomator2操作真机(华为Honor 10)

环境&#xff1a; python3.8.10&#xff0c;华为手机Honor 10(6G,64g)&#xff0c;版本android 9。 之前写过一篇文章&#xff1a; python使用uiautomator2操作真机_python uiautomator2 控制真机-CSDN博客 今天再拿另外一部手机测试。 一、将手机设置为开发者模式 1、设…

基于ssm冀中工程技师校园网站设计与实现论文

摘 要 使用旧方法对冀中工程技师学院网站的信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在冀中工程技师学院网站的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误不能及时纠正等问题。这次…

【数据恢复软件】:Magnet AXIOM V8.0

Magnet AXIOM V8.0重大更新 1、全新的UI设计 2、更快的相应速度 3、补全工件分析 4、支持亚马逊AWS云数据&#xff08; 获取同一帐户或安全帐户上下文中的快照。 支持Windows实例、加密卷和超过1 TB的卷、具有多个卷的实例等等&#xff01; &#xff09; 5、Bug修复 6、AI支持…

Promise模块化编程ES6新特性

文章目录 Promise&模块化编程1.Promise基本介绍2.快速入门1.需求分析2.原生ajax jQuery3.Promise使用模板 3.课后练习1.原生ajax jQuery2.promise 4.模块化编程基本介绍5.CommonJS基本介绍6.ES5模块化编程1.题目2.示意图3.代码实例—普通导入导出function.jsuse.js 4.代码…

JVM垃圾回收与算法

1. 如何确定垃圾 1.1 引用计数法 在 Java 中&#xff0c;引用和对象是有关联的。如果要操作对象则必须用引用进行。因此&#xff0c;很显然一个简单 的办法是通过引用计数来判断一个对象是否可以回收。简单说&#xff0c;即一个对象如果没有任何与之关 联的引用&#xff0c;即…

推荐系统综述

推荐系统研究综述 - 中国知网 传统推荐方法主要分类&#xff1a; 1)基于内容推荐方法 主要依据用户与项目之间的特征信息,用户之间的联系不会影响推荐结果,所以不存在冷启动和稀疏问题,但是基于内容推荐的结果新颖程度低并且面临特征提取的问题。 基于内容的推荐方法的思想非…

能源成果3D网络三维展厅越发主流化

在这个数字化飞速发展的时代&#xff0c;我们为您带来了全新的展览形式——线上3D虚拟展厅。借助VR虚拟现实制作和web3d开发技术&#xff0c;我们能够将物品、图片、视频和图文信息等完美融合&#xff0c;通过计算机技术和3D建模&#xff0c;为您呈现一个逼真、生动的数字化展览…

动态规划|1049.最后一块石头的重量II

力扣题目链接 class Solution { public:int lastStoneWeightII(vector<int>& stones) {vector<int> dp(15001, 0);int sum 0;for (int i 0; i < stones.size(); i) sum stones[i];int target sum / 2;for (int i 0; i < stones.size(); i) { // 遍…

开源项目one-api的k8s容器化部署(下)-- 部署至k8s

一、接着上文 本文讲述如何把上文制作好的docker镜像部署到K8S&#xff0c;会涉及以下部分&#xff1a; 健康检测应用程序的配置应用程序的端口日志路径 二、健康检测 1、健康状态 从官方的docker-compose.yml可以得知其健康检测方法 curl http://localhost:5175/api/statu…

03-JAVA设计模式-迭代器模式

迭代器模式 什么是迭代器模式 迭代器模式&#xff08;demo1.Iterator Pattern&#xff09;是Java中一种常用的设计模式&#xff0c;它提供了一种顺序访问一个聚合对象中各个元素&#xff0c;而又不需要暴露该对象的内部表示的方法。迭代器模式将遍历逻辑从聚合对象中分离出来…

Latex学习(从入门到入土)2

第一章 &#xff1a;插图 在LaTeX中插入插图可以通过graphicx宏包来实现&#xff0c;这个宏包提供了强大的图像处理功能。以下是如何使用graphicx宏包插入图像的基本步骤&#xff1a; ### 1. 加载宏包 在文档的序言部分&#xff08;\begin{document}之前&#xff09;&#x…

《C语言深度解剖》:(5)C语言操作符一网打尽

&#x1f921;博客主页&#xff1a;醉竺 &#x1f970;本文专栏&#xff1a;《C语言深度解剖》 &#x1f63b;欢迎关注&#xff1a;感谢大家的点赞评论关注&#xff0c;祝您学有所成&#xff01; ✨✨&#x1f49c;&#x1f49b;想要学习更多数据结构与算法点击专栏链接查看&am…

一些docker安装配置以及常见命令

​常用命令 docker 命令 //进去容器内部&#xff0c;找到需要拷贝的文件及目录 docker exec -it 2c2600fb60f8 /bin/bash ​ //将container id为4db8edd86202的容器内elasticsearch.yml文件拷贝到宿主机指定目录下&#xff1a; docker cp 4db8edd86202:/usr/share/elasticsea…

pytest系列——allure之在测试用例添加标题(@allure.title())

前言 通过使用装饰器allure.title可以为测试用例自定义一个更具有阅读性的易读的标题。 allure.title的三种使用方式&#xff1a; 直接使用allure.title为测试用例自定义标题&#xff1b;allure.title支持通过占位符的方式传递参数&#xff0c;可以实现测试用例标题参数化&a…

温度对射频电路性能的影响

对于射频电路,通常会有使用温度范围的要求,即在特定的温度范围内其性能变化不超出指标要求的值。对于工业级产品,一般要求使用温度范围为-40℃~+70℃,而军品要求使用温度范围为-55℃~+85℃。有一些其他特殊使用场景的产品会有不同的要求。 不同的温度对电路性能的影响,…
最新文章