掘金账号:橘松Java
微信公众号:橘松Java技术窝
文章首发掘金平台,后续同步更新公众号,关注后回复 "加群" 可加入互联网技术交流&内推群,和一群大厂大佬讨论面试问题。回复 "666" 可获取一线互联网具备所有资料包(包括开发软件、开发规范、经典电子pdf、以及一些精品学习课程)。

前言

随着工程项目的日积月累,系统的维护成本越来越高成为了我们要面临的问题,当你发现改造一个很小的需求需要改动很多的地方或者不知道改哪里?怎么改? 全是坑?这时候可能就需要代码重构了。
less coding,more thinking(少编码,多思考) ; think more,code less(多思考,少编码)。我这肯定不是在套娃哈哈哈~

套娃.gif

下面总结一些平时编码细节规则,给广大Java程序员一些编码建议,帮助大家编写出更优雅、更高效、更高质的代码,利用好在今后工作中使用。

1. 通用工具函数

案例1:字符串比较

不建议的写法
thisOrange != null && thisOrange.equals(orange);
建议写法
Objects.equals(orange,thisOrange);

案例2:判断列表为空

不建议的写法
!(list == null || list.isEmpty());
建议写法
import org.apache.commons.collections4.CollectUtils;
CollectionUtils.isNotEmpty(list);
主要好处
  • 函数式编程,一方面代码减少,逻辑也更清晰。
  • 通用工具函数,逻辑考虑周全,出问题概率低。

2. 一个方法内代码块级别保持一致

案例1:烹饪方法

public void cooking() {
   //洗菜
   brushFood();

   //翻炒
   //假设翻炒方法几百行代码

   //洗锅
   brushGuo()
}

很明显,这个cooking()这段代码块中,brushFood()brushGuo() 两个方法和其他内容不在同一级别上,显得很突兀。而我们讲究一个方法一眼看过去能知道他的主流程是怎样的。

建议写法
public void cooking() {
   //洗菜
   brushFood();

   //翻炒
   cook();

   //洗锅
   brushGuo()
}

//翻炒
private void cook(){
   // 翻炒方法几百行代码
}
主要好处
  • 函数调用表明用途,函数实现表达逻辑,层次分明增强可读性。
  • 能梳理出方法的主流程,且也满足设计模式原则的srp原则,避免代码头重脚轻。

3. 工具类、枚举定义

案例1:定义工具类

通常,我们会如下定义工具类

public class XxxUtils{
    public final static int COUNT_VALUE = 123;
    public static int sum(int a , int b) {
        return a + b ;
    }
}
存在问题
  • 修饰符顺序不规范,Java语言规范建议使用static final 而不是 final static 。至于为什么,这算是一种规范,也没有具体的对错,规范就是大家的认知一样
  • 工具类将会被继承覆盖,假设某个开源工具类名、方法名和你写的一致,那么将会覆盖,最好的办法就是对工具类添加final关键字
  • 工具类将会会实例化,对于工具类来说没必要进行实例化,所以需要添加私有构造方法,并在方法中抛出UnsupportOperationException异常
建议写法
public final class XxxUtils{
    public static final int COUNT_VALUE = 123;

    private XxxUtils(){
        throw new UnsupportOperationException();
    }

    public static int sum(int a , int b) {
        return a + b ;
    }
}

案例2:定义枚举类

通常,我们会如下定义枚举类

  public enum XxxEnum{
      ONE(1,"第一"),
      TWO(2,"第二");

      private Integer value
      private String desc;

      private XxxEnum(Integer value,String desc) {
          this.value = value;
          this.desc = desc;
      }

      // getter/setter
  }
存在问题
  • 构造方法前多余的修饰符private可缺省
  • 用包装类型Integer保存枚举取值,建议使用基本类型int
  • 为了避免枚举值被修改,建议对字段添加final修饰符。
    建议写法
  public enum XxxEnum {
      ONE(1,"第一"),
      TWO(2,"第二");

      private final int value
      private final String desc;

      XxxEnum(Integer value,String desc) {
          this.value = value;
          this.desc = desc;
      }

      // getter/setter
  }

4. 定义集合常量

最简单的方法,就是直接定义一个普通的集合常量

public final class CollectionTest{
    public static final List<Integer> CONST_VALUE_LIST = Arrays.asList(1,2,3);
    public static final List<Integer> CONST_VALUE_SET = new HashSet<>(Arrays.asList(1,2,3))
}
存在问题
  • 对于普通的集合对象,像ArrayList,HashSet等都是可变集合对象,就算定义为静态常量,也可以通过操作方法进行修改,另外其中Arrays.asList方法生成内部ArrayList不能执行add/clear等方法。
    建议写法
public final class CollectionTest{
    public static final List<Integer> CONST_VALUE_LIST = Collections.unmodifiableList(Arrays.asList(1,2,3));
    public static final List<Integer> CONST_VALUE_SET = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(1,2,3)));
}

5. 其他小tips

  • 利用条件表达式函数减少代码层级
  • 利用continue提前结束循环
  • 利用return提前返回函数
  • 减少不必要的null判断,比如mybatis查询返回列表不会返回null
  • 当传入成组参数时,应封装为参数类或者Context上下文
  • 通过接口参数化或者函数式接口封装相同的逻辑调用

想了解更多的编码细节和优化,请持续关注代码设计优化专栏

图片1.png

最后

  • 文章均原创,原创不易,感谢掘金平台,觉得有收获,帮忙三连哈,感谢
  • 微信搜索公众号:橘松Java技术窝,交个朋友,进互联网技术交流群
  • 文章涉及的所有代码、时序图、架构图均共享,可通过公众号加群免费索要
  • 文章若有错误,欢迎评论留言指出,也欢迎转载,麻烦标注下出处就好