目 录CONTENT

文章目录

代码规范

小王同学
2023-12-29 / 0 评论 / 0 点赞 / 63 阅读 / 0 字

代码规范

引言

在软件开发中,代码规范是一组约定俗成的准则,它们指导开发人员编写结构清晰、易读、易维护的代码。

试想一下,一个几十万行代码的项目,存在几种不同的代码规范,阅读起来是什么感受?连代码缩进使用空格还是 Tab 都能引发不少开发者的争论,可以说统一代码规范是非常重要的事情。

统一代码规范除了刚才所说的两点外,还有其他好处:

  • 规范的代码可以促进团队合作
  • 规范的代码可以降低维护成本
  • 规范的代码有助于 code review(代码审查)
  • 养成代码规范的习惯,有助于程序员自身的成长

当团队的成员都严格按照代码规范来写代码时,可以保证每个人的代码看起来都像是一个人写的,看别人的代码就像是在看自己的代码(代码一致性),阅读起来更加顺畅。更重要的是我们能够认识到规范的重要性,并坚持规范的开发习惯。

命名风格

1.严禁使用中文或者中文拼音进行重命名(单词最好控制在三个以内)。

说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,纯拼音命名方式更要避免采用。

说明:beijing/ shanghai 等国际通用的名称,可视同英文。

正例 ✅ :

int studentCount;
void calculateAverageScore() {}
String username;

反例 ❌ :

          xueGuanGuanLi[学管管理] / getChengJi() [成绩]

星级评定:⭐️⭐️⭐️

2.方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵 从驼峰形式。

正例 ✅ :

   localValue / getHttpMessage() / inputUserId

反例 ❌ :

Local\_Value(不符合 lowerCamelCase 风格)

get\_http\_message()(使用下划线而不是驼峰形式)

InputUserID(首字母大写,不符合 lowerCamelCase 风格)

星级评定:⭐️⭐️⭐️

3.杜绝完全不规范的缩写,避免望文不知义,如果命名能够很清晰的表达出该方法或者该类名的含义,这也可以减少写注释。

反例 ❌ :AbstractClass“缩写”命名成 AbsClass;condition“缩写”命名成 condi,此类随意缩写严重 降低了代码的可阅读性。

星级评定:⭐️⭐️⭐️

4.为了达到代码自解释的目标,任何自定义编程元素在命名时,使用尽量完整的单词 组合来表达其意。

反例 ❌ :

public List<int[]> getThem(){
        List<int[]> list1 = new ArrayList<>();
        for (int[] x : theList){
            if (x[0] == 4){
                list1.add(x);
            }
        }
        return list1;
    }

theList是什么类型的东西?

theList下标条目的意义是什么?

值4的意义是什么?

我怎么使用返回的列表?

正例 ✅ :

public List<int[]> getFlaggedCells(){
        List<int[]> flaggedCells = new ArrayList<>();
        for (int[] cell : gameBoard){
            if (cell[STATUS_VALUE] == FLAGGED){
                flaggedCells.add(cell);
            }
        }
        return flaggedCells;
    }

比方说我们在开发一种扫雷的游戏,我们发现,盘面是名为gameBoard的二维数组

盘面上每个单元格都用一个简单数组表示

而该状态值为4表示"已标记"。只要改为有意义的名称,代码就会变得更加清晰

星级评定:⭐️⭐️⭐️

4.常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。

正例 ✅ :MAX_STOCK_COUNT / CACHE_EXPIRED_TIME

反例 ❌ :MAX_COUNT / EXPIRED_TIME

星级评定:⭐️⭐️⭐️

6.如果模块、接口、类、方法使用了设计模式,在命名时需体现出具体模式。

说明:将设计模式体现在名字中,有利于阅读者快速理解架构设计理念。

正例 ✅ :

    public class OrderFactory;
    public class LoginProxy;
    public class ResourceObserver;

星级评定:⭐️⭐️⭐️

常量定义

  1. 不允许任何魔法值(即未经预先定义的常量)直接出现在代码中。

反例:String key = “Id#taobao_” + tradeId; cache.put(key, value); // 缓存 get 时,由于在代码复制时,漏掉下划线,导致缓存击穿而出现问题

星级评定:⭐️⭐️⭐️

  1. 不要使用一个常量类维护所有常量,要按常量功能进行归类,分开维护。

说明:大而全的常量类,杂乱无章,使用查找功能才能定位到修改的常量,不利于理解和维护。 正例:缓存相关常量放在类 CacheConsts 下;系统配置相关常量放在类 ConfigConsts 下。

星级评定:⭐️⭐️⭐️

代码格式

1.函数设计要职责单一

举个例子:我们来校验下我们的额一些用户属性,当然这个校验就省略成判断是否为空了

正例 ✅ :

public void validateName(String name) {
        if (name == null || "".equals(name.trim())) {
            throw new IllegalArgumentException("姓名不能为空");
        }
    }
    public void validatePhone(String phone) {
        if (phone == null || "".equals(phone.trim())) {
            throw new IllegalArgumentException("手机号不能为空");
        }
    }
    public void validateEmail(String email) {
        if (email == null || "".equals(email.trim())) {
            throw new IllegalArgumentException("邮箱不能为空");
        }
    }

反例 ❌ :

public void validateUser(String userName, String phone, String email, String password) {
        if (userName == null || "".equals(userName.trim())) {
            throw new IllegalArgumentException("用户名不能为空");
        }
        if (password == null || "".equals(password.trim())) {
            throw new IllegalArgumentException("密码不能为空");
        }
        if (phone == null || "".equals(phone.trim())) {
            throw new IllegalArgumentException("手机号不能为空");
        }
        if (email == null || "".equals(email.trim())) {
            throw new IllegalArgumentException("邮箱不能为空");
        }
    }

星级评定:⭐️⭐️⭐️

2.单个方法的总行数不超过 80 行(大约两个显示屏的高度)。

说明:

函数的代码太多和太少,都是不太好的

行数太多:

一个方法上千行,一个函数几百行,逻辑过于繁杂,阅读代码的时候,很容易就会看了后面忘了前面

行数太少:

在代码总量相同的情况下,被分割成的函数就会相应增多,调用关系就会变得更复杂,阅读某个代码逻辑的时候,需要频繁地在n多方法或者n多函数之间跳来跳去,阅读体验也不好。

星级评定:⭐️⭐️⭐️

3.避免函数或方法参数过多

说明:函数包含3、4个参数的时候还是能接受的,大于等于5个的时候,我们就觉得参数有点过多了,会影响到代码的可读性,使用起来也不方便。

public  void updateBookshelf(String userId,String deviceId,String platform,String version,String bookshelf){
        ```
    }
public void updateBookshelf(Object object){
        ```
    }

星级评定:⭐️⭐️⭐️

4.单行字符数限制不超过 120 个,超出需要换行,换行时遵循如下原则:

1)第二行相对第一行缩进 4 个空格,从第三行开始,不再继续缩进,参考示例。

2)运算符与下文一起换行。

3)方法调用的点符号与下文一起换行。

4)方法调用中的多个参数需要换行时,在逗号后进行。

5)在括号前不要换行,见反例。

反例 ❌ :

public void addFruits(){
        List<String> fruits = new ArrayList<>();
        fruits.add("Apple").add("Orange").add("Banana").add("Pear").add("Mango").add("Grape");
    }

星级评定:⭐️⭐️⭐️

5.Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。

正例 ✅ :“test”.equals(object);

反例 ❌ :object.equals(“test”);

星级评定:⭐️⭐️⭐️

6.防止 NPE,是程序员的基本修养,注意 NPE 产生的场景:

1) 返回类型为基本数据类型,return 包装数据类型的对象时,自动拆箱有可能产生 NPE。

反例 ❌ :public int f() { return Integer 对象}, 如果为 null,自动解箱抛 NPE。

2) 数据库的查询结果可能为 null。

3) 集合里的元素即使 isNotEmpty,取出的数据元素也可能为 null。

4) 远程调用返回对象时,一律要求进行空指针判断,防止 NPE。

5) 对于 Session 中获取的数据,建议进行 NPE 检查,避免空指针。

6) 级联调用 obj.getA().getB().getC();一连串调用,易产生 NPE。

星级评定:⭐️⭐️⭐️

推荐代码质量管理工具:SonarLint

SonarLint是一款集成开发环境(IDE)插件,用于帮助开发人员在编写代码时进行静态代码分析和质量检查。

它能够在编码过程中即时检测和标记出潜在的代码缺陷、安全漏洞和代码异味(code smells),并提供相应的修复建议。

SonarLint提供了对多种编程语言的支持,包括但不限于C、C++、Java、JavaScript、TypeScript、Python、C#、Kotlin、Ruby、HTML和PHP。

它与多个常见的IDE集成,如IntelliJ IDEA、CLion、WebStorm、PHPStorm、PyCharm、Rider、Android Studio和RubyMine。

代码检查结果如下,可以在服务器中定制代码检查规则,将常用的规则优先级提高,一些不必要的规则优先级降低。

当然还有很多这种代码质量检测插件,可以选择适合自己的插件进行安装

代码注释:

说明:注释应该着重描述“做了什么”而不是“怎么做”。

好的代码是不需要写注释的。其实这种说法有点片面

我们平时强调的代码规范、项目规范、重构等等,就是为了减少沟通,提高开发效率

写注释的目的也是为了让代码更加容易理解,出问题了,也能快速定位问题,从而解决问题。

所以不是不写注释,而是不写垃圾注释。

正例 ✅ :

/**
     * 将map对象转为url参数
     * @param obj
     * @return
     */
    public static String objToUrlParams(Object obj) {}

反例 ❌ :

/**
     * 将包含键值对的对象转换成url参数
     * 对于每一个键值对,如果值为null或者空字符串,则不添加到url参数中
     * 将键值对中的键和值按照URL参数的格式拼接起来,并以""&""符号分隔
     * 最终返回的字符串形式为:key1=value1&key2=value2&key3=value3
     * @param obj
     * @return
     */
    public static String objToUrlParams(Object obj) {}

多使用设计模式

使用常用的设计模式进行开发,可以重用代码、让代码更容易被他人理解、保证代码可靠性。

以下是各个模式的关键点:

单例模式:某个类只能有一个实例,提供一个全局的访问点。

简单工厂:一个工厂类根据传入的参量决定创建出那一种产品类的实例。

工厂方法:定义一个创建对象的接口,让子类决定实例化那个类。

抽象工厂:创建相关或依赖对象的家族,而无需明确指定具体类。

建造者模式:封装一个复杂对象的构建过程,并可以按步骤构造。

原型模式:通过复制现有的实例来创建新的实例。

适配器模式:将一个类的方法接口转换成客户希望的另外一个接口。

组合模式:将对象组合成树形结构以表示“”部分-整体“”的层次结构。

装饰模式:动态的给对象添加新的功能。

代理模式:为其他对象提供一个代理以便控制这个对象的访问。

亨元(蝇量)模式:通过共享技术来有效的支持大量细粒度的对象。

外观模式:对外提供一个统一的方法,来访问子系统中的一群接口。

桥接模式:将抽象部分和它的实现部分分离,使它们都可以独立的变化。

模板模式:定义一个算法结构,而将一些步骤延迟到子类实现。

解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器。

策略模式:定义一系列算法,把他们封装起来,并且使它们可以相互替换。

状态模式:允许一个对象在其对象内部状态改变时改变它的行为。

观察者模式:对象间的一对多的依赖关系。

备忘录模式:在不破坏封装的前提下,保持对象的内部状态。

中介者模式:用一个中介对象来封装一系列的对象交互。

命令模式:将命令请求封装为一个对象,使得可以用不同的请求来进行参数化。

访问者模式:在不改变数据结构的前提下,增加作用于一组对象元素的新功能。

责任链模式:将请求的发送者和接收者解耦,使的多个对象都有处理这个请求的机会。

迭代器模式:一种遍历访问聚合对象中各个元素的方法,不暴露该对象的内部结构。

Code Review 代码审查

代码审查是指让其他人来审查自己代码的一种行为。

审查有多种方式:例如结对编程(一个人写,一个人看)或者统一某个时间点大家互相做审查(单人或多人)。

代码审查的目的是为了检查代码是否符合代码规范以及是否有错误,另外也能让评审人了解被审人所写的功能。

经常互相审查,能让大家都能更清晰地了解整个项目的功能。

当然,代码审查也是有缺点的:一是代码审查非常耗时,二是有可能引发团队成员争吵。

参考:

阿里巴巴 Java 开发手册

代码整洁之道

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区