好的代码的品味

1. 代码检测工具

  1. 代码格式检测工具-CheckStyle
  2. 代码规范检测工具-Sonarlint
  3. 代码规范检测工具-Alibaba-Java-Coding-Guidelines
  4. AlibabaJava开发规范PDF版
  5. 代码规范检测工具-SonarQube

2. 代码规范书籍

  1. Effective Java
  2. 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. 使用工具类

  1. Guava
  2. Apache-Commons
  3. hutool
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
  1. org.springframework.beans.BeanUtils#copyProperties(java.lang.Object, java.lang.Object)
4.3 org.apache.commons.lang3.StringUtils
  1. org.apache.commons.lang3.StringUtils#isEmpty
  2. org.apache.commons.lang3.StringUtils#left
  3. org.apache.commons.lang3.StringUtils#split(java.lang.String)
  4. org.apache.commons.lang3.StringUtils#equals
  5. org.apache.commons.lang3.StringUtils#startsWith(java.lang.CharSequence, java.lang.CharSequence)
4.4 org.apache.commons.lang3.math.NumberUtils
  1. org.apache.commons.lang3.math.NumberUtils#toInt(java.lang.String)
4.5 org.apache.commons.lang3.ArrayUtils
  1. org.apache.commons.lang3.ArrayUtils#isEmpty(boolean[])
4.6 org.apache.commons.lang3.time.DateUtils
  1. org.apache.commons.lang3.time.DateUtils#addDays
  2. org.apache.commons.lang3.time.DateUtils#isSameDay(java.util.Calendar, java.util.Calendar)
4.7 cn.hutool.core.date.DateUtil
  1. cn.hutool.core.date.DateUtil#beginOfDay
  2. cn.hutool.core.date.DateUtil#betweenDay
4.8 org.springframework.core.NamedThreadLocal
4.9 org.springframework.util.StopWatch
4.10 org.springframework.util.ObjectUtils
  1. org.springframework.util.ObjectUtils#nullSafeEquals
  2. org.springframework.util.ObjectUtils#isEmpty(java.lang.Object)
4.11 org.apache.commons.lang3.EnumUtils
  1. org.apache.commons.lang3.EnumUtils#getEnum(java.lang.Class, java.lang.String)
4.12 org.springframework.util.ResourceUtils
  1. org.springframework.util.ResourceUtils#getURL
  2. 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 规范

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7rzG48r3-1668530259752)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6a7f8624a6514a24996d4a46a387e30d~tplv-k3u1fbpfcp-zoom-1.image)]

6.1 概述

使用 git commit -m "" 可以提交对应的更改信息。

git commit -m "";
6.2. Commit 规范
6.2.1 commit 格式

提交中应该包含 标题类型主题正文页脚,其中标题、类型、主题包含在了header/标题,这与我们HTML类似,一个完整的网页应该包含 headerbodybody。例如:

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
  1. DTO:数据传输对象(Data Transfer Object),一般用于接受前端传输过来的值,类以 DTO 结尾。
  2. VO:值对象,一般用于返回给前端的数据,类以 VO 结尾。
  3. BO:业务对象,一般用于业务模块内部使用,类以 BO结尾。
8. pom.xml规范
8.1 依赖版本管理

对于依赖的版本需要放在 pom.xmlproperties元素中,标签名以依赖的 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
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值