阿里Java開發手冊思考(一)

舊時王謝堂前燕, 飛入尋常百姓家。 小編將帶大家一塊兒分析阿里巴巴Java開發手冊!java

背景

阿里巴巴Java開發手冊是阿里巴巴集團技術團隊的集體智慧結晶和經驗總結,以Java開發者爲中心視角,劃分爲編程規約、異常日誌、單元測試、安全規約、工程結構、MySQL數據庫六個維度。手冊的願景是碼出高效、碼出質量、效率優先、質量爲本。數據庫

目的

之因此要寫這個系列的文章,首先是學習與總結,其次是思考與理解,更是分享與交流,手冊中的每一條每一項都有其背後隱藏的原理與經驗,咱們看到的只是冰山一角,深刻挖掘其背後的知識有益於更深入的理解,並在本身實際編程中提升本身的基本技術素養。編程

主題

  • 【推薦】表達異常的分支時,少用 if-else 方式,這種方式能夠改寫成:
if (condition) { 
    ...
    return obj; 
}
// 接着寫 else 的業務邏輯代碼;
複製代碼

說明:若是非得使用 if()...else if()...else...方式表達邏輯,【強制】避免後續代碼維 護困難,請勿超過 3 層。 正例:超過 3 層的 if-else 的邏輯判斷代碼可使用衛語句、策略模式、狀態模式等來實現, 其中衛語句示例以下:安全

public void today() { 
    if (isBusy()) {
        System.out.println(「change time.」); return;
    }
    if (isFree()) {
        System.out.println(「go to travel.」);
        return; 
    }
    System.out.println(「stay at home to learn Alibaba Java Coding Guidelines.」);
    return; 
}
複製代碼

咱們試圖經過例子來分析下上面的規則,在分析以前,咱們先明確在Java裏,默認的equals和hashCode方法的實現,以及把一個元素放入散列集合(HashSet、HashMap等)時,散列集合對equals和hashCode方法的斷定規則。 Java對象中默認的equals(Object obj)方法用來判斷兩個對象是否「相同」,若是「相同」則返回true,不然返回false。hashCode()方法返回一個int數,這個整數值是將該對象的內部地址轉換成一個整數返回的 。 在散列集合中存儲一個對象時,先進行hashCode的比較,若是hashCode不相等,則直接放入,不然繼續進行equals的比較,equals不相等才放入,equals相等就直接丟棄了。微信

理解

  • 若是隻重寫equals而不重寫hashCode會致使什麼問題?
package com.test;
import java.util.HashSet;
import java.util.Set;
public class OverrideEqualsTest {    
    public static void main(String[] args) {
        Set<Point> set = new HashSet<Point>();
        Point p1 = new Point(1, 1);
        Point p2 = new Point(1, 1);
        System.out.println("p1.equals(p2):" + p1.equals(p2));
        set.add(p1);
        set.add(p2);
        set.add(p1);
        System.out.println("set.size():" + set.size());        
        for (Point p : set) {
            System.out.println(p);
        }
    }    
    static class Point {        
        private int x;        
        private int y;        
        public Point(int x, int y) {            
            super();            
            this.x = x;            
            this.y = y;
        }        
        @Override
        public boolean equals(Object obj) {            
            if (this == obj) {              
                return true;  
            }          
            if (obj == null) {                
                return false; 
            }           
            if (getClass() != obj.getClass()) {                
                return false;
            }
            Point other = (Point) obj;            
            if (x != other.x) {                
                return false;  
            }          
            if (y != other.y) {               
                return false;  
            }          
            return true;
        }        
        @Override
        public String toString() {            
            return "Point [x=" + x + ", y=" + y + "]";
        }
    }
}
複製代碼

運行結果: p1.equals(p2):true set.size():2 Point[x=1,y=1] Point[x=1,y=1]ide

分析:因爲沒有重寫hashCode方法,p1和p2對象默認的hashCode方法返回的兩個對象地址轉換的整數確定不一樣,因此p1和p2均可以放入set中,因此這並非咱們指望的結果。單元測試

  • ​若是隻重寫hashCode而不重寫equals又會致使什麼問題?
package com.test;
import java.util.HashSet;
import java.util.Set;
public class OverrideHashCodeTest {    
    public static void main(String[] args) {
        Set<Point> set = new HashSet<Point>();
        Point p1 = new Point(1, 1);
        Point p2 = new Point(1, 1);
        System.out.println("p1.equals(p2):" + p1.equals(p2));
        set.add(p1);
        set.add(p2);
        set.add(p1);
        System.out.println("set.size():" + set.size());        
        for (Point p : set) {
            System.out.println(p);
        }
    }    
    static class Point {        
        private int x;        
        private int y;        
        public Point(int x, int y) {            
            super();            
            this.x = x;            
            this.y = y;
        }        
        @Override
        public int hashCode() {            
            final int prime = 3L;            
            int result = 1;
            result = prime * result + x;
            result = prime * result + y;            
            return result;
        }        
        @Override
        public String toString() {            
            return "Point [x=" + x + ", y=" + y + "]";
        }
    }
}
複製代碼

運行結果: p1.equals(p2):false set.size():2 Point[x=1,y=1] Point[x=1,y=1]學習

分析:因爲沒有重寫equals方法,p1和p2對象的默認的equals方法經過「==」來比較,而p1和p2是兩個不一樣的對象,因此p1和p2均可以放入set中,因此這也不是咱們指望的結果。 因此綜上,當咱們同時重寫equals和hashCode方法後,才能在散列集合操做中獲得一致性的結果。測試

  • 對象放入散列集合後,又修改了影響hashCode的值,後果?
package com.test;
public class Test {    
    public static void main(String[] args) {
        Point p1 = new Point(1, 1);
        Point p2 = new Point(2, 2);
        set.add(p1);
        set.add(p2);
        System.out.println("set.size():" + set.size());
        p2.setY(3);
        set.remove(p1);
        set.remove(p2);
        System.out.println("set.size():" + set.size());
    }
}
複製代碼

運行結果: set.size():2 set.size():1ui

分析:因爲在執行期間,修改了p2對象的y值,致使p2對象的hashCode返回值有變化,因此hashset的remove方法將找不到新的hashCode所映射的對象,致使內存泄漏。

微信公衆號: 碼上論劍
請關注個人我的技術微信公衆號,訂閱更多內容
相關文章
相關標籤/搜索