场景:需要初始化常量List和Map,所以一开始代码如下:
/**
* List初始化
*/
public static final List<String> ES_KEY_LIST = new ArrayList(){{
add(ES_KEY_KEY);
add(ES_KEY_COUNT);
add(ES_KEY_TOTAL_ORDER_COUNT);
add(ES_KEY_TOTAL_ENTERPRISE_COUNT);
add(ES_KEY_TOTAL_ENTERPRISE_ACTIVATE_COUNT);
add(ES_KEY_TOTAL_ENTERPRISE_RENEW_COUNT);
add(ES_KEY_TOTAL_ORDER_ACTIVATE_COUNT);
add(ES_KEY_TOTAL_ORDER_RENEW_COUNT);
}};
/**
1. Map初始化
*/
public static final Map<String,String> TOTAL_COMPUTE_MAP = new HashMap(){{
put(ES_KEY_TOTAL_ORDER_ACTIVATE_RATE,ES_FORMULA_TOTAL_ORDER_ACTIVATE_RATE);
put(ES_KEY_TOTAL_ENTERPRISE_ACTIVATE_RATE,ES_FORMULA_TOTAL_ENTERPRISE_ACTIVATE_RATE);
put(ES_KEY_TOTAL_ENTERPRISE_RENEW_RATE,ES_FORMULA_TOTAL_ENTERPRISE_RENEW_RATE);
}};
然后sonar检测报警了…
那么为什么sonar不建议直接初始化List和Map呢?
- 我们使用final修饰变量的目的是避免被修改,对于基本类型、String等普通类型变量用final修饰之后确实不可以被修改,但是List和Map被修饰之后虽然不能使用“=”重新赋值,但是可以使用add、remove、put等方法改变其中的元素,这就违背了我们使用final的初衷了。
- 双括号初始化List,使用的是内部类的语法,这里会有一定的缺陷。参考:双括号初始化(double brace initialization)踩坑记录、为什么不建议使用双括号初始化?
那么怎么修改呢?
/**
* 声明常量List
*/
private static final List<String> ES_KEY_LIST = getEsKeyList();
/**
* 声明常量Map
*/
private static final Map<String,String> TOTAL_COMPUTE_MAP = getTotalComputeMap();
/**
* 初始化常量Map
*/
public static Map<String,String> getTotalComputeMap(){
Map<String,String> map = new HashMap<>();
map.put(ES_KEY_TOTAL_ORDER_ACTIVATE_RATE,ES_FORMULA_TOTAL_ORDER_ACTIVATE_RATE);
map.put(ES_KEY_TOTAL_ENTERPRISE_ACTIVATE_RATE,ES_FORMULA_TOTAL_ENTERPRISE_ACTIVATE_RATE);
map.put(ES_KEY_TOTAL_ENTERPRISE_RENEW_RATE,ES_FORMULA_TOTAL_ENTERPRISE_RENEW_RATE);
return Collections.unmodifiableMap(map);
}
/**
* 初始化常量List
*/
public static List<String> getEsKeyList(){
List<String> list = new ArrayList<>();
list.add(ES_KEY_KEY);
list.add(ES_KEY_COUNT);
list.add(ES_KEY_TOTAL_ORDER_COUNT);
list.add(ES_KEY_TOTAL_ENTERPRISE_COUNT);
list.add(ES_KEY_TOTAL_ENTERPRISE_ACTIVATE_COUNT);
list.add(ES_KEY_TOTAL_ENTERPRISE_RENEW_COUNT);
list.add(ES_KEY_TOTAL_ORDER_ACTIVATE_COUNT);
list.add(ES_KEY_TOTAL_ORDER_RENEW_COUNT);
return Collections.unmodifiableList(list);
}
划重点: Collections.unmodifiableList()/unmodifiableMap()
Collections.unmodifiableList()返回一个"只读"的List,当调用put()方法时,会抛出如下异常:他会报 java.lang.UnsupportedOperationException。
那么Collections.unmodifiableList() 是怎么保证不可修改的呢?
查看源码:
unmodifiableList()
方法会根据判断把List转换成UnmodifiableRandomAccessList
或者UnmodifiableList
。UnmodifiableList
是Collections的内部类,并且UnmodifiableList
继承了UnmodifiableRandomAccessList
。上图中红框圈中的方法,如add()、set()、remove()、addAll()
方法都会抛出UnsupportedOperationException
。从而保证了List不可更改