1. 程式人生 > >阿里巴巴Java開發手冊要點筆記 (一)

阿里巴巴Java開發手冊要點筆記 (一)

1:【強制】Object 的 equals 方法容易拋空指標異常,應使用常量或確定有值的物件來呼叫 equals。

正例:"test".equals(object);

反例:object.equals("test");

說明:推薦使用 java.util.Objects#equals(JDK7 引入的工具類)。其就是例項物件equals的一個健壯版本

實現:

複製程式碼
    /**
     * Returns {@code true} if the arguments are equal to each other
     * and {@code false} otherwise.
     * Consequently, if both arguments are {
@code null}, {@code true} * is returned and if exactly one argument is {@code null}, {@code * false} is returned. Otherwise, equality is determined by using * the {@link Object#equals equals} method of the first * argument. * * @param a an object * @param b an object to be compared with {
@code a} for equality * @return {@code true} if the arguments are equal to each other * and {@code false} otherwise * @see Object#equals(Object) */ public static boolean equals(Object a, Object b) { // 可以巧妙避開空指標異常。首先判斷a==b,在判斷a!=null,如果a==null的話此時a.equals(b)短路 return
(a == b) || (a != null && a.equals(b)); }
複製程式碼

2:java.util.Objects.deepEquals(Object, Object)方法講解分析,原始碼如下:

複製程式碼
   /**
    * Returns {@code true} if the arguments are deeply equal to each other
    * and {@code false} otherwise.
    *
    * Two {@code null} values are deeply equal.  If both arguments are
    * arrays, the algorithm in {@link Arrays#deepEquals(Object[],
    * Object[]) Arrays.deepEquals} is used to determine equality.
    * Otherwise, equality is determined by using the {@link
    * Object#equals equals} method of the first argument.
    *
    * @param a an object
    * @param b an object to be compared with {@code a} for deep equality
    * @return {@code true} if the arguments are deeply equal to each other
    * and {@code false} otherwise
    * @see Arrays#deepEquals(Object[], Object[])
    * @see Objects#equals(Object, Object)
    */
    public static boolean deepEquals(Object a, Object b) {
        if (a == b)
            return true;
        else if (a == null || b == null)
            return false;
        else
            return Arrays.deepEquals0(a, b);
    }
複製程式碼

java.util.Arrays.deepEquals0(Object, Object)原始碼如下:

複製程式碼
   static boolean deepEquals0(Object e1, Object e2) {
        assert e1 != null;
        boolean eq;
     // 如下的equals是Arrays中的equals方法,是對每一個元素進行比較
if (e1 instanceof Object[] && e2 instanceof Object[]) eq = deepEquals ((Object[]) e1, (Object[]) e2); else if (e1 instanceof byte[] && e2 instanceof byte[]) eq = equals((byte[]) e1, (byte[]) e2); else if (e1 instanceof short[] && e2 instanceof short[]) eq = equals((short[]) e1, (short[]) e2); else if (e1 instanceof int[] && e2 instanceof int[]) eq = equals((int[]) e1, (int[]) e2); else if (e1 instanceof long[] && e2 instanceof long[]) eq = equals((long[]) e1, (long[]) e2); else if (e1 instanceof char[] && e2 instanceof char[]) eq = equals((char[]) e1, (char[]) e2); else if (e1 instanceof float[] && e2 instanceof float[]) eq = equals((float[]) e1, (float[]) e2); else if (e1 instanceof double[] && e2 instanceof double[]) eq = equals((double[]) e1, (double[]) e2); else if (e1 instanceof boolean[] && e2 instanceof boolean[]) eq = equals((boolean[]) e1, (boolean[]) e2); else eq = e1.equals(e2); return eq; }
複製程式碼

java.util.Arrays.equals(char[], char[])原始碼如下:

複製程式碼
/**
     * Returns <tt>true</tt> if the two specified arrays of chars are
     * <i>equal</i> to one another.  Two arrays are considered equal if both
     * arrays contain the same number of elements, and all corresponding pairs
     * of elements in the two arrays are equal.  In other words, two arrays
     * are equal if they contain the same elements in the same order.  Also,
     * two array references are considered equal if both are <tt>null</tt>.<p>
     *
     * @param a one array to be tested for equality
     * @param a2 the other array to be tested for equality
     * @return <tt>true</tt> if the two arrays are equal
     */
    public static boolean equals(char[] a, char[] a2) {
        if (a==a2)
            return true;
        if (a==null || a2==null)
            return false;

        int length = a.length;
        if (a2.length != length)
            return false;

        for (int i=0; i<length; i++)
            if (a[i] != a2[i])
                return false;

        return true;
    }
複製程式碼

示例1:對於基本型別的陣列,元素相同,使用Objects的equals方法判定是false,但是對於deepEquals方法是對底層每一個元素呼叫其equals判斷是否相等。

        int[] a = { 1, 2, 3, 4, 5 };
        int[] b = { 1, 2, 3, 4, 5 };
        // 陣列的equals方法其實就是直接判斷引用是否相等,不會具體判斷每一個元素
        System.out.println(Objects.equals(a, b)); // false
        System.out.println(Objects.deepEquals(a, b)); // true

示例2:

實體類User,此版本實現了HashCode和equals方法

複製程式碼
class User {
    public String userName;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((userName == null) ? 0 : userName.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        User other = (User) obj;
        if (userName == null) {
            if (other.userName != null)
                return false;
        } else if (!userName.equals(other.userName))
            return false;
        return true;
    }

    public User(String userName) {
        super();
        this.userName = userName;
    }

    public User() {
        super();
        // TODO Auto-generated constructor stub
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

}
複製程式碼

此時:

        User[] u1 = { new User("daxin"), new User("mali") };
        User[] u2 = { new User("daxin"), new User("mali") };
        System.out.println(Objects.equals(u1, u2)); //false
        System.out.println(Objects.deepEquals(u1, u2)); //true,呼叫的User自己實現的equals方法

示例3:沒有實現hashcode和equals方法的User:

複製程式碼
class User {
    public String userName;

    public User(String userName) {
        super();
        this.userName = userName;
    }

    public User() {
        super();
        // TODO Auto-generated constructor stub
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

}
複製程式碼

此時:

        User[] u1 = { new User("daxin"), new User("mali") };
        User[] u2 = { new User("daxin"), new User("mali") };
        System.out.println(Objects.equals(u1, u2)); //false
        System.out.println(Objects.deepEquals(u1, u2)); //false,對底層每一個元素呼叫預設的equals方法(此時equals方法判定的是引用)

3:【強制】所有的相同型別的包裝類物件之間值的比較,全部使用 equals 方法比較。 說明:對於 Integer var = ? 在-128 至 127 範圍內的賦值,Integer 物件是在IntegerCache.cache 產生,會複用已有物件,這個區間內的 Integer 值可以直接使用==進行 判斷,但是這個區間之外的所有資料,都會在堆上產生,並不會複用已有物件,這是一個大坑, 推薦使用 equals 方法進行判斷。

示例:

複製程式碼
       Integer a=12;
        Integer b=12;
        System.out.println(a==b);//true
        Integer c=1550;
        Integer d=1550;
        System.out.println(c==d);//false
        System.out.println(c.intValue()==d);//對c進行拆箱,所以導致d也拆箱。所以true
        System.out.println(c==d.intValue());//對d進行拆箱,所以導致c也拆箱。所以true
        System.out.println(c.intValue()==d.intValue());//都拆箱
        System.out.println(Objects.equals(c, d));//使用Objects的equals方法比較
複製程式碼

4:【推薦】使用索引訪問用 String 的 split 方法得到的陣列時,需做最後一個分隔符後有無 內容的檢查,否則會有拋 IndexOutOfBoundsException 的風險。

說明:

String str = "a,b,c,,";
String[] ary = str.split(",");
// 預期大於 3,結果是 3
System.out.println(ary.length);

又如:

System.out.println(",,,,".split(",").length); //0

5:【強制】ArrayList的subList結果不可強轉成ArrayList,否則會丟擲ClassCastException 異常,即 java.util.RandomAccessSubList cannot be cast to java.util.ArrayList. 說明:subList 返回的是 ArrayList 的內部類 SubList,並不是 ArrayList ,而是 ArrayList 的一個檢視,對於 SubList 子列表的所有操作最終會反映到原列表上。

複製程式碼
        List<Integer> list =new ArrayList<>();
        list.add(1);
        list.add(2);
        List<Integer> subList = list.subList(0, list.size());
        System.out.println(subList);//[1, 2]
        subList.add(3); //對subList操作反映在list上
        System.out.println(list);//[1, 2, 3]
複製程式碼