1. 代码检测工具
- 代码格式检测工具-CheckStyle
- 代码规范检测工具-Sonarlint
- 代码规范检测工具-Alibaba-Java-Coding-Guidelines
- AlibabaJava开发规范PDF版
- 代码规范检测工具-SonarQube
2. 代码规范书籍
- Effective Java
- AlibabaJava开发规范
3. 规范规则-使用新版本特性
3.1 lambda语法-Java8
3.1.1 提取元素
正例:
List<String> emails = users.stream()
.map(User::getEmail)
.collect(Collectors.toUnmodifiableList());
int total = users.stream()
.filter(Objects::nonNull)
.mapToInt(NumberUtils::toInt)
.sum();
反例:
List<String> emails = Lists.newArrayListWithCapacity(users.size());
for (User u : users) {
emails.add(u.getEmail());
}
3.1.2 过滤元素
正例:
List<String> emails = users.stream()
.map(User::getEmail)
.filter(Objects::nonNull)
.collect(Collectors.toUnmodifiableList());
3.1.3 分组
正例:
Map<String, List<Person>> peopleByCity
= personStream.collect(Collectors.groupingBy(Person::getCity));
3.1.4 连接指定字符串
String email = users.stream()
.map(User::getEmail)
.collect(Collectors.joining(","));
3.1.5 排序
users.stream()
.sorted(Comparator.comparing(User::getRegistrationTime, Comparator.nullsLast(Comparator.reverseOrder())))
.collect(Collectors.toList());
3.2 try-with-resources语法-Java8
正例:
static String readFirstLineFromFile(String path) throws IOException {
try (FileReader fr = new FileReader(path);
BufferedReader br = new BufferedReader(fr)) {
return br.readLine();
}
}
反例:
static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
FileReader fr = new FileReader(path);
BufferedReader br = new BufferedReader(fr);
try {
return br.readLine();
} finally {
br.close();
fr.close();
}
}
3.4 使用不可变集合
3.4.1 Java9
static <E> List<E> of() {
return ImmutableCollections.emptyList();
}
static <E> Set<E> of() {
return ImmutableCollections.emptySet();
}
static <K, V> Map<K, V> of() {
return ImmutableCollections.emptyMap();
}
3.4.2 Guava
如果使用的是JDK9一下的版本可以考虑使用Guava,JDK9不可变集合的设计在一定程度上参考了Guava。
ImmutableList
public static <E> ImmutableList<E> of() {
return (ImmutableList<E>) EMPTY;
}
ImmutableMap
public static <K, V> ImmutableMap<K, V> of(K k1, V v1) {
return ImmutableBiMap.of(k1, v1);
}
3.5 Optional
return Optional.of(user).map(User::getNickname).orElse(user.getUsername());
return Optional.ofNullable(user).ifPresent(this.userService::delete);
this.userService.getOne(id).orElse(defaultUser);
3.6 日期格式转换
TimeUnit.of(ChronoUnit.MILLIS).convert(diffInMillis, TimeUnit.MINUTES);
4. 使用工具类
4.1 org.springframework.util.CollectionUtils
public static boolean isEmpty(@Nullable Collection<?> collection) {
return (collection == null || collection.isEmpty());
}
public static boolean isEmpty(@Nullable Map<?, ?> map) {
return (map == null || map.isEmpty());
}
@Nullable
public static <T> T firstElement(@Nullable List<T> list) {
if (isEmpty(list)) {
return null;
}
return list.get(0);
}
@Nullable
public static <T> T lastElement(@Nullable List<T> list) {
if (isEmpty(list)) {
return null;
}
return list.get(list.size() - 1);
}
4.2 org.springframework.beans.BeanUtils
- org.springframework.beans.BeanUtils#copyProperties(java.lang.Object, java.lang.Object)
4.3 org.apache.commons.lang3.StringUtils
- org.apache.commons.lang3.StringUtils#isEmpty
- org.apache.commons.lang3.StringUtils#left
- org.apache.commons.lang3.StringUtils#split(java.lang.String)
- org.apache.commons.lang3.StringUtils#equals
- org.apache.commons.lang3.StringUtils#startsWith(java.lang.CharSequence, java.lang.CharSequence)
- ...
4.4 org.apache.commons.lang3.math.NumberUtils
- org.apache.commons.lang3.math.NumberUtils#toInt(java.lang.String)
4.5 org.apache.commons.lang3.ArrayUtils
- org.apache.commons.lang3.ArrayUtils#isEmpty(boolean[])
4.6 org.apache.commons.lang3.time.DateUtils
- org.apache.commons.lang3.time.DateUtils#addDays
- org.apache.commons.lang3.time.DateUtils#isSameDay(java.util.Calendar, java.util.Calendar)
4.7 cn.hutool.core.date.DateUtil
- cn.hutool.core.date.DateUtil#beginOfDay
- cn.hutool.core.date.DateUtil#betweenDay
4.8 org.springframework.core.NamedThreadLocal
4.9 org.springframework.util.StopWatch
4.10 org.springframework.util.ObjectUtils
- org.springframework.util.ObjectUtils#nullSafeEquals
- org.springframework.util.ObjectUtils#isEmpty(java.lang.Object)
4.11 org.apache.commons.lang3.EnumUtils
- org.apache.commons.lang3.EnumUtils#getEnum(java.lang.Class<E>, java.lang.String)
4.12 org.springframework.util.ResourceUtils
- org.springframework.util.ResourceUtils#getURL
- org.springframework.util.ResourceUtils#getFile(java.lang.String)
5. 避免使用魔法值
5.1. org.springframework.http.MediaType
@PostMapping(path = "/create", consumes = {MediaType.APPLICATION_JSON_VALUE})
public Message<Entity> create() {}
5.2. org.springframework.http.HttpHeaders
5.3. org.springframework.http.HttpStatus
5.4. java.nio.charset.StandardCharsets
5.5. org.apache.commons.collections4.ArrayUtils
org.apache.commons.collections4.ArrayUtils#INDEX_NOT_FOUND
5.6. org.apache.commons.lang3.StringUtils
public static final String SPACE = " ";
public static final String EMPTY = "";
public static final String LF = "\n";
public static final String CR = "\r";
public static final int INDEX_NOT_FOUND = -1;
5.7. org.springframework.util.ObjectUtils
private static final String EMPTY_STRING = "";
private static final String NULL_STRING = "null";
private static final String ARRAY_START = "{";
private static final String ARRAY_END = "}";
private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END;
private static final String ARRAY_ELEMENT_SEPARATOR = ", ";
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
5.8 反例
HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
int index = userIds.indexOf(userId);
if (index != -1) {
// ...do something
}
URLEncoder.encode(url, "utf-8")
5.9 正例
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=file.txt");
headers.add(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
headers.add(HttpHeaders.PRAGMA, "no-cache");
headers.add(HttpHeaders.EXPIRES, "0");
int index = userIds.indexOf(userId);
if (index != ArrayUtils.INDEX_NOT_FOUND) {
// ...do something
}
URLEncoder.encode(url, StandardCharsets.UTF_8)
6. Git Commit 规范
6.1 概述
使用 git commit -m ""
可以提交对应的更改信息。
git commit -m "";
6.2. Commit 规范
6.2.1 commit 格式
提交中应该包含 标题、类型、主题、正文和页脚,其中标题、类型、主题包含在了header/标题,这与我们HTML类似,一个完整的网页应该包含 header、body、body。例如:
git commit -m "${type}(${scope}): ${body}" -m "${footer}"
6. 2.2 标题
标题是必选的,它以下部分组成:
- 类型:提交的类型,有功能、修复、格式整理等。
- 范围:更改的范围,例如数据访问层、控制层、对外api、Spring配置等。
- 主题:对本次修改的概述。
绝大多数场景中,我们提交信息都只包含了标题部分,例如:
git commit -m "feat(dao): 增加自定义TypeHandler";
feat
表示提交的类型,后面使用()
包含修改的范围,使用:
和一个空格分割消息的正文。
6.3 正文
可选
6.4 页脚
可选
6.5 查看提交记录
git log;
git reflog;
git log --oneline;
git log --oneline -n3;
git log --oneline | grep "feat"
6.3. 类型
除了commit
的规范之外,还规定了常见的提交类型。
6.3.1 build/chore
build/chore
,用于构建系统(包括脚本、配置或工具)和依赖的变化等,例如:
git commit -m "build(deps/pom.xml): bump maven-deploy-plugin from 2.8.2 to 3.0.0"
git commit -m "fix(deps): upgrade com.google.code.gson:gson from 2.8.9 to 2.9.0"
6.3.2 ci
ci
用于系统持续集成、持续部署相关的配置文件、脚本文件、配置或者工具,例如:
git commit -m "ci: add docker file"
6.3.3 docs
docs
用于标识项目相关文档的更改,例如:
git commit -m "doc(README.md): Update README.md"
6.3.4 feat
feat
用于标识新功能,例如:
git commit -m "feat(oa): 增加审批流程支持";
6.3.5 fix
fix
用于标识bug修复,例如:
git commit -m "fix(router): IE9下路由没有响应";
6.3.6 perf
perf
用于标识性能提升,例如:
git commit -m "perf(excel/export): 使用线程池批处理文件";
6.3.7 refactor
refactor
用于标识代码重构,既不添加新功能也不修复错误--例如删除冗余代码、简化代码、重命名变量等。
git commit -m "refactor(cms): 重构CMS客户模块";
6.3.8 style
style
用于标记代码格式化,代码风格调制,修复checkstyle等问题,例如:
git commit -m "style: Reformat Code.";
6.3.9 test
test
用于标记测试相关的更改,修改现有测试或添加新的测试,例如:
git commit -m "test(dao): add user unit tests.";
6.3.10 revert
revert
用于版本回滚,例如:
git commit -m "revert: rever to xxx";
7. 包命名规范
7.1 support
7.2 controller
7.3 service
7.4 service/impl
7.5 utils
7.6 annotation
7.7 constants
7.8 enums
7.9 aspect
7.10 exception
7.11 pojo
DTO
:数据传输对象(Data Transfer Object
),一般用于接受前端传输过来的值,类以DTO
结尾。VO
:值对象,一般用于返回给前端的数据,类以VO
结尾。BO
:业务对象,一般用于业务模块内部使用,类以BO
结尾。
8. pom.xml规范
8.1 依赖版本管理
对于依赖的版本需要放在 pom.xml
的properties
元素中,标签名以依赖的 artifactId
加上 .version
作为标签名,例如:
<properties>
<jackson-xml-databind.version>0.6.2</jackson-xml-databind.version>
</properties>
8. 集合规范
8.1 指定集合初始化容量
正例:
List<String> emails = Lists.newArrayListWithCapacity(users.size());
for (User u : users) {
emails.add(u.getEmail());
}
Map<String, Object> result = Maps.newHashMapWithExpectedSize(3);
result.put("code",100);
result.put("msg","success");
result.put("result",Collections.emptyList());
反例:
List<String> emails = new ArrayList<>();
for (User u : users) {
emails.add(u.getEmail());
}
Map<String, Object> result = new HashMap<>();
result.put("code",100);
result.put("msg","success");
result.put("result",Collections.emptyList());
9. 避免空指针
9.1 返回空对象
return Collections.emptyList();
return StringUtils.EMPTY;
return Optinal.empty();
return ArrayUtils.EMPTY_CHAR_ARRAY;
10. 使用业务命名而非技术命名
反例:
List bookList = service.getBooks();
正例:
List books = service.getBooks();
11. 使用卫语句
反例:
function getPayAmount() {
let result;
if (isDead)
result = deadAmount();
else {
if (isSeparated)
result = separatedAmount();
else {
if (isRetired)
result = retiredAmount();
else
result = normalPayAmount();
}
}
return result;
}
正例:
function getPayAmount() {
if (isDead) return deadAmount();
if (isSeparated) return separatedAmount();
if (isRetired) return retiredAmount();
return normalPayAmount();
}
12 使用语意化API
12.1 日期的表示
反例:
long millis = 1000;
正例:
long millis = Duration.ofSeconds(1).toMillis();
12.2 日期的比较
反例:
if (startTime.getTime() > now) {
// do something
}
if(startTime.compareTo(now) > 0) {
// do something
}
正例:
if(startTime.after(now)) {
// do something
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。