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
示例:
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";
复制代码
评论