- 方法的返回類型, 方法參數, 變量聲明時均采用接口類型, 而不是實際類型:
/** 定義接口變量為接受類型的好處: 1).面向接口編程 一種規范約束 制定者(或者叫協調者),實現者(或者叫生產者),調用者(或者叫消費者)。 接口本質上就是由制定者來協調實現者和調用者之間的關系。 只有實現者和調用者都遵循“面向接口編程”這個准則,制定者的協調目的才能達到。 接口的語義是can-do語義,表約束(Constraint)。 像JDBC的規范API,不管你使用哪一套實現,我們使用的時候都是使用相同的API. 分離設計與實現 使得系統可以支持開閉原則和依賴倒轉原則。設計師可以設計出接口,而程序員可以依照接口去寫實現。 2).解耦合 在一定程度上解耦合,依賴接口還不依賴具體實現,在替換實現類的時候,可以將影響減到最小. 3).在依賴接口的情況下,單元測試更容易,使用mock也更容易,在TDD中,測試驅動就是要讓程序易於測試。 4).與設計有關 在一個面向對象的系統中,系統的各種功能是由許許多多的不同對象協作完成的。 在這種情況下,各個對象內部是如何實現自己的對系統設計人員來講就不那么重要了; 而各個對象之間的協作關系則成為系統設計的關鍵。 在OSGI規范中,接口與實現的分離是用得最淋漓盡致的。 5).參考spring中的IOC的實現 */ public Map<String, Object> getStockWarrantIV(String ul, String updateDate) { //HashMap<String, Object> ivMap = new HashMap<>(); Map<String, Object> ivMap = new HashMap<>(); try { String key = STOCK_WARRANT_IV_PREFIX + ul; String hashKey = updateDate; ivMap = (HashMap<String, Object>) redisTemplate.boundHashOps(key).get(hashKey); } catch (Exception e) { LOG.error("getStockWarrantIV", e); } return ivMap; }
-
代碼中不要有多余的空行, 無效的注釋,無意義的注釋要刪掉; 注釋要規范, 符合javadoc原則;注釋和日志細節寫清楚,不要出錯誤;變量命名規范,不要存在歧義和沖突;
-
方法命名符號常規英語表達習慣, 能從名字明白方法的作用;
-
調用工具類, 盡量調用已經封裝好的工具類方法,減少自定義工具類方法編碼;
-
判斷字符串非空, 調用StringUtils類中方法, 注意isBlank和isEmpty的區別
1.StringUtils里的isEmpty方法和isBlank方法的區別 isEmpty() public static boolean isEmpty(String str) { return str == null || str.length() == 0; } isBlank() public static boolean isBlank(String str) { int strLen; if (str != null && (strLen = str.length()) != 0) { for(int i = 0; i < strLen; ++i) { // 判斷字符是否為空格、制表符、tab if (!Character.isWhitespace(str.charAt(i))) { return false; } } return true; } else { return true; } } 結論 1).isEmpty 沒有忽略空格參數,是以是否為空和是否存在為判斷依據 2).isBlank 是在 isEmpty 的基礎上進行了為空(字符串都為空格、制表符、tab 的情況)的判斷。(一般更為常用) StringUtils.isEmpty("yyy") = false StringUtils.isEmpty("") = true StringUtils.isEmpty(" ") = false StringUtils.isBlank("yyy") = false StringUtils.isBlank("") = true StringUtils.isBlank(" ") = true
6.處理時間用joda庫中的函數和java8中的時間函數,保證線程安全,避免使用Calendar以及jdk8以前的方法;
7.判斷集合非空, CollectionUtils.isNotEmpty; 判斷Map非空, MapUtils.isNotEmpty; 盡量少用原始方法判斷, 能用工具包盡量用工具包;
8.集合排序, 自然逆序用Comparator.reverseOrder(), 不要用重寫compare方法實現;
9.new的對象不能能為null, 不做為null的判斷, 並且不做無效的new操作, 有賦值就不new;
10.在設計到時間的格式轉換時注意時區的影響, 如下:
//用format會導致時區的錯誤 hkStockRedisDao.setCallOrPullIVsRegion(ul, String.format("%tF", time.toDate()), ivMaps); //考慮時區的影響, 尤其是在設計到不同交易所的情況 hkStockRedisDao.setCallOrPullIVsRegion(ul, TimeUtils.printHkDate(time.getMillis()), ivMaps); public static final DateTimeZone TIMEZONE_HK = DateTimeZone.forID("Asia/Hong_Kong"); private static final DateTimeFormatter COMMON_DATE_FORMAT_HK = DateTimeFormat.forPattern("yyyy-MM-dd") .withZone(TIMEZONE_HK); public static String printHkDate(long timestamp) { return COMMON_DATE_FORMAT_HK.print(timestamp); }
11.在做條件判斷時考慮周全,無效無意義的判斷要減少,沒有必要的else盡量減少, return語句在if, else里盡量減少, 在外面return;
12.在做時間的比較計算時, 用joda庫或者java8中的日期操作方法: 比如判斷時間相差三個月, 用DateTime中的minusMonths函數,考慮11月和2月之間的差
int timeDiff = expireDateTime.minusMonths(3).compareTo(currentDate);
-
無效的import要及時去掉, StringUtils用lang3的;
-
操作數據庫時需要考慮到性能因素, 不能只認結果;
-
異常處理, 強轉需要捕獲異常;
try 塊:用於捕獲異常。其后可接零個或多個catch塊,如果沒有catch塊,則必須跟一個finally塊。 catch 塊:用於處理try捕獲到的異常。 finally 塊:無論是否捕獲或處理異常,finally塊里的語句都會被執行。當在try塊或catch塊中遇到return語句時,finally語句塊將在方法返回之前被執行。在以下4種特殊情況下,finally塊不會被執行: 1)在finally語句塊中發生了異常。 2)在前面的代碼中用了System.exit()退出程序。 3)程序所在的線程死亡。 4)關閉CPU。
-
類型相同的變量直接賦值, 無需在重新new
-
出現太多常量, 需要提取公共常量;
-
分頁時主要默認最小頁大小和最大頁大小, 避免返回全部;
-
常量命名規范, 大寫下划線;
-
方法權限, 類中調用private, 子類調用protected;
-
代碼格式調整option+command+l, "{"前有空格, 語句對齊, 用option+command+l快捷鍵對齊;
-
如果用//注釋, 需要與注釋內容之間有一個空格;
-
相同業務類型, 相同意義用才用可變參數, 可變參數放在最后一個參數;
-
包裝類型的值比較用equals方法, 不用==, 因為java在包裝類型有緩存;
-
構造方法里不加任何業務邏輯, 放在init方法里;
-
只要重寫equals就必須重寫hashCode
-
關於通配符: 泛型通配符<? extends T>來接收返回的數據,此寫法的泛型集合不能使用add方 法,而<? super T>不能使用get方法,做為接口調用賦值時易出錯;PECS(Producer Extends Consumer Super)原則:第一、頻繁往外讀取內 容的,適合用<? extends T>。第二、經常往里插入的,適合用<? super T>;
-
不要在 foreach 循環里進行元素的 remove/add 操作。remove 元素請使用 Iterator 方式,如果並發操作,需要對 Iterator 對象加鎖。
-
集合初始化時,指定集合初始值大小
-
使用 entrySet 遍歷 Map 類集合 KV,而不是 keySet 方式進行遍歷; keySet 其實是遍歷了 2 次,一次是轉為 Iterator 對象,另一次是從 hashMap 中取出 key 所對應的 value。而 entrySet 只是遍歷了一次就把 key 和 value 都放到了 entry 中,效 率更高。如果是 JDK8,使用 Map.foreach 方法。
-
線程池不允許使用 Executors 去創建,而是通過 ThreadPoolExecutor 的方式,這樣 的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險。
-
SimpleDateFormat 是線程不安全的類,一般不要定義為static變量,如果定義為 static,必須加鎖,或者使用 DateUtils 工具類。
注意線程安全,使用 DateUtils。亦推薦如下處理: private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() { @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd"); } }; 如果是 JDK8 的應用,可以使用 Instant 代替 Date,LocalDateTime 代替 Calendar, DateTimeFormatter 代替 SimpleDateFormat,官方給出的解釋:simple beautiful strong immutable thread-safe。
-
public方法傳參注意, 防止調用者調錯
-
if else 考慮清楚, 需要讓看的人覺得邏輯清晰
-
分頁實現, 需要totalPage, pageSize, page三個參數, totalPage和page需要返回給客戶端
-
maven在打包發布前要clean下, 防止本地的target下的classess影響發布后的結果
-
字符串截圖判斷是否越界
stockStat.getNameCN().substring(2, 4);
比較: redisTemplate.boundValueOps(key).get() redisTemplate.opsForValue().get(key);