前言
小編用自己的項目做白老鼠琴昆,試試這個阿里巴巴榮譽出品的《Java規(guī)約插件》
結(jié)果居然有4800+條問題7掀瘛!簡直嚇得小編懷疑人生有木有1即?(默哀0.01秒)小編依舊懷著認(rèn)真的科學(xué)精神進(jìn)入試驗田(快開車,別廢話!)悦陋。如想了解如何安裝插件和插件的使用技巧請猛戳:http://www.reibang.com/p/834899aa90b4
入題
掃描出三個分類結(jié)果(類jira的bug優(yōu)先級分為:blocker,critical,major,minor,trivial)
-
Blocker 有妨礙的
-
Critical 緊要的
-
Major 嚴(yán)重的
具體的語法問題,值得學(xué)習(xí)下:
Blocker 有妨礙的
在if/else/for/while/do語句中必須使用大括號筑辨,即使只有一行代碼俺驶,避免使用下面的形式:if (condition) statements;
在使用正則表達(dá)式時,利用好其預(yù)編譯功能棍辕,可以有效加快正則匹配速度暮现。
說明:不要在方法體內(nèi)定義:Pattern pattern = Pattern.compile(規(guī)則);
public class XxxClass {
// Use precompile
private static Pattern NUMBER_PATTERN = Pattern.compile("[0-9]+");
public Pattern getNumberPattern() {
// Avoid use Pattern.compile in method body.
Pattern localPattern = Pattern.compile("[0-9]+");
return localPattern;
}
}多線程并行處理定時任務(wù)時,Timer運行多個TimeTask時楚昭,只要其中之一沒有捕獲拋出的異常栖袋,其它任務(wù)便會自動終止運行,使用ScheduledExecutorService則沒有這個問題抚太。 //org.apache.commons.lang3.concurrent.BasicThreadFactory
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
//do something
}
},initialDelay,period, TimeUnit.HOURS);所有的覆寫方法塘幅,必須加@Override注解。 反例:getObject()與get0bject()的問題尿贫。一個是字母的O电媳,一個是數(shù)字的0,加@Override可以準(zhǔn)確判斷是否覆蓋成功庆亡。另外匾乓,如果在抽象類中對方法簽名進(jìn)行修改,其實現(xiàn)類會馬上編譯報錯又谋。
線程池不允許使用Executors去創(chuàng)建拼缝,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學(xué)更加明確線程池的運行規(guī)則彰亥,規(guī)避資源耗盡的風(fēng)險咧七。 說明:Executors各個方法的弊端:
1)newFixedThreadPool和newSingleThreadExecutor:
??主要問題是堆積的請求處理隊列可能會耗費非常大的內(nèi)存,甚至OOM剩愧。
2)newCachedThreadPool和newScheduledThreadPool:
??主要問題是線程數(shù)最大數(shù)是Integer.MAX_VALUE猪叙,可能會創(chuàng)建數(shù)量非常多的線程娇斩,甚至OOM仁卷。
Positive example 1:
//org.apache.commons.lang3.concurrent.BasicThreadFactory
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
Positive example 2:
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("demo-pool-%d").build();
//Common Thread Pool
ExecutorService pool = new ThreadPoolExecutor(5, 200,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
pool.execute(()-> System.out.println(Thread.currentThread().getName()));
pool.shutdown();//gracefully shutdown
Positive example 3:
<bean id="userThreadPool"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="queueCapacity" value="2000" />
<property name="threadFactory" value= threadFactory />
<property name="rejectedExecutionHandler">
<ref local="rejectedExecutionHandler" />
</property>
</bean>
//in code
userThreadPool.execute(thread);
避免通過一個類的對象引用訪問此類的靜態(tài)變量或靜態(tài)方法穴翩,無謂增加編譯器解析成本,直接用類名來訪問即可锦积。
-
Critical 緊要的
Object的equals方法容易拋空指針異常芒帕,應(yīng)使用常量或確定有值的對象來調(diào)用equals。
public void f(String str){
String inner = "hi";
if(inner.equals(str)){
System.out.println("hello world");
}
}
- SimpleDateFormat 是線程不安全的類丰介,一般不要定義為static變量背蟆,如果定義為static,必須加鎖哮幢,或者使用DateUtils工具類带膀。 說明:如果是JDK8的應(yīng)用,可以使用instant代替Date橙垢,LocalDateTime代替Calendar垛叨,DateTimeFormatter代替SimpleDateFormat,官方給出的解釋:simple beautiful strong immutable thread-safe柜某。
Positive example 1:
private static final String FORMAT = "yyyy-MM-dd HH:mm:ss";
public String getFormat(Date date){
SimpleDateFormat dateFormat = new SimpleDateFormat(FORMAT);
return sdf.format(date);
}
Positive example 2:
private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public void getFormat(){
synchronized (sdf){
sdf.format(new Date());
….;
}
Positive example 3:
private static final ThreadLocal<DateFormat> DATE_FORMATTER = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
};
不能使用過時的類或方法嗽元。 說明:java.net.URLDecoder 中的方法decode(String encodeStr) 這個方法已經(jīng)過時,應(yīng)該使用雙參數(shù)decode(String source, String encode)喂击。接口提供方既然明確是過時接口剂癌,那么有義務(wù)同時提供新的接口;作為調(diào)用方來說翰绊,有義務(wù)去考證過時方法的新實現(xiàn)是什么佩谷。
-
在一個switch塊內(nèi),每個case要么通過break/return等來終止监嗜,要么注釋說明程序?qū)⒗^續(xù)執(zhí)行到哪一個case為止琳要;在一個switch塊內(nèi),都必須包含一個default語句并且放在最后秤茅,即使它什么代碼也沒有稚补。
switch( x ){
case 1 :
break ;
case 2 :
break ;
default :
} -
常量命名應(yīng)該全部大寫,單詞間用下劃線隔開框喳,力求語義表達(dá)完整清楚课幕,不要嫌名字長
public class ConstantNameDemo {
/**
- max stock count
*/
public static final Long MAX_STOCK_COUNT = 50000L;
- max stock count
-
所有的枚舉類型字段必須要有注釋,說明每個數(shù)據(jù)項的用途五垮。
public enum TestEnum {
/**
* agree
/
agree("agree"),
/*
* reject
*/
reject("reject");private String action; TestEnum(String action) { this.action = action; } public String getAction() { return action; }
}
所有編程相關(guān)的命名均不能以下劃線或美元符號開始
-
抽象類命名使用Abstract或Base開頭
abstract class BaseControllerDemo{
}abstract class AbstractActionDemo{
} 方法名乍惊、參數(shù)名、成員變量放仗、局部變量都統(tǒng)一使用lowerCamelCase润绎,必須遵從駝峰形式
-
Major 嚴(yán)重的
不允許任何魔法值(即未經(jīng)定義的常量)直接出現(xiàn)在代碼中。
Negative example:
//Magic values, except for predefined, are forbidden in coding.
if(key.equals("Id#taobao_1")){
//...
}
Positive example:
String KEY_PRE = "Id#taobao_1";
if(key.equals(KEY_PRE)){
//...
}-
中括號是數(shù)組類型的一部分,數(shù)組定義如下:String[] args
String[] a = new String[3];
及時清理不再使用的代碼段或配置信息莉撇。 說明:對于垃圾代碼或過時配置呢蛤,堅決清理干凈,避免程序過度臃腫棍郎,代碼冗余其障。
Positive example: For codes which are temporarily removed and likely to be reused, use /// to add a reasonable note.
public static void hello() {
/// Business is stopped temporarily by the owner.
// Business business = new Business();
// business.active();
System.out.println("it's finished");
}循環(huán)體內(nèi),字符串的聯(lián)接方式涂佃,使用StringBuilder的append方法進(jìn)行擴展励翼。 說明:反編譯出的字節(jié)碼文件顯示每次循環(huán)都會new出一個StringBuilder對象,然后進(jìn)行append操作辜荠,最后通過toString方法返回String對象汽抚,造成內(nèi)存資源浪費。
反例:
String result;
for (String string : tagNameList) {
result = result + string;
}
正例:
StringBuilder stringBuilder = new StringBuilder();
for (String string : tagNameList) {
stringBuilder.append(string);
}
String result = stringBuilder.toString();-
所有的抽象方法(包括接口中的方法)必須要用javadoc注釋伯病、除了返回值殊橙、參數(shù)、異常說明外狱从,還必須指出該方法做什么事情膨蛮,實現(xiàn)什么功能。 說明:如有實現(xiàn)和調(diào)用注意事項季研,請一并說明敞葛。
/**- fetch data by rule id
- @param ruleId rule id
- @param page page number
- @param jsonContext json format context
- @return Result<XxxxDO>
*/
Result<XxxxDO> fetchDataByRuleId(Long ruleId, Integer page, String jsonContext);
-
所有的類都必須添加創(chuàng)建者信息。 說明:在設(shè)置模板時与涡,注意IDEA的@author為${USER}惹谐,而eclipse的@author為${user},大小寫有區(qū)別驼卖,而日期的設(shè)置統(tǒng)一為yyyy/MM/dd的格式氨肌。
/**- Demo class
- @author keriezhang
- @date 2016/10/31
*/
public class CodeNoteDemo {
}
-
方法內(nèi)部單行注釋,在被注釋語句上方另起一行酌畜,使用//注釋怎囚。方法內(nèi)部多行注釋使用/* */注釋。注意與代碼對齊桥胞。
public void method() {
// Put single line comment above code. (Note: align '//' comment with code)
int a = 3;/** * Some description about follow code. (Note: align '/**' comment with code) */ int b = 4;
}
-
類恳守、類屬性、類方法的注釋必須使用javadoc規(guī)范贩虾,使用/內(nèi)容/格式催烘,不得使用//xxx方式和/xxx/方式。 說明:在IDE編輯窗口中缎罢,javadoc方式會提示相關(guān)注釋伊群,生成javadoc可以正確輸出相應(yīng)注釋考杉;在IDE中,工程調(diào)用方法時舰始,不進(jìn)入方法即可懸浮提示方法崇棠、參數(shù)、返回值的意義蔽午,提高閱讀效率易茬。
/*- XXX class function description.
/
public class XxClass implements Serializable {
private static final long serialVersionUID = 113323427779853001L;
/*
* id
/
private Long id;
/*
* title
*/
private String title;/** * find by id * * @param ruleId rule id * @param page start from 1 * @return Result<Xxxx> */ public Result<Xxxx> funcA(Long ruleId, Integer page) { return null; }
}
類名使用UpperCamelCase風(fēng)格酬蹋,必須遵從駝峰形式及老,但以下情形例外:(領(lǐng)域模型的相關(guān)命名)DO / BO / DTO / VO / DAO
除常用方法(如getXxx/isXxx)等外,不要在條件判斷中執(zhí)行復(fù)雜的語句范抓,將復(fù)雜邏輯判斷的結(jié)果賦值給一個有意義的布爾變量骄恶,以提高可讀性。 說明:很多if語句內(nèi)的邏輯相當(dāng)復(fù)雜匕垫,閱讀者需要分析條件表達(dá)式的最終結(jié)果僧鲁,才能明確什么樣的條件執(zhí)行什么樣的語句,那么象泵,如果閱讀者分析邏輯表達(dá)式錯誤呢寞秃?
Negative example:
if ((file.open(fileName, "w") != null) && (...) || (...)) {
...
}
Positive example:
boolean existed = (file.open(fileName, "w") != null) && (...) || (...);
if (existed) {
...
}
- 集合初始化時,指定集合初始值大小偶惠。 說明:HashMap使用如下構(gòu)造方法進(jìn)行初始化春寿,如果暫時無法確定集合大小,那么指定默認(rèn)值(16)即可忽孽。
Negative example:
Map<String, String> map = new HashMap<String, String>();
Positive example:
Map<String, String> map = new HashMap<String, String>(16);
小結(jié)
總的來說绑改,阿里巴巴Java規(guī)約插件還是對項目很有幫助的,大家用起來吧兄一。