在编码中,经常使用到各种集合常量,比如List(列表)常量、Set(集合)常量、Map(映射)常量等。
普通方式一般这样写:
public static final List CONST_VALUE_LIST = Arrays.asList(1,2,3);
public static final Set CONST_VALUE_SET = new HashSet<>(Arrays.asList(1,2,3));
public static final Map CONST_VALUES_MAP;
static {
CONST_VALUES_MAP = new HashMap<>();
CONST_VALUES_MAP.put(1,"a");
CONST_VALUES_MAP.put(2,"b");
}
问题:
由于普通的集合对象(如ArrayList、HashMap、HashSet等)都是可变集合对象,即便是定义为静态常量,
也可以通过操作方法进行修改。所以,上面方法定义的集合常量,并不是真正意义上的集合常量。
其中,Arrays.asList方法生成的内部ArrayList不能执行add/remove/clear方法,但是可以执行set方法,也属于可变集合对象。
注:
博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主
最佳方式使用如下
在JDK中,Collections工具类中提供一套方法,用于把可变集合对象变为不可变
(不可修改,修改时会抛出UnsupportedOperationException异常)集合对象。所以,可以利用这套方法定义集合静态常量。
public static final List CONST_VALUE_LIST_2 = Collections.unmodifiableList(Arrays.asList(1,2,3));
public static final Set CONST_VALUE_SET_2 = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(1,2,3)));
public static final Map CONST_VALUE_MAP_2;
static {
CONST_VALUE_MAP_2 = Collections.unmodifiableMap(new HashMap(){{
put(1,"a");
put(2,"b");
}});
}
一般定义数组常量,会像下面代码一样,定义一个公有数组常量
public static final int[] CONST_ARRAY = new int[]{1,2,3};
但是,可以通过下标修改数组值,导致数组常量的值可变。所以,这种方法定义的数组常量,并不是一个真正意义上的数组常量。
最佳法“私有数组常量+公有克隆方法”的解决方案。
如下代码所示:先定义一个私有数组常量,保证不会被外部类使用;在定义一个获取数组常量方法,并返回一个数组常量的克隆值。
private static final int[] CONST_ARRAY_2 = new int[]{1,2,3};
public static int[] getConstArray2(){
return CONST_ARRAY_2.clone();
}
由于每次返回的是一个克隆数组,即便修改了克隆数组的常量值,也不会导致原始数组常量值的修改。