發現JDK的3個bug

1.Annotation引用非空enum數組返回空數組

首次發現時的環境:JDK 1.8

首次發現所在項目:APIJSON

測試用例:

public enum RequestRole {

	/**未登錄,不明身份的用戶
	 */
	UNKNOWN,

	/**已登錄的用戶
	 */
	LOGIN,

	/**聯繫人,必須已登錄
	 */
	CONTACT,

	/**圈子成員(CONTACT + OWNER),必須已登錄
	 */
	CIRCLE,

	/**擁有者,必須已登錄
	 */
	OWNER,

	/**管理員,必須已登錄
	 */
	ADMIN;

	//似乎不管怎麼做,外部引用後都是空值。並且如果在註解內的位置不是最前的,還會導致被註解的類在其它類中import報錯。
	//雖然直接打印顯示正常,但被@MethodAccess內RequestRole[] GET()等方法引用後獲取的是空值
	public static final RequestRole[] ALL = {RequestRole.UNKNOWN};//values();//所有
	public static final RequestRole[] HIGHS;//高級
	static {
		HIGHS = new RequestRole[] {OWNER, ADMIN};
	}

	public static final String[] NAMES = {
			UNKNOWN.name(), LOGIN.name(), CONTACT.name(), CIRCLE.name(), OWNER.name(), ADMIN.name()
	};


}


@MethodAccess(
		GETS = RequestRole.ALL,
		HEADS = RequestRole.HIGHS
		)
public class Verify {

}


public class DemoVerifier {
	// <TableName, <METHOD, allowRoles>>
	// <User, <GET, [OWNER, ADMIN]>>
    public static final Map<String, Map<RequestMethod, RequestRole[]>> ACCESS_MAP;
	static { //註冊權限
        ACCESS_MAP = new HashMap<String, Map<RequestMethod, RequestRole[]>>();
		ACCESS_MAP.put(Verify.class.getSimpleName(), getAccessMap(Verify.class.getAnnotation(MethodAccess.class)));
	}

	public static HashMap<RequestMethod, RequestRole[]> getAccessMap(MethodAccess access) {
		if (access == null) {
			return null;
		}

		HashMap<RequestMethod, RequestRole[]> map = new HashMap<>();
		map.put(GET, access.GET());
		map.put(HEAD, access.HEAD());
		map.put(GETS, access.GETS());
		map.put(HEADS, access.HEADS());
		map.put(POST, access.POST());
		map.put(PUT, access.PUT());
		map.put(DELETE, access.DELETE());

		return map;
	}

}

解決方案:

不抽象數組常量ALL,HIGHTS等,而是在每個用到的地方硬編碼寫死具體的值。

 

2.ArrayList可通過構造函數傳入非指定泛型的List並在get時出錯

首次發現時的環境:JDK 1.7

首次發現所在項目:APIJSON

測試用例:

JSONArray arr = new JSONArray(); //com.alibaba.fastjson.JSONArray
arr.add("s");

List<Long> list = new ArrayList<>(arr); 
list.get(0); //throw new IllegalArgumentException

解決方案:

1.改用 Open JDK8

2.升級 JDK

注:後面多次測試,已無法復現。

 

3.基本類型在三元表達式內可賦值爲null,編譯通過但運行出錯

首次發現時的環境: JDK 1.7

測試用例:

int i = true ? null : 0; //Exception in thread "main" java.lang.NullPointerException

首次發現所在項目:ZBLibrary

解決方案:

在給基礎類型用3元表達式賦值時,null 先轉爲基礎類型的默認值。

 

最後再提2個不是bug,但容易引發編程bug的問題:

1.局部變量和同名的全局變量能在一個方法內,編譯通過,運行也正常。

    public class Test {
        
        int val;
        @Override
        public String toString() {
            val = 1;
            String val = "";
            return super.toString();
        }
    }

如果兩個變量中間隔了比較長的其它代碼,很可能會導致開發人員將兩者混淆,導致邏輯認知錯誤,從而寫出或改出有問題的代碼。

解決方案:

命名局部變量前先搜素,確保沒有已聲明的同名全局變量。

 

2. (非 JDK bug)Gson 通過 TypeToken 轉換 List<T> 能寫入不屬於 T 類型的數據,get 出來賦值給 T 類型的變量/常量報錯。


        String json = "[1, '2', 'a']";
        Type type = new TypeToken<Integer>(){}.getType();
        Gson gson = new Gson();
        List<Integer> list = gson.fromJson(json, type);
        
        Integer i = list == null || list.isEmpty() ? null : list.get(1); //Exception cannot cast String to Integer

解決方案:

1.手動檢查列表內數據都符合泛型 T

2.改用 fastjson 等其它能靜態檢查類型的庫。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章