写点什么

Java 开发规范(一)

作者:DC.夜猫
  • 2022 年 5 月 26 日
  • 本文字数:6063 字

    阅读完需:约 20 分钟

Java开发规范(一)

1、【强制】对于方法中采用逻辑判断后返回 boolean 类型值的情况

强制: 不要使用 if-else 结构中直接返回 Boolean 值。


反例:


public Boolean isEmpty(String chars) {    if ("".equals(chars)) {        return true;    } else {        return false;    }}
复制代码


正例:


public boolean isEmpty(String chars) {    return "".equals(chars);}
复制代码

2、用静态工厂方法代替构造器;

​ 根据《Effective Java(第 III 版)》第二章第一条:对于类而言,为了让客户端获取它自身的一个实例,最传统的方法就是提供一个公有的构造器。还有一种方法,类可以提供一个公有的静态工厂方法( static factory method ),它只是一个返回类的实例的静态方法。


示例:


public static Boolean valueOf(boolean b) {  return b ? Boolean.TRUE : Boolean.FALSE;}
复制代码

3、【强制】不应通过派生类型访问“静态”基类成员

​ 基类的静态成员不应使用派生类型的名称进行访问。可能会令人产生两个不同的静态成员存在的假象困惑。


正例:


public void export(HttpServletResponse response) throws IOException {    List<Object> list = new ArrayList<>();    EasyExcelFactory.write(response.getOutputStream(), ExportWorkOrder.class).autoCloseStream(Boolean.FALSE)        .sheet("sheet1").doWrite(list);}
复制代码


反例:


public void export(HttpServletResponse response) throws IOException {    List<Object> list = new ArrayList<>();    EasyExcel.write(response.getOutputStream(), ExportWorkOrder.class).autoCloseStream(Boolean.FALSE)        .sheet("sheet1").doWrite(list);}
复制代码

4、【强制】指定编码使用 JDK 提供的字符编码常量类 StandardCharsets

示例:


public String getFileName() throws UnsupportedEncodingException {    return URLEncoder.encode("XXXXXX - " + LocalDate.now().toString(), StandardCharsets.UTF_8.name());}
复制代码

5、【强制】代码中禁止使用 Exception#printStackTrace();打印异常堆栈信息

反例:


public String getFileName() {    try {        return URLEncoder.encode("XXXXXX - " + LocalDate.now().toString(),                                 StandardCharsets.UTF_8.name());    } catch (UnsupportedEncodingException e) {        e.printStackTrace();        return null;    }}
复制代码

6、工具类(实用类)不应具备公开构造函数

正例:


public class AesUtil {    // 防止实例化    private AesUtil() {    }        public String getPrivateKey() {      // coding    }}
复制代码

7、try-with-resources 结构优先于 try-finally

反例:


// try-finally - No longer the best way to close resources!public static String firstlineOfFile (String path) throws IOException {    BufferedReader br = new BufferedReader(new FileReader(path));    try {        return br.readLine();    } finally {        br.close();    }}
复制代码


正例:


// try-with -resourcespublic static String firstlineOfFile (String path) throws IOException {    try(BufferedReader br = new BufferedReader(new FileReader(path))) {        return br.readLine();    }}
复制代码

8、写在类上面的 Javadoc

写在类上的文档标注一般分为三段:


  • 第一段:概要描述,通常用一句或者一段话简要描述该类的作用,以英文句号作为结束

  • 第二段:详细描述,通常用一段或者多段话来详细描述该类的作用,一般每段话都以英文句号作为结束

  • 第三段:文档标注,用于标注作者、创建时间、参阅类等信息


在注释中出现以 @开头东东被称之为 Javadoc 文档标记,是 JDK 定义好的,如 @author、@version、@since、@see、@link、@code、@param、@return、@exception、@throws 等。

1)@link {@link 包名.类名 #方法名(参数类型)} 用于快速链接到相关代码
2)@cod {@code text} 将文本标记为 code
3)@param 一般类中支持泛型时会通过 @param 来解释泛型的类型
4)@author 详细描述后面一般使用 @author 来标记作者,如果一个文件有多个作者来维护就标记多个 @author;

​ @author 后面可以跟作者姓名(也可以附带邮箱地址)、组织名称(也可以附带组织官网地址)

5)@see 一般用于标记该类相关联的类,@see 即可以用在类上,也可以用在方法上。
6)@since 从以下版本开始,一般用于标记文件创建时项目当时对应的版本

​ 一般后面跟版本号,也可以跟是一个时间,表示文件当前创建的时间

7)@version 用于标记当前版本,默认为 1.0

示例:


/** * The class {@code String} includes methods for examining * individual characters of the sequence, for comparing strings, for * searching strings, for extracting substrings, and for creating a * copy of a string with all characters translated to uppercase or to * lowercase. Case mapping is based on the Unicode Standard version * specified by the {@link java.lang.Character Character} class. * * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor * or method in this class will cause a {@link NullPointerException} to be * thrown. * * <p>A {@code String} represents a string in the UTF-16 format * in which <em>supplementary characters</em> are represented by <em>surrogate * pairs</em> (see the section <a href="Character.html#unicode">Unicode * Character Representations</a> in the {@code Character} class for * more information). * Index values refer to {@code char} code units, so a supplementary * character uses two positions in a {@code String}. * <p>The {@code String} class provides methods for dealing with * Unicode code points (i.e., characters), in addition to those for * dealing with Unicode code units (i.e., {@code char} values). * * @author  Lee Boynton * @author  Arthur van Hoff * @author  Martin Buchholz * @author  Ulf Zibis * @see     java.lang.Object#toString() * @see     java.lang.StringBuffer * @see     java.lang.StringBuilder * @see     java.nio.charset.Charset * @since   JDK1.0 */
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { // code}
复制代码

9、写在方法上的 Javadoc

写在方法上的文档标注一般分为三段:


  • 第一段:概要描述,通常用一句或者一段话简要描述该方法的作用,以英文句号作为结束

  • 第二段:详细描述,通常用一段或者多段话来详细描述该方法的作用,一般每段话都以英文句号作为结束

  • 第三段:文档标注,用于标注参数、返回值、异常、参阅等

1)@param 后面跟参数名,再跟参数描述
2)@return 跟返回值的描述
3)@throws 跟异常类型 异常描述 , 用于描述方法内部可能抛出的异常
4)@exception 用于描述方法签名 throws 对应的异常
5)@see 既可以用来类上也可以用在方法上,表示可以参考的类或者方法
6)@value 用于标注在常量上,{@value} 用于表示常量的值
/** 默认数量 {@value} */private static final Integer QUANTITY = 1;
复制代码
7)@inheritDoc 用于注解在重写方法或者子类上,用于继承父类中的 Javadoc
  • 基类的文档注释被继承到了子类

  • 子类可以再加入自己的注释(特殊化扩展)

  • @return @param @throws 也会被继承


示例:


package org.springframework.util;
public abstract class StringUtils { /** * Decode the given encoded URI component value. Based on the following rules: * <ul> * <li>Alphanumeric characters {@code "a"} through {@code "z"}, {@code "A"} through {@code "Z"}, * and {@code "0"} through {@code "9"} stay the same.</li> * <li>Special characters {@code "-"}, {@code "_"}, {@code "."}, and {@code "*"} stay the same.</li> * <li>A sequence "{@code %<i>xy</i>}" is interpreted as a hexadecimal representation of the character.</li> * </ul> * * @param source the encoded String * @param charset the character set * @return the decoded value * @throws IllegalArgumentException when the given source contains invalid encoded sequences * @since 5.0 * @see java.net.URLDecoder#decode(String, String) */ public static String uriDecode(String source, Charset charset) { // code }}
复制代码

10、Java Doc 示例

package com.example.demo;
/** * 类 {@code OrderService} 订单服务层. * * <p> 主要包括 创建订单、取消订单、查询订单等功能更 * * @see Order * @author <a href="mailto:2867665887@qq.com">SunlightBright</a> * @since 2021/1/1 */public class OrderService {
/** 默认数量 {@value} */ private static final Integer QUANTITY = 1;
/** * 创建订单. * * <p> 创建订单需要传用户id和商品列表(商品id和商品数量). * * <pre> // <pre>标签在代码格式化时不会发生改变 * <code> * // 演示如何使用该方法 * List<Goods> items = new ArrayList<>(); * Goods goods = new Goods(1L, BigDecimal.ONE); * Goods goods2 = new Goods(2L, BigDecimal.TEN); * items.add(goods); * items.add(goods2); * * Order order1 = new Order(); * order.setUserId("1"); * order.setItems(items); * OrderService#createOrder(order); * </code> * </pre> * * @param order 订单信息 * @throws NullPointerException 参数信息为空 * @exception IllegalArgumentException 数量不合法 * @return 是否创建成功 * @version 1.0 * @see {@link Order} */ public boolean createOrder(Order order) throws IllegalArgumentException{ Objects.requireNonNull(order); List<Goods> items = order.getItems(); items.forEach(goods -> { BigDecimal quantity = goods.getQuantity(); if (quantity == null || BigDecimal.ZERO.compareTo(quantity) == 0) { throw new IllegalArgumentException(); } }); System.out.println("create order..."); return true; }}
复制代码

11、【强制】所有的覆写方法,必须加 @Override 注解。

​ 说明:getObject()与 get0bject()的问题。一个是字母的 O,一个是数字的 0,加 @Override 可以准确判断是否覆盖成功。另外,如果在抽象类中对方法签名进行修改,其实现类会马上编译报错。

12、【强制】不能使用过时的类或方法。

​ 说明:java.net.URLDecoder 中的方法 decode(String encodeStr) 这个方法已经过时,应该使用双参数 decode(String source, String encode)。接口提供方既然明确是过时接口,那么有义务同时提供新的接口;作为调用方来说,有义务去考证过时方法的新实现是什么。

13、【强制】Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。

​ 正例:"test".equals(object);


​ 反例:object.equals("test");


​ 说明:推荐使用 java.util.Objects#equals(JDK7 引入的工具类)

14、DO/DTO/VO 等 POJO 类时必须实现 Serializable 类,并生成 serialVersionUID

示例:


/** * 用户数据模型 * * @author <a href="mailto:2867665887@qq.com" title="SunBright">ShuNing</a> */@Datapublic class SysUserDTO implements Serializable {  // IDE生成的serialVersionUID    private static final long serialVersionUID = 3616208581527945802L;
private Long id; private String username; private String loginName;}
复制代码

15、【推荐】 类内方法定义的顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter 方法。

说明: 公有方法是类的调用者和维护者最关心的方法,首屏展示最好;保护方法虽然只是子类关心,也可能是“模板设计模式”下的核心方法;而私有方法外部一般不需要特别关心,是一个黑盒实现;因为承载的信息价值较低,所有 Service 和 DAO 的 getter/setter 方法放在类体最后。

16、【强制】不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator 方式,如果并发操作,需要对 Iterator 对象加锁。

示例:


// Java迭代器的使用 IteratorList<Object> list = new ArrayList<>();for(Iterator<Map<String, Object>> it = list.iterator(); it.hasNext();){    Map<String, Object> map = it.next();    if (Objects.nonNull(map.get("name")) && "OPERATOR_NAME".equals(map.get("name").toString())) {        roleId = map.get("id").toString();        break;    }    it.remove();}
复制代码

17、Java 集合(Collections)的非空判断使用 Collection#isEmpty()

正例:


public List<SysUser> collectionsIsEmpty(int status) {    List<SysUser> userListCollections = sysUserService.findByStatus(status);    if (userListCollections.isEmpty()) {        throw new SysUserIsEmptyException("There is no system user collection");    }    return userListCollections;}
复制代码

18、【强制】SimpleDateFormat 是线程不安全的类,一般不要定义为 static 变量,如果定义为 static,必须加锁,或者使用 DateUtils 工具类。

正例:注意线程安全,使用 DateUtils。亦推荐如下处理:


private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {    @Override    protected DateFormat initialValue() {      return new SimpleDateFormat("yyyy-MM-dd");    }};
复制代码


说明:如果是 JDK8 的应用,可以使用 Instant 代替 Date,LocalDateTime 代替 Calendar,DateTimeFormatter 代替 SimpleDateFormat,官方给出的解释:simple beautiful strong immutable thread-safe。

19、【推荐】避免如下误解:敏捷开发 = 讲故事 + 编码 + 发布。

​ 说明:敏捷开发是快速交付迭代可用的系统,省略多余的设计方案,摒弃传统的审批流程,但核心关键点上的必要设计和文档沉淀是需要的。


​ 反例:某团队为了业务快速发展,敏捷成了产品经理催进度的借口,系统中均是勉强能运行但像面条一样的代码,可维护性和可扩展性极差,一年之后,不得不进行大规模重构,得不偿失。

20、静态常量定义规则:

// 正例private static final String UNKNOWN = "unknown";
// 反例static private final String UNKNOWN_IS = "unknown";private final static String UNKNOWN_IS_DEL = "unknown";
复制代码


用户头像

DC.夜猫

关注

码农一枚,喜欢聊聊代码,爱技术也爱生活! 2019.04.22 加入

长期致力于基础代码库的研发工作,主要关注微服务、高并发和容器化等技术领域;对Spring Boot、Spring Cloud、Netty以及物联网技术有深刻的研究和独到的见解。

评论

发布
暂无评论
Java开发规范(一)_DC.夜猫_InfoQ写作社区