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

2024-04-18 04:04

本文主要是介绍编程技巧:小技巧,大作用,一招提高代码的可读性,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

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 contentString 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.chinasem.cn/article/913713

相关文章

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

购买磨轮平衡机时应该注意什么问题和技巧

在购买磨轮平衡机时,您应该注意以下几个关键点: 平衡精度 平衡精度是衡量平衡机性能的核心指标,直接影响到不平衡量的检测与校准的准确性,从而决定磨轮的振动和噪声水平。高精度的平衡机能显著减少振动和噪声,提高磨削加工的精度。 转速范围 宽广的转速范围意味着平衡机能够处理更多种类的磨轮,适应不同的工作条件和规格要求。 振动监测能力 振动监测能力是评估平衡机性能的重要因素。通过传感器实时监

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

滚雪球学Java(87):Java事务处理:JDBC的ACID属性与实战技巧!真有两下子!

咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE啦,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~ 🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!! 环境说明:Windows 10

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d