代码是团队沟通方式
让营地比来时更干净
合适的命名
短小的方法
减少 if/else 嵌套
抽离 try/catch
封装多个参数
第三方库
Lombok
Apache Commons 系列
很早就阅读过《代码整洁之道》(英文版 Clean Code), 当时博主是个青涩的菜鸟, 正在为团队创造着混乱的代码. 多年的工作中, 屡次被别人的代码坑的苦不堪言, 回想起当年我留下的代码, 肯定也坑害了后来的同僚. 当阅读 JDK 源码或者其他优秀开源工程时, 叹服作者代码构建之精良, 他们都有共同的特点: 精确的变量名, 恰到好处的设计模式, 详细而不赘述的注释等等. 如今重读本书, 总结一下内容并加上自己的一些见解与大家分享.
代码是团队沟通方式
工作的沟通, 不只是电子邮件或者面对面语言交流, 代码也是沟通方式之一. 用代码实现需求, 只是万里长征走完了第一步, 必须让代码表达自己的设计思想. 试想一下, 你负责的功能被另外一个同事接手, 如果你的代码结构清晰, 注释合理, 他就不用频繁的询问代码疑点, 不用打断你的工作. 编写代码的时候, 应该考虑到别人的阅读感受, 减少阅读障碍, 为整个团队创造代码, 而不是你自己.
让营地比来时更干净
这是美国童子军规的谚语, 美国童子军相当于半军事化管理的青少年夏令营. 夏令营结束后孩子们离开营地, 要打扫卫生保持整洁, 让营地比来时更干净. 在软件开发过程中, 可以理解为不要破坏规则, 不要引入混乱. 如果团队已经制定了代码规范, 比如类名必须有子系统前缀比如 BiOrderService(Bi 指 BI 业务部门), 就继续遵循下去; 再比如, 团队已经提供了公共库比如 MD5 的加密, 那就不要再次引入新的 MD5 库. 很多新手程序员接活儿后, 看到不喜欢的规范就另起炉灶, 需要某些工具类也不询问老司机公共库有没有, 直接引入自己熟悉的库, 造成兼容性或者其他问题.
合适的命名
合适的命名是头等大事, 正如给新生儿起个好名字那样重要. 不合适的命名通常是词不达意, 误导观众, 过度缩写等, 由于英文并非我们的母语, 找个合适的单词命名似乎真的很难. 我建议是先把业务弄清楚, 组织会议定下常用业务领域的单词, 禁止组员各自发明. 比如代码里使用 canteen 表示饭堂, 那就不要再发明 DinnerHall, 既啰嗦又误导同僚.
看看反例:
- // 手机号
- String phone = "13421800409";
- // 获取地址
- private String getDiZhi();
- // 修改密码
- private void modifyPassword(String password1 ,String password2)
看看正例:
- // 手机号 mobileNo 比 phone 更精确
- String mobileNo= "13421800409";
- // 避免英文拼音混杂
- private String getAddress();
- // 参数的命名要区分意义
- private void modifyPassword(String oldPassowrd,String newPassword)
短小的方法
方法有多短小才合适没有定论, 但是长达 500 行的一个方法, 绝对让阅读者起杀人之心. 过长的方法, 让阅读者不知道从何看起, 看了前面忘记后面. 将复杂的方法, 拆分成逻辑相对简单的短方法.
看看反例:
- // 获取个人信息
- Private UserDTO getUserDTO(Integer userId)
- {
- // 获取基本信息
... 此处写了 10 行
// 获取最近的一次订单信息
... 此处写了 30 行
// 获取钱包余额, 可用优惠券张数等
... 此处写了 30 行
- return userDTO;
- }
看看正例:
- // 获取个人信息
- Private UserDTO getUserDTO(Integer userId)
- {
- // 获取基本信息
- UserDTO userDTO= getUserBasicInfo(userId);
- // 获取最近的一次订单信息
- userDTO.setUserLastOrder(getUserLastOrder(userId));
- // 获取钱包, 可用优惠券张数等
- userDTO.setUserAccount(getUserAccount(userId));
- return userDTO;
- }
- Private UserDTO getUserBasicInfo(userId);
- Private UserLastOrder getUserLastOrder(userId);
- Private UserAccount getUserAccount(userId);
减少 if/else 嵌套
为什么要减少嵌套, 难道嵌套看上去不时尚吗? 我曾经看到某位同事的一段代码嵌套达到 9 层, 他自己再去维护的时候都看晕了. 代码过度嵌套的结果是只有原作者才能读懂, 接盘侠一脸茫然.
看看反例:
- // 修改用户密码, 这个例子只有 3 层嵌套, 很温柔了
- public boolean modifyPassword(Integer userId, String oldPassword, String newPassword) {
- if (userId != null && StringUtils.isNotBlank(newPassword) && SpringUtils.isNotBlank(oldPassword)) {
- User user = getUserById(userId);
- if(user != null) {
- if(user.getPassword().equals(oldPassword) {
- return updatePassword(userId, newPassword)
- }
- }
- }
- }
看看正例:
- // 修改用户密码
- Public Boolean modifyPassword(Integer userId, String oldPassword, String newPassword) {
- if (userId == null || StringUtils.isBlank(newPassword) || StringUtils.isBlank(oldPassword)) {
- return false;
- }
- User user = getUserById(userId);
- if(user == null) {
- return false;
- }
- if(!user.getPassword().equals(oldPassword) {
- return false;
- }
- return updatePassword(userId, newPassword);
- }
正例采用卫语句减少了嵌套, 但是并非所有场景都适合这样改写. 如果不适合, 可以将关联性高的逻辑抽取成一个独立的方法减少嵌套.
抽离 try/catch
大家有没有见过一个超长的方法, 从头到尾被一个 try/catch 照顾着? 博主经历过的项目中, 这种不负责的写法比比皆是. 并非每行代码都会抛出错误, 只要将会抛出错误的业务放在一个独立的方法即可.
看看反例:
- // 获取个人信息
- Private UserDTO getUserDTO(Integer userId)
- {
- try {
- // 获取基本信息
... 此处写了 10 行
// 获取最近的一次订单信息.
... 此处写了 20 行
// 获取钱包, 可用优惠券张数等
... 此处写了 20 行
- }catch (Exception e) {
- logger.error(e);
- return null;
- }
- }
- return userDTO;
- }
看看正例:
- // 获取个人信息
- Private UserDTO getUserDTO(Integer userId)
- {
- // 获取基本信息
- UserDTO userDTO= getUserBasicInfo(userId);
- // 获取最近的一次订单信息
- userDTO.setUserLastOrder(getUserLastOrder(userId));
- // 获取钱包, 可用优惠券张数等
- userDTO.setUserAccount(getUserAccount(userId));
- return userDTO;
- }
- Private UserDTO getUserBasicInfo(userId);
- Private UserLastOrder getUserLastOrder(userId);
Private UserAccount getUserAccount(userId){
- try{
- // TODO
- } catch( Exception e) {
- //TODO
- }
- }
封装多个参数
如果方法参数将超过 3 个, 建议放在类中包装起来, 否则再增加参数时, 由于语义的强耦合会导致调用方语法错误. 在后台管理中的分页查询接口, 常常会有很多查询参数, 而且有可能增加, 封装起来是最好的.
看看反例:
- // 分页查询订单 6 个参数
- Public Page<Order> queryOrderByPage(Integer current,Integer size,String productName,Integer userId,Date startTime,Date endTime,Bigdecimal minAmount ,Bigdecimal maxAmount) {
- }
看看正例:
- @Getter
- @Setter
- Public class OrderQueryDTO extends PageDTO {
- private String productName;
- private Integer userId;
- private Date startTime;
- private Date endTime;
- private Bigdecimal minAmount ;
- private Bigdecimal maxAmount;
- }
- // 分页查询订单 6 个参数
- Public Page<Order> queryOrderByPage(OrderQueryDTO orderQueryDTO) {
- }
第三方库
Lombok
Lombok 组件通过注解的方式, 在编译时自动为属性生成构造器, getter/setter,equals,hashcode,toString 方法
举例如下:
@Setter 注解在类或字段, 注解在类时为所有字段生成 setter 方法, 注解在字段上时只为该字段生成 setter 方法.
@Getter 使用方法同上, 区别在于生成的是 getter 方法.
@ToString 注解在类, 添加 toString 方法.
@EqualsAndHashCode 注解在类, 生成 hashCode 和 equals 方法.
@NoArgsConstructor 注解在类, 生成无参的构造方法.
@RequiredArgsConstructor 注解在类, 为类中需要特殊处理的字段生成构造方法, 比如 final 和被 @NonNull 注解的字段.
@AllArgsConstructor 注解在类, 生成包含类中所有字段的构造方法.
@Data 注解在类, 生成 setter/getter,equals,canEqual,hashCode,toString 方法, 如为 final 属性, 则不会为该属性生成 setter 方法.
常规写法:
- Public class Order {
- private Integer userId;
- public Integer getUserId() {
- return userId;
- }
- public void setUserId(Integer userId) {
- return this.userId = userId;
- }
- }
采用 Lombok:
- @Getter
- @Setter
- Public class Order {
- private Integer userId;
- }
Apache Commons 系列
Apache Commons 系列组件给我们提供了关于字符串, 集合, IO 操作等工具方法. 这些组件是个大宝库, 提供了不少轮子.
组件 | 介绍 |
---|---|
beanUtils | JavaBean 进行各种操作,克隆对象、属性等等 |
codec | 处理常用的编码方法的工具类包,例如 DES、SHA1、MD5、Base64 等. |
collections | java 集合框架操作 |
configuration | java 应用程序的配置管理类库 |
io | io 工具的封装 |
lang | Java 基本对象方法的工具类包 如 StringUtils、ArrayUtils 等等. |
logging | 提供的日志接口 |
net | 提供了客户端和服务器端的数据验证框架 |
看看例子:
例 1: 判断集合是否为空:
- CollectionUtils.isEmpty(null): true
- CollectionUtils.isEmpty(new ArrayList()): true
- CollectionUtils.isEmpty({
- a,b
- }): false
例 2: 判断集合是否不为空:
- CollectionUtils.isNotEmpty(null): false
- CollectionUtils.isNotEmpty(new ArrayList()): false
- CollectionUtils.isNotEmpty({
- a,b
- }): true
例 3:2 个集合间的操作:
集合 a: {1,2,3,3,4,5}
集合 b: {3,4,4,5,6,7}
- CollectionUtils.union(a, b)(并集): {
- 1,2,3,3,4,4,5,6,7
- }
- CollectionUtils.intersection(a, b)(交集): {
- 3,4,5
- }
- CollectionUtils.disjunction(a, b)(交集的补集): {
- 1,2,3,4,6,7
- }
- CollectionUtils.disjunction(b, a)(交集的补集): {
- 1,2,3,4,6,7
- }
- CollectionUtils.subtract(a, b)(A 与 B 的差): {
- 1,2,3
- }
- CollectionUtils.subtract(b, a)(B 与 A 的差): {
- 4,6,7
- }
来源: https://www.cnblogs.com/xiaoyangjia/p/11245235.html