編碼規範集錦

1.      

Result result=new Result();

result.setCode(201);

result.setStr(re);

result.setMessage("獲取id成功");

 

建議:對常用的功能,可以:新增Constructor,把4行code用1行搞定。

Result result=new Result(code, str, msg);

 

2.      

StringBuffer stringBuffer=newStringBuffer();

String[]formatStr=snFormatStr.split(splitChar);

for(String inStr:formatStr){

   //判斷以str開頭,不分大小寫

   if(inStr.matches("^[Ss][Tt][Rr].*")){

       stringBuffer.append(processStr(inStr));

 

建議:StringBuffer改成StringBuilder。

倒數第二行用commons-lang3的,既能避免硬編碼,又避免了寫正則表達式。

StringUtils.startsWithIgnoreCase(CharSequence,CharSequence)

 

 

3.      

private String processDate(String str)throws Exception{

   String[] strings=str.split(innerChar);

Stringdef="yyyyMMdd";

 

建議:凡是屬於 “無狀態的” “通用的”功能,可以放在Util.java裏。

如果確實需要硬編碼,放在Util.java裏,讓它們只永遠出現一次。

 

4.      

String re="";

……

if(ar.length>1&&add!=""){

 

建議:org.apache.commons.lang3.StringUtils.EMPTY

重用常量,不要自己新創建。

 

5.      

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

 

if (LOGGER.isDebugEnabled()) {

         LOGGER.debug("Attemptingto resolve a principal...");

建議:既然用了slf4j,裏面就封裝了判斷log level的功能。

LOGGER.isDebugEnabled()是多餘的。

 

6.      

if (attributes == null) {

return null;

……

if (itemNo.length()!=3) {

         thrownew RuntimeException("ItemCode has exceed 3 bits !");

 

建議:

jdk,throw new IllegalArgumentException(...);

jdk,throw new IllegalStateException(...);

org.springframework.util.Assert.isTrue(boolean,String)

org.springframework.util.Assert.state(boolean,String)

 

7.      

if (null != sos) {

   try {

       sos.close();

    }catch (IOException e) {

             LOGGER.error("handleRequest 關閉流出現異常! ",e);

    }

}

建議:

org.apache.commons.io.IOUtils.closeQuietly(OutputStream)

org.apache.commons.io.IOUtils.closeQuietly(Writer)

8.      

public void setApplicationContext(finalApplicationContext applicationContext) {

   super.setApplicationContext(applicationContext);

   this.applicationContext = applicationContext;

}

建議:既然父類已經有了ApplicationContext,子類的就是無用的,可以刪除。

 

9.      

public classImageVaditeAuthenticationViaFormAction

  if(this.credentialsBinder != null &&this.credentialsBinder.supports(credentials.getClass())) {

   this.credentialsBinder.bind(request, credentials);

  }

建議:Web層裏,傳遞給Service層的東東,不應該有ServletAPI。

10.              

UserCacheVO vo = new UserCacheVO();

vo.setLoginIP(request.getRemoteAddr());

vo.setLoginTime(DateUtil.DateTimeToString(newDate()));

vo.setResourceNo(resourceNo);

vo.setUserName(loginId);

vo.setUserSymbol(userSymbol);

建議:做成UserCacheVO vo =new UserCacheVO(w,x,y,z);

 

11.              

建議:合併。每個package裏,有幾個幾十個類是正常的。

com.gy.prvg.acl.constant裏的多個常量類,合併爲一個。Enum,也做在常量類裏面。

 

2014/09/22增補)目前公司裏還有個類似的狀況,工程師們喜歡狂建項目——

只有幾個類的十幾個類的,都能做個單獨的項目出來。

建議:一個工程有了2000--4000個類,可以考慮拆分。幾百個類的,先保持在一起。

好處:便於開發,便於查找,便於檢錯,便於調試,便於維護,便於測試。

 

 

 

 

12.              

public static final List<AccountType>AllTypes() {

         List<AccountType>types = new ArrayList<AccountType>();

         for(AccountType accountType : AccountType.values()) {

                   types.add(accountType);

         }

         returntypes;

}

建議:List<TimeUnit>list = java.util.Arrays.asList(TimeUnit.values()); 一句話搞定。

 

13.              

@Override

public String toString() {

         Map<String,Object> map = new HashMap<String, Object>();

         map.put("loginId",loginId);

         map.put("resourceNo",resourceNo);

         map.put("deptNo",deptNo);

         map.put("userName",userName);

         map.put("userCode",userCode);

         map.put("cardId",cardId);

         map.put("phone",phone);

         map.put("email",email);

         map.put("status",status);

         map.put("roleType",roleType);

         map.put("corpName",getCorpName());

         map.put("deptNo",getDeptName());

         returnJSON.toJSONString(map);

 

建議:

可以用JSON.toJSONString(this);一句搞定。或者加上@JsonIgnore能屏蔽些field。

搞json格式,全部項目應該用統一的jar。推薦:fastjson。

 

14.              

import org.apache.log4j.FileAppender;

import org.apache.log4j.Layout;

importorg.apache.log4j.helpers.CountingQuietWriter;

import org.apache.log4j.helpers.LogLog;

importorg.apache.log4j.helpers.OptionConverter;

import org.apache.log4j.spi.LoggingEvent;

 

public class AclLogFileAppender extendsFileAppender

 

建議:org.apache.log4j.RollingFileAppender應該足夠用了,不用自建class。

 

15.              

public enum RoleType {

 PlatAdmin("平臺管理員"),

 CorpAdmin("公司管理員"),

 Normal("普通角色");

 

if ("財務視圖".equals(view.getViewName())) {

         view.setViewType("Finance");

}

if ("管理視圖".equals(view.getViewName())) {

         view.setViewType("Manage");

}

if ("參數視圖".equals(view.getViewName())) {

         view.setViewType("Param");

建議:用ASCII表裏的英文字母或數字。

 

16.              

public interface ILoginService {

         voidloadPrivilegeItemList(String resourceNo, String loginId, HttpServletRequestrequest);

 HttpResult logon(HttpServletRequest request);

 

建議:

團長能夠指揮士兵,士兵不能指揮團長。

上層能調用下層,下層不能調用上層。

Service層裏,不應該有Web層api。

 

17.              

if(data.get("uri").indexOf(action.getItemContent())>=0) {

 

建議:java.lang.String.contains(CharSequence)

org.apache.commons.lang3.CharEncoding.UTF_8

 

18.              

int len = roleCode.length() - 3;

int maxNo =Integer.valueOf(roleCode.substring(len));

String leafNo = String.valueOf(maxNo + 1);

leafNo = (leafNo.length() == 3) ? leafNo :(leafNo.length() == 2 ? "0" + leafNo : "00" + leafNo);

code = roleCode.substring(0, len) + leafNo;

 

建議:

org.apache.commons.lang3.StringUtils.leftPad(String,int, char)

org.apache.commons.lang3.StringUtils.leftPad(String,int, String)

 

19.              

try {

  ……

} catch (SystemException se){

         LOGGER.error("Finding listCorporation is error !",se);

         thrownew SystemException(se.getErrorCode(), se.getMessage());

} catch (Exception e) {

         LOGGER.error("Finding listCorporation is error !",e);

         thrownew SystemException(ErrorCode.ERROR_9004,"查詢公司出現異常!", e);

 

每個項目裏的每層的每個類裏,都有這些catch,有實際意義嗎?

白白的增加了幾千幾萬行code。

建議:絕大多數情況,不需要catch。public void someMethod() throws Exception是最簡潔的。

只是在必要之處,例如:返回給頁面之前,才做catch。

 

附:javachecked exception是個設計錯誤。

按照現代的程序理論:在任何地方,catch都是可有可無的,不應該強迫搞catch

Java5以前的Runnable  run(),就是強迫catch { },讓開發者感到臃腫。

Java5+CallableV call()  throws Exception; catch { } 就是可有可無的,很清爽。

 

20.              

userRole.setRoleName(URLDecoder.decode(userRole.getRoleName(),"UTF-8"));

 

建議:凡是可能有編碼毛病之處,用POST方式,

把org.springframework.web.filter.CharacterEncodingFilter當做過濾器,就實現了統管,

就不用在多處搞多個URLDecoder.decode()了。

 

 

21.              

int index =StringUtil.isEmpty(pageLeafCode) ? 0 : pageLeafCode.indexOf("[");

if (index > 0) {

         pageLeafCode= pageLeafCode.substring(index + 1,pageLeafCode.length() - 1);

 

建議:org.apache.commons.lang3.StringUtils.substringAfter(String,String)

 

 

22.              

public String toString() {

         return"Leaf [leafId=" + leafId + ", leafName=" + leafName

                            +", leafCode=" + leafCode + ", nodeCode=" + nodeCode

                            +", leafType=" + leafType + ", leafContent=" + leafContent

                            +", description=" + description + ", subSystemId="

                            +subSystemId + "]";

 

建議:在基類裏定義toString()一次就行了。

org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString(

this, ToStringStyle.SHORT_PREFIX_STYLE);

 

23.              

Map<String,String> data = newHashMap<>();

data.put("uri",request.getRequestURI());

data.put("loginId",SSOConstant.getLoginId(request));

data.put("resourceNo",SSOConstant.getResourceNo(request));

 

建議:凡是常用的hardcode,都做成靜態常量。

 

24.              

CacheLoadUtil.getRelationMap().put(roleCode,map);

建議:緩存的東東,不應該在static map的裏面,而應該在obj map裏面。

 

 

25.              

public static String objectToString(Objectobj){

         returnobj.toString();

建議:刪除這個函數。

 

26.              

public static StringreplaceSpecialStr(Object value){

         if(null!= value && !"".equals(value)){

                   returnvalue.toString().replaceAll("'", "’").trim();

建議:

org.apache.commons.lang3.StringUtils.isNotEmpty(CharSequence)

java.lang.String.replaceAll(String, String)適合於:正則表達式。

java.lang.String.replace(CharSequence,CharSequence) 更適合此處。

 

 

27.              

public static String nullConvert(Stringvalue){

         returnnull==value?"":value;

建議:該報錯的時候,就報錯,用org.springframework.util.Assert.notNull(Object)

如果確實有用,用:org.apache.commons.lang3.StringUtils.defaultString(String)

 

28.              

void modifyAuditStatus(Long[] ids, StringoperType, Map<String,String> data)

建議:Long[] ids改成:List<Long>,面向對象編程,少用array,多用List。

 

29.              

Map<String, List<Role>> map =new HashMap<String,List<Role>>();

map.put("leftRoles", leftRoles);

map.put("rightRoles",rightRoles);

建議:既然只放兩個,可以用:org.apache.commons.lang3.tuple.Pair.of(left,right)

 

 

30.              

for (String loginId : addUsers) {

         UserRoleur = new UserRole();

         ur.setCreated(now);

         ur.setCreatedBy(operator);

         ur.setIsActive('0');

         ur.setLoginId(loginId);

         ur.setResourceNo(resourceNo);

         ur.setRoleCode(roleCode);

         ur.setStatus("1");

         ur.setUpdated(now);

         ur.setUpdatedBy(operator);

建議:

ur.setIsActive('0');ur.setStatus("1"); 把類似的風格做成兩樣東東了,建議都用int風格。

 

建議:

用多參數的Constructor,把10行變成1行。

 

 

有人對此提出疑問:把10個參數放在Constructor裏,太多了……

他說的,適合於啥情況呢?

OO設計,有幾條重要原則:

(A)迪米特法則——“最少知識原則”。“不要和陌生人說話”。

(B)強內聚,弱耦合。即:關係越少越好。

 

UserRole,裏面所有的屬性都是“同類的傻傻的boolean/int/String/…”,是很簡單的容器,

不屬於OO設計範圍,就算Constructor裏有200+個參數,也是正確的。

 

下圖,如果用了3個參數的Result(x, y, z); 將會大量縮減代碼行數。

 

 

31.              

if(StringUtil.isNotEmpty(viewVO.getViewName())) {

         viewVO.setViewName("%"+ viewVO.getViewName() + "%");

         where.append("and viewName LIKE :viewName ");

}

if(StringUtil.isNotEmpty(viewVO.getViewType())) {

         viewVO.setViewType("%"+ viewVO.getViewType() + "%");

         where.append("and viewType LIKE :viewType ");

}

if(StringUtil.isNotEmpty(viewVO.getCreatedBy())) {

         viewVO.setCreatedBy("%"+ viewVO.getCreatedBy() + "%");

         where.append("and createdBy LIKE :createdBy ");

}

建議:

把"%"改成'%'

public static final char SQL_WILDCARD ='%';

把常用的拼接功能做成個靜態函數:

public static void wildcardSqlWord(Stringstr) {

   return Util.SQL_WILDCARD + str + Util.SQL_WILDCARD;

}

 

 

32.              

// 轉換用戶狀態

switch (u.getStatus()) {

case "0":

         u.setStatus("New");//新建

         break;

case "1":

         u.setStatus("Normal");//正常

         break;

case "2":

         u.setStatus("Forbidden");//禁用

         break;

default:

         u.setStatus("Illegal");//非法

         break;

// 轉換參數狀態

switch (sys.getStatus()) {

case "0":

         sys.setStatus("Normal");//正常

         break;

case "1":

         sys.setStatus("Forbidden");//禁止

         break;

default:

         sys.setStatus("Illegal");//非法

         break;

}

// 操作級別轉換

switch (sys.getOperationGrade()) {

case "0":

         sys.setOperationGrade("無");

         break;

case "1":

         sys.setOperationGrade("查詢");

         break;

case "2":

         sys.setOperationGrade("修改");

         break;

case "3":

         sys.setOperationGrade("刪除");

         break;

case "4":

         sys.setOperationGrade("全部");

         break;

default:

         sys.setOperationGrade("Illegal");

         break;

 

 

建議:

在default後面,不要寫break。

switch(x)裏,儘量不用String,而用enum。

如果確實需要switch(數字),就在enum里加入成員常量。例如:

public enum CmdCategory implements MyEnum {

  /**

   *<code>dummy = 0;</code>

   */

 dummy(0, 0),

  /**

   * 統一官網

   */

 official(1, 10000),

  /**

   * 個人系統

   */

 person(2, 20000),

  /**

   * 企業系統

   */

 company(3, 30000),

 

 

33.              

private CacheLoadUtil() {

         super();

}

public class StringUtil {

         privateStringUtil(){

                   super();

         };

建議:

public Util() { // 這裏用了public,是爲了覆蓋率的完美。

   throw new java.lang .NoSuchMethodError();

}

 

34.              

String sql = " select l.* fromT_PVG_LEAF l join T_PVG_ROLE_LEAF rl on l.leafCode

建議:應該回避”l”。

”l”長得很像數字1和i的大寫字母,java的語言規範中都回避,long 3用”3L”表示。

 

 

35.              

if (obj == null) {

         result= "PO00000000";

}else {

         result= LeafRelation.nextBriefCode(String.valueOf(obj));

}

建議:如果兩個長度都中等,可以合併爲一行,用java的三元運算符:

result = (null == obj) ? x : y

 

 

36.              

public class CacheLoadUtil {

         /**

          * <p>以企業資源號爲key 公司對象爲value</p>

          */

         privatestatic final Map<String, Corporation> CORPS = new HashMap<String,Corporation>();

         /**

          * <p>以部門編號爲key 部門對象爲value</p>

          */

         privatestatic final Map<String, Department> DEPTS = newHashMap<String,Department>();

         /**

          * <p>以角色代碼爲key 角色對象爲value</p>

          */

         privatestatic final Map<String, Role> ROLES = new HashMap<String,Role>();

建議:緩存,不要搞static Map,用實例化的對象,最好用框架EHCache、Memcache……

 

37.             推薦的Java測試組件

頁面層:HtmlUnit

業務層:Mockito/EasyMock +JUnit

持久層:HsqlDB/H2/Derby +JUnit + Spring Context

測試結果報表:Cobertura /JaCoCo

 

 

38.             自動化測試的重要信息

(1)       想要在程序這條路上走幾十年,搞自動化測試是最正確的路線。

(2)       ……

(3)       ……

待續。

 

 

39.             有人問:爲什麼推薦JUnit4?爲什麼拋棄TestNG?

JUnit,簡單易用,最好了。JUnit4,約束更少,功能更強大。

Testng,本身過度複雜,在各大IDE上的版本都不同,

本身也有內存泄露等毛病,新版本久不更新,應該拋棄。

 

 

40.              

public static final Map<String,Corporation> getCorps() throws SystemException {

         if(CORPS.isEmpty()) {

                   List<Corporation>cps = SpringBeanUtil.getBean(AclConstants.CORP_SERVICE,CorporationServiceImpl.class).queryCorporationAll();

…………

 

public class SpringBeanUtil implementsApplicationContextAware {

         privatestatic ApplicationContext ctx;

         privateSpringBeanUtil() {

                   super();

         }

         publicstatic <T> T getBean(String id, Class<T> clazz) {

                   if(ctx == null) {

                            thrownew NullPointerException("ApplicationContext is null");

                   }

                   return(T) ctx.getBean(id);

         }

         @Override

         publicvoid setApplicationContext(ApplicationContext applicationContext)

                            throwsBeansException {

                   ctx= applicationContext;

         }

}

建議:刪除Constructor,或者參考第33節

 

建議:扔掉getBean函數,用:

org.springframework.beans.factory.BeanFactory.getBean(String,Class<T>)

BeanFactory 是ApplicationContext的父接口。

 

建議:Spring搞的都是OO,我們用Spring也應該遵循OO。OO和靜態的東東是相排斥的。

把Spring的ctx做成靜態的引用,會有多種缺陷。例如:

(A)潛在的內存泄露。

(B)清理對象的時候,總是不能清理static ctx,這是災難性的錯誤。

 

建議:getBean可能是作者的使用目的,是以static的方式訪問的。

可它的初始化,竟然是以實例的方式搞的!!!

         @Override

         publicvoid setApplicationContext

 

建議:經過上面4條建議,可以刪除掉SpringBeanUtil這個可憐的類了。

 

41.              

public String resetPassword(String loginId,String resourceNo,

                   Map<String,String>data) throws SystemException {

         Stringmessage = "";

         StringuserSymbol = CacheCommonUtil.getUserSymbol(loginId, resourceNo);

         Useruser = CacheLoadUtil.getUsers().get(userSymbol);

         SystemParamdPassword =systemDao.selectSystemParamByKey(SystemParamConstants.PARAM_PWD_GROUP,user.getResourceNo());

         try{

                   if(dPassword==null||StringUtil.isEmpty(dPassword.getParamValue())) {//若無公司的默認密碼,則默認爲登錄名

                            user.setPassword(CoderUtils.toHex(CoderUtils.encryptMD5(user.getLoginId())));

                   }else{

         user.setPassword(CoderUtils.toHex(CoderUtils.encryptMD5(dPassword.getParamValue())));

                   }

                   user.setUpdated(newDate());

                   user.setUpdatedBy(data.get("loginId"));

                   userDao.update(user);

                   CacheLoadUtil.getUsers().put(userSymbol,user);

                   //增加操作日誌

                   SystemLogUtil.addSystemLog(data,FuncType.SYSTEM_SETTING,AclConstants.SYS_RESET_PASSWORD, "密碼******", "密碼******");

                   message= "success";

建議:第4行,凡是從緩存取數據的操作,應該建立個成員變量(member variable),

用Spring的標準set方式注入cacheManager對象,堅決拋棄靜態功能。

 

建議:CoderUtils,詞彙Coder明顯意義錯誤。

可以改成CodecUtils,標準依據:org.apache.commons.codec.*

 

建議:加密用:org.apache.commons.codec.digest.DigestUtils.md5Hex(byte[] data)

 

建議:倒數第3行,密碼,不應該以明文方式出現在log裏。

 

 

42.              

public class SystemServiceImpl implements ISystemService{

         privatestatic final Logger LOGGER = LoggerFactory.getLogger(SystemServiceImpl.class);

建議:實例範圍的類,就用實例範圍的Logger。

private Logger LOGGER =LoggerFactory.getLogger(getClass());

 

發佈了50 篇原創文章 · 獲贊 3 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章