当前位置: 首页 > 后端技术 > Java

良好的代码品味

时间:2023-04-01 23:17:39 Java

1。代码检查工具代码格式检查工具-CheckStyle代码规范检查工具-Sonarlint代码规范检查工具-Alibaba-Java-Coding-GuidelinesAlibabaJava开发规范PDF版代码规范检查工具-SonarQube2.0CodeSpecificationBookEffectiveJavaAlibabaJavaDevelopmentSpecification3.规范规则-使用新版本特性3.1Lambda语法-Java83.1.1ExtractElements正例:Listemails=users.stream().map(User::getEmail).collect(Collectors.toUnmodifiableList());inttotal=users.stream().filter(Objects::nonNull).mapToInt(NumberUtils::toInt).sum();反例:Listemails=Lists.newArrayListWithCapacity(users.size());for(Useru:users){emails.add(u.getEmail());}3.1.2过滤元素正例:Listemails=users.stream().map(User::getEmail).filter(Objects::nonNull).collect(Collectors.toUnmodifiableList());3.1.3分组正例:Map>peopleByCity=personStream.collect(Collectors.groupingBy(Person::getCity));3.1.4连接指定字符串Stringemail=users.stream().map(User::getEmail).collect(Collegectors.joining(","));3.1.5排序users.stream().sorted(Comparator.comparing(User::getRegistrationTime,Comparator.nullsLast(Comparator.reverseOrder()))).collect(Collectors.toList());3.2try-with-resources语法-Java8正例:staticStringreadFirstLineFromFile(Stringpath)throwsIOException{try(FileReaderfr=newFileReader(path);BufferedReaderbr=newBufferedReader(fr)){returnbr.readLine();}}反例:staticStringreadFirstLineFromFileWithFinallyBlock(Stringpath)throwsIOException{FileReaderfr=newFileReader(path);BufferedReaderbr=newBufferedReader(fr);尝试{返回br.readLine();}最后{br.close();fr.close();}}3.4使用不可更改集合3.4.1Java9staticListof(){returnImmutableCollections.emptyList();}staticSetof(){returnImmutableCollections.emptySet();}staticMapof(){返回ImmutableCollections.emptyMap();}3.4.2Guava如果你使用的是JDK9以下的版本,可以考虑使用Guava。JDK9不可变集合的设计一定程度上参考了GuavaImmutableListpublicstaticImmutableListof(){return(ImmutableList)EMPTY;}ImmutableMappublicstaticImmutableMapof(Kk1,Vv1){返回ImmutableBiMap.of(k1,v1);}3.5OptionalreturnOptional.of(user).map(User::getNickname).orElse(user.getUsername());returnOptional.ofNullable(user).ifPresent(this.userService::delete);this.userService.getOne(id).orElse(defaultUser);3.6日期格式转换TimeUnit.of(ChronoUnit.MILLIS).convert(diffInMillis,TimeUnit.MINUTES);4.使用工具类GuavaApache-Commonshutool4.1org.springframework.util.CollectionUtilspublicstaticbooleanisEmpty(@NullableCollectioncollection){return(collection==null||collection.isEmpty());}publicstaticbooleanisEmpty(@NullableMapmap){return(map==null||map.isEmpty());}@NullablepublicstaticTfirstElement(@NullableListlist){if(isEmpty(list)){返回空值;}返回list.get(0);}@NullablepublicstaticTlastElement(@NullableListlist){if(isEmpty(list)){返回空;}returnlist.get(list.size()-1);}4.2org.springframework.beans.BeanUtilsorg.springframework.beans.BeanUtils#copyProperties(java.lang.Object,java.lang.Object)4.3org.apache。commons.lang3.StringUtilsorg.apache.commons.lang3.StringUtils#isEmptyorg.apache.commons.lang3.StringUtils#leftorg.apache.commons.lang3.StringUtils#split(java.lang.String)org.apache.commons.lang3。StringUtils#equalsorg.apache.commons.lang3.StringUtils#startsWith(java.lang.CharSequence,java.lang.CharSequence)...4.4org.apache.commons.lang3.math.NumberUtilsorg.apache.commons.lang3.math.NumberUtils#toInt(java.lang.String)4.5org.apache.commons.lang3.ArrayUtilsorg.apache.commons.lang3.ArrayUtils#isEmpty(boolean[])4.6org.apache.commons.lang3.time.DateUtilsorg.apache。commons.lang3.time.DateUtils#addDaysorg.apache.commons.lang3.time.DateUtils#isSameDay(java.util.Calendar,java.util.Calendar)4.7cn.hutool.core.date.DateUtilcn.hutool.core.date.DateUtil#beginOfDaycn.hutool.core.date.DateUtil#betweenDay4.8org.springframework.core.NamedThreadLocal4.9组织.springframework.util.StopWatch4.10org.springframework.util.ObjectUtilsorg.springframework.util.ObjectUtils#nullSafeEqualsorg.springframework.util.ObjectUtils#isEmpty(java.lang.Object)4.11org.apache.commons.lang3.EnumUtilsorg.apache.commons.lang3.EnumUtils#getEnum(java.lang.Class,java.lang.String)4.12org.springframework.util.ResourceUtilsorg.springframework.util.ResourceUtils#getURLorg.springframework.util.ResourceUtils#getFile(java.lang.String)5.避免使用魔法值5.1。org.springframework.http.MediaType@PostMapping(path="/create",consumes={MediaType.APPLICATION_JSON_VALUE})publicMessagecreate(){}5.2。org.springframework.http.HttpHeaders5.3.org.springframework.http.HttpStatus5.4.java.nio.charset.StandardCharsets5.5。组织.apache.commons.collections4.ArrayUtilsorg.apache.commons.collections4.ArrayUtils#INDEX_NOT_FOUND5.6。org.apache.commons.lang3.StringUtilspublicstaticfinalStringSPACE="";publicstaticfinalStringEMPTY="";publicstaticfinalStringLF="\n";publicstaticfinalStringCR="\r";publicstatic最终intINDEX_NOT_FOUND=-1;5.7。org.springframework.util.ObjectUtilsprivatestaticfinalStringEMPTY_STRING="";privatestaticfinalStringNULL_STRING="null";privatestaticfinalStringARRAY_START="{";privatestaticfinalStringARRAY_END="}";privatestaticfinalStringEMPTY_ARRAY=ARRAY_START+ARRAY_END;privatestaticfinalStringARRAY_ELEMENT_SEPARATOR=",";privatestaticfinalObject[]EMPTY_OBJECT_ARRAY=newObject[0];5.8反例HttpHeadersheaders=newHttpHeaders();headers.add("Cache-Control","无缓存,无存储,必须重新验证");headers.add("Pragma","no-cache");headers.add("Expires","0");intindex=userIds.indexOf(userId);if(index!=-1){//...dosomething}URLEncoder.encode(url,"utf-8")5.9正例HttpHeadersheaders=newHttpHeaders();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");intindex=userIds.indexOf(userId);if(index!=ArrayUtils.INDEX_NOT_FOUND){//...dosomething}URLEncoder.encode(url,StandardCharsets.UTF_8)6.Git提交规范6.1概述使用gitcommit-m""可以提交相应的变更信息gitcommit-m"";6.2.Commit规范6.2.1Commit格式提交应该包括title,type,subject,textandfooter,其中title,type,subject包含在header/title中,类似于我们的HTML,一个完整的网页应该包含header,body,身体。例如:gitcommit-m"${type}(${scope}):${body}"-m"${footer}"6.2.2标题标题是必填项,由以下部分组成:类型:submittedType,withfunctions,fixes,formatting等。Scope:变更范围,如数据访问层、控制层、外部API、Spring配置等。Subject:修订概况。在大多数场景下,我们的提交信息只包含标题部分,例如:gitcommit-m"feat(dao):AddacustomTypeHandler";feat表示提交的类型,后面用()表示修改范围,用:和空格分隔消息正文。6.3Text可选6.4Footer可选6.5查看提交记录gitlog;gitreflog;gitlog--oneline;gitlog--oneline-n??3;gitlog--oneline|此外,还指定了常见的提交类型。6.3.1build/chorebuild/chore,用于构建系统(包括脚本、配置或工具)和更改依赖等,例如:gitcommit-m"build(deps/pom.xml):bumpmaven-deploy-pluginfrom2.8.2to3.0.0"gitcommit-m"fix(deps):upgradecom.google.code.gson:gsonfrom2.8.9to2.9.0"6.3.2cici用于系统连续集成和持续部署配置文件、脚本文件、配置或工具,例如:gitcommit-m"ci:adddockerfile"6.3.3docsdocs用于标识项目相关文件的变更,例如:gitcommit-m"doc(README.md):UpdateREADME.md"6.3.4featfeat用于标识新特性,例如:gitcommit-m"feat(oa):Addapprovalprocesssupport";6.3.5fixfix用于标识bug修复,例如:gitcommit-m"fix(router):TheroutedoesnotrespondunderIE9";6.3.6perfperf用于标识性能改进,例如:gitcommit-m"perf(excel/export):usethreadpoolbatchfiles";6.3.7refactorrefactor用于标识既不增加新功能也不修复bug的代码重构——例如去除冗余代码、简化代码、重命名变量等。gitcommit-m"refactor(cms):重构CMS客户端模块";6.3.8stylestyle用于标记代码格式化,代码风格调制,修复checkstyle问题,例如:gitcommit-m"style:ReformatCode.";6.3.9testtest用于标记测试相关的变化,修改已有的测试或增加新的测试,例如:gitcommit-m"test(dao):adduserunittests.";6.3.10revertrevert用于版本回滚,例如:gitcommit-m"revert:revertoxxx";7.包命名约定7.1support7.2controller7.3service7.4service/impl7.5utils7.6annotation7.7constants7.8enums7.9aspect7.10exception7.11pojoDTO:数据传输对象(DataTransferObject),一般用于接受前端传过来的值,类以DTO结尾。VO:值对象,一般用于返回给前端的数据,类以VO结尾。BO:业务对象,一般在业务模块内部使用,类以BO结尾。8.pom.xml规范8.1依赖版本管理依赖版本需要放在pom.xml的properties元素中,标签名是依赖的artifactId加上.version作为标签名,例如:0.6.28.集合规范8.1指定集合的??初始化容量正例:Listemails=Lists.newArrayListWithCapacity(users.size());for(Useru:users){emails.add(u.getEmail());}Mapresult=Maps.newHashMapWithExpectedSize(3);result.put("code",100);result.put("msg","success");result.put("result",Collections.emptyList());反例:Listemails=newArrayList<>();for(Useru:users){emails.add(u.getEmail());}Mapresult=newHashMap<>();result.put("code",100);result.put("msg","success");result.put("result",Collections.emptyList());9.避免空指针9.1返回空对象returnCollections.emptyList();returnStringUtils.EMPTY;returnOptional.empty();re转ArrayUtils.EMPTY_CHAR_ARRAY;10、用业务命名代替技术命名反面例子:ListbookList=service.getBooks();正例:Listbooks=service.getBooks();11、使用guard语句反例:functiongetPayAmount(){letresult;如果(isDead)结果=deadAmount();else{if(isSeparated)结果=separatedAmount();else{if(isRetired)结果=retiredAmount();否则result=normalPayAmount();}}返回结果;示例:函数getPayAmount(){if(isDead)returndeadAmount();如果(isSeparated)返回separatedAmount();如果(isRetired)返回retiredAmount();returnnormalPayAmount();}12使用语义API12.1日期表示反例:longmillis=1000;正例:longmillis=Duration.ofSeconds(1).toMillis();12.2日期比较反例:if(startTime.getTime()>now){//dosomething}if(startTime.compareTo(now)>0){//dosomething}正例:if(startTime.after(now)){//做一点事}