【Java编程规范】集合篇

  • 【强制】关于hashCode和equals的处理,遵循如下规则: 1) 只要重写equals,就必须重写hashCode。 2) 因为Set存储的是不重复的对象,依据hashCode和equals进行判断,所以Set存储的对象必须重写这两个方法。 3) 如果自定义对象作为Map的键,那么必须重写hashCode和equals。 说明:String重写了hashCode和equals方法,所以我们可以非常愉快地使用String对象作为key来使用。
  • 【强制】不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    List<String> list = new ArrayList<>();
    list.add("1");
    list.add("2");
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
    String item = iterator.next();
    if (删除元素的条件) {
    iterator.remove();
    }
    }


  • 【强制】 在JDK7版本及以上,Comparator实现类要满足如下三个条件,不然Arrays.sort,Collections.sort会报IllegalArgumentException异常。 说明:三个条件如下 1) x,y的比较结果和y,x的比较结果相反。 2) x>y,y>z,则x>z。 3) x=y,则x,z比较结果和y,z比较结果相同。


  • 【推荐】使用entrySet遍历Map类集合KV,而不是keySet方式进行遍历。 说明:keySet其实是遍历了2次,一次是转为Iterator对象,另一次是从hashMap中取出key所对应的value。而entrySet只是遍历了一次就把key和value都放到了entry中,效率更高。如果是JDK8,使用Map.foreach方法。 正例:values()返回的是V值集合,是一个list集合对象;keySet()返回的是K值集合,是一个Set集合对象;entrySet()返回的是K-V值组合集合。

  • 初始化集合时尽量指定其大小
    尽量在初始化时指定集合的大小,能有效减少集合的扩容次数,因为集合每次扩容的时间复杂度很可能时O(n),耗费时间和性能。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //反例:

    //初始化list,往list 中添加元素反例:
    int[] arr = new int[]{1,2,3,4};
    List<Integer> list = new ArrayList<>();
    for (int i : arr){
    list.add(i);
    }
    //正例:

    //初始化list,往list 中添加元素正例:
    int[] arr = new int[]{1,2,3,4};
    //指定集合list 的容量大小
    List<Integer> list = new ArrayList<>(arr.length);
    for (int i : arr){
    list.add(i);
    }
  • 若需频繁调用Collection.contains 方法则使用Set
    在Java 集合类库中,List的contains 方法普遍时间复杂度为O(n),若代码中需要频繁调用contains 方法查找数据则先将集合list 转换成HashSet 实现,将O(n) 的时间复杂度将为O(1)。
  • 使用静态代码块实现赋值静态成员变量
    对于集合类型的静态成员变量,应该使用静态代码块赋值,而不是使用集合实现来赋值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    //反例:
    //赋值静态成员变量反例
    private static Map<String, Integer> map = new HashMap<String, Integer>(){
    {
    map.put("Leo",1);
    map.put("Family-loving",2);
    map.put("Cold on the out side passionate on the inside",3);
    }
    };
    private static List<String> list = new ArrayList<>(){
    {
    list.add("Sagittarius");
    list.add("Charming");
    list.add("Perfectionist");
    }
    };
    //正例:
    //赋值静态成员变量正例
    private static Map<String, Integer> map = new HashMap<String, Integer>();
    static {
    map.put("Leo",1);
    map.put("Family-loving",2);
    map.put("Cold on the out side passionate on the inside",3);
    }

    private static List<String> list = new ArrayList<>();
    static {
    list.add("Sagittarius");
    list.add("Charming");
    list.add("Perfectionist");
    }
  • 静态构造方法的语义和简化程度真的高于直接去 new 一个对象。比如 new 一个 List 对象,过去的使用是这样的:

    List<String> list = new ArrayList<>();


    看一下 Guava 中的创建方式:

    List list = Lists.newArrayList();
    Lists 命名是一种约定(俗话说:约定优于配置),它是指 Lists 是 List 这个类的一个工具类,那么使用 List 的工具类去产生 List,这样的语义是不是要比直接 new 一个子类来的更直接一些呢,答案是肯定的,再比如如果有一个工具类叫做 Maps,那你是否想到了创建 Map 的方法呢:

    HashMap<String, String> objectObjectHashMap = Maps.newHashMap();