Java开发规范

作者:SunlightBright GitHUb地址:SunlightBright
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 -resources
public 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>
 */
@Data
public 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迭代器的使用 Iterator
List<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";
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值