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

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

相关文章

Java 接口定义变量的示例代码

《Java接口定义变量的示例代码》文章介绍了Java接口中的变量和方法,接口中的变量必须是publicstaticfinal的,用于定义常量,而方法默认是publicabstract的,必须由实现类... 在 Java 中,接口是一种抽象类型,用于定义类必须实现的方法。接口可以包含常量和方法,但不能包含实例

使用Redis实现会话管理的示例代码

《使用Redis实现会话管理的示例代码》文章介绍了如何使用Redis实现会话管理,包括会话的创建、读取、更新和删除操作,通过设置会话超时时间并重置,可以确保会话在用户持续活动期间不会过期,此外,展示了... 目录1. 会话管理的基本概念2. 使用Redis实现会话管理2.1 引入依赖2.2 会话管理基本操作

MySQL日志UndoLog的作用

《MySQL日志UndoLog的作用》UndoLog是InnoDB用于事务回滚和MVCC的重要机制,本文主要介绍了MySQL日志UndoLog的作用,文中介绍的非常详细,对大家的学习或者工作具有一定的... 目录一、Undo Log 的作用二、Undo Log 的分类三、Undo Log 的存储四、Undo

mybatis-plus分表实现案例(附示例代码)

《mybatis-plus分表实现案例(附示例代码)》MyBatis-Plus是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生,:本文主要介绍my... 目录文档说明数据库水平分表思路1. 为什么要水平分表2. 核心设计要点3.基于数据库水平分表注意事项示例

Nginx服务器部署详细代码实例

《Nginx服务器部署详细代码实例》Nginx是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务,:本文主要介绍Nginx服务器部署的相关资料,文中通过代码... 目录Nginx 服务器SSL/TLS 配置动态脚本反向代理总结Nginx 服务器Nginx是一个‌高性

Python使用Matplotlib和Seaborn绘制常用图表的技巧

《Python使用Matplotlib和Seaborn绘制常用图表的技巧》Python作为数据科学领域的明星语言,拥有强大且丰富的可视化库,其中最著名的莫过于Matplotlib和Seaborn,本篇... 目录1. 引言:数据可视化的力量2. 前置知识与环境准备2.1. 必备知识2.2. 安装所需库2.3

HTML5的input标签的`type`属性值详解和代码示例

《HTML5的input标签的`type`属性值详解和代码示例》HTML5的`input`标签提供了多种`type`属性值,用于创建不同类型的输入控件,满足用户输入的多样化需求,从文本输入、密码输入、... 目录一、引言二、文本类输入类型2.1 text2.2 password2.3 textarea(严格

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

JAVA项目swing转javafx语法规则以及示例代码

《JAVA项目swing转javafx语法规则以及示例代码》:本文主要介绍JAVA项目swing转javafx语法规则以及示例代码的相关资料,文中详细讲解了主类继承、窗口创建、布局管理、控件替换、... 目录最常用的“一行换一行”速查表(直接全局替换)实际转换示例(JFramejs → JavaFX)迁移建

Go异常处理、泛型和文件操作实例代码

《Go异常处理、泛型和文件操作实例代码》Go语言的异常处理机制与传统的面向对象语言(如Java、C#)所使用的try-catch结构有所不同,它采用了自己独特的设计理念和方法,:本文主要介绍Go异... 目录一:异常处理常见的异常处理向上抛中断程序恢复程序二:泛型泛型函数泛型结构体泛型切片泛型 map三:文