很早就閱讀過《代碼整潔之道》(英文版Clean Code),當時博主是個青澀的菜鳥,正在爲團隊創造着混亂的代碼。多年的工做中,多次被別人的代碼坑的苦不堪言,回想起當年我留下的代碼,確定也坑害了後來的同僚。當閱讀JDK源碼或者其餘優秀開源工程時,歎服做者代碼構建之精良,他們都有共同的特色:精確的變量名、恰到好處的設計模式、詳細而不贅述的註釋等等。現在重讀本書,總結一下內容並加上本身的一些看法與你們分享。java
工做的溝通,不僅是電子郵件或者面對面語言交流,代碼也是溝通方式之一。用代碼實現需求,只是萬里長征走完了第一步,必須讓代碼表達本身的設計思想。試想一下,你負責的功能被另一個同事接手,若是你的代碼結構清晰、註釋合理,他就不用頻繁的詢問代碼疑點,不用打斷你的工做。編寫代碼的時候,應該考慮到別人的閱讀感覺,減小閱讀障礙,爲整個團隊創造代碼,而不是你本身。程序員
這是美國童子軍規的諺語,美國童子軍至關於半軍事化管理的青少年夏令營。夏令營結束後孩子們離開營地,要打掃衛生保持整潔,讓營地比來時更乾淨。在軟件開發過程當中,能夠理解爲不要破壞規則,不要引入混亂
。若是團隊已經制定了代碼規範,好比類名必須有子系統前綴好比BiOrderService
(Bi指BI業務部門),就繼續遵循下去;再好比,團隊已經提供了公共庫好比MD5的加密,那就不要再次引入新的MD5庫。不少新手程序員接活兒後,看到不喜歡的規範就另起爐竈,須要某些工具類也不詢問老司機公共庫有沒有,直接引入本身熟悉的庫,形成兼容性或者其餘問題。apache
合適的命名是頭等大事,正如給新生兒起個好名字那樣重要。不合適的命名一般是詞不達意、誤導觀衆、過分縮寫
等,因爲英文並不是咱們的母語,找個合適的單詞命名彷佛真的很難。我建議是先把業務弄清楚,組織會議定下經常使用業務領域的單詞,禁止組員各自發明。好比代碼裏使用canteen
表示飯堂,那就不要再發明DinnerHall
,既囉嗦又誤導同僚。設計模式
// 手機號 String phone = 「13421800409」; // 獲取地址 private String getDiZhi(); //修改密碼 private void modifyPassword(String password1 ,String password2)
// 手機號 mobileNo比phone更精確 String mobileNo= 「13421800409」; // 避免英文拼音混雜 private String getAddress(); // 參數的命名要區分意義 private void modifyPassword(String oldPassowrd,String newPassword)
方法有多短小才合適沒有定論,可是長達500行的一個方法,絕對讓閱讀者起殺人之心。過長的方法,讓閱讀者不知道從何看起,看了前面忘記後面。將複雜的方法,拆分紅邏輯相對簡單的短方法。服務器
// 獲取我的信息 private UserDTO getUserDTO(Integer userId) { //獲取基本信息 … 此處寫了10行 //獲取最近的一次訂單信息 … 此處寫了30行 // 獲取錢包餘額、可用優惠券張數等 … 此處寫了30行 return userDTO; }
// 獲取我的信息 private UserDTO getUserDTO(Integer userId) { //獲取基本信息 UserDTO userDTO= getUserBasicInfo(userId); //獲取最近的一次訂單信息 userDTO.setUserLastOrder(getUserLastOrder(userId)); // 獲取錢包、可用優惠券張數等 userDTO.setUserAccount(getUserAccount(userId)); return userDTO; } private UserDTO getUserBasicInfo(Integer userId); private UserLastOrder getUserLastOrder(Integer userId); private UserAccount getUserAccount(Integer userId);
爲何要減小嵌套,難道嵌套看上去不時尚嗎?我曾經看到某位同事的一段代碼嵌套達到9層,他本身再去維護的時候都看暈了。代碼過分嵌套的結果是隻有原做者才能讀懂,接盤俠一臉茫然。框架
// 修改用戶密碼,這個例子只有3層嵌套,很溫柔了 public boolean modifyPassword(Integer userId, String oldPassword, String newPassword) { if (userId != null && StringUtils.isNotBlank(newPassword) && SpringUtils.isNotBlank(oldPassword)) { User user = getUserById(userId); if (user != null) { if (user.getPassword().equals(oldPassword) { return updatePassword(userId, newPassword) } } } }
// 修改用戶密碼 Public Boolean modifyPassword(Integer userId, String oldPassword, String newPassword) { if (userId == null || StringUtils.isBlank(newPassword) || StringUtils.isBlank(oldPassword)) { return false; } User user = getUserById(userId); if(user == null) { return false; } if(!user.getPassword().equals(oldPassword) { return false; } return updatePassword(userId, newPassword); }
正例採用衛語句減小了嵌套,可是並不是全部場景都適合這樣改寫。若是不適合,能夠將關聯性高的邏輯抽取成一個獨立的方法減小嵌套。工具
你們有沒有見過一個超長的方法,從頭至尾被一個try/catch照顧着?博主經歷過的項目中,這種不負責的寫法比比皆是。並不是每行代碼都會拋出錯誤,只要將會拋出錯誤的業務放在一個獨立的方法便可。ui
// 獲取我的信息 private UserDTO getUserDTO(Integer userId) { try { //獲取基本信息 ... 此處寫了10行 //獲取最近的一次訂單信息. ...此處寫了20行 // 獲取錢包、可用優惠券張數等 ...此處寫了20行 }catch (Exception e) { logger.error(e); return null; } } return userDTO; }
// 獲取我的信息 private UserDTO getUserDTO(Integer userId) { //獲取基本信息 UserDTO userDTO= getUserBasicInfo(userId); //獲取最近的一次訂單信息 userDTO.setUserLastOrder(getUserLastOrder(userId)); // 獲取錢包、可用優惠券張數等 userDTO.setUserAccount(getUserAccount(userId)); return userDTO; } private UserDTO getUserBasicInfo(Integer userId); private UserLastOrder getUserLastOrder(Integer userId); private UserAccount getUserAccount(Integer userId){ try{ // TODO } catch ( Exception e) { //TODO } }
若是方法參數將超過3個,建議放在類中包裝起來,不然再增長參數時,因爲語義的強耦合會致使調用方語法錯誤。在後臺管理中的分頁查詢接口,經常會有不少查詢參數,並且有可能增長,封裝起來是最好的。this
// 分頁查詢訂單 6個參數 public Page<Order> queryOrderByPage(Integer current,Integer size,String productName,Integer userId,Date startTime,Date endTime,Bigdecimal minAmount ,Bigdecimal maxAmount) { }
@Getter @Setter public class OrderQueryDTO extends PageDTO { private String productName; private Integer userId; private Date startTime; private Date endTime; private Bigdecimal minAmount ; private Bigdecimal maxAmount; } // 分頁查詢訂單 6個參數 Public Page<Order> queryOrderByPage(OrderQueryDTO orderQueryDTO) { }
Lombok組件經過註解的方式,在編譯時自動爲屬性生成構造器、getter/setter、equals、hashcode、toString方法
舉例以下:
@Setter 註解在類或字段,註解在類時爲全部字段生成setter方法,註解在字段上時只爲該字段生成setter方法。
@Getter 使用方法同上,區別在於生成的是getter方法。
@ToString 註解在類,添加toString方法。
@EqualsAndHashCode 註解在類,生成hashCode和equals方法。
@NoArgsConstructor 註解在類,生成無參的構造方法。
@RequiredArgsConstructor 註解在類,爲類中須要特殊處理的字段生成構造方法,好比final和被@NonNull註解的字段。
@AllArgsConstructor 註解在類,生成包含類中全部字段的構造方法。
@Data 註解在類,生成setter/getter、equals、canEqual、hashCode、toString方法,如爲final屬性,則不會爲該屬性生成setter方法。編碼
Public class Order { private Integer userId; public Integer getUserId() { return userId; } public void setUserId(Integer userId) { return this.userId = userId; } }
@Getter @Setter Public class Order { private Integer userId; }
Apache Commons系列組件給咱們提供了關於字符串、集合、IO操做等工具方法。這些組件是個大寶庫,提供了很多輪子。
組件 | 介紹 |
---|---|
beanUtils | JavaBean進行各類操做,克隆對象、屬性等等 |
codec | 處理經常使用的編碼方法的工具類包,例如DES、SHA一、MD五、Base64等. |
collections | java集合框架操做 |
configuration | java應用程序的配置管理類庫 |
io | io工具的封裝 |
lang | Java基本對象方法的工具類包 如StringUtils、ArrayUtils等等. |
logging | 提供的日誌接口 |
net | 提供了客戶端和服務器端的數據驗證框架 |
例1: 判斷集合是否爲空: CollectionUtils.isEmpty(null): true CollectionUtils.isEmpty(new ArrayList()): true CollectionUtils.isEmpty({a,b}): false 例2: 判斷集合是否不爲空: CollectionUtils.isNotEmpty(null): false CollectionUtils.isNotEmpty(new ArrayList()): false CollectionUtils.isNotEmpty({a,b}): true 例3:2個集合間的操做: 集合a: {1,2,3,3,4,5} 集合b: {3,4,4,5,6,7} CollectionUtils.union(a, b)(並集): {1,2,3,3,4,4,5,6,7} CollectionUtils.intersection(a, b)(交集): {3,4,5} CollectionUtils.disjunction(a, b)(交集的補集): {1,2,3,4,6,7} CollectionUtils.disjunction(b, a)(交集的補集): {1,2,3,4,6,7} CollectionUtils.subtract(a, b)(A與B的差): {1,2,3} CollectionUtils.subtract(b, a)(B與A的差): {4,6,7}