跳至主要內容

List

chanchaw大约 2 分钟languagejava

不使用Arrays.asList

出错演示

看下面的代码,说明正常声明的 ArrayList 是可以无限 add 元素的,但是通过 Arrays.asList 创建 List 对象后再次 add 元素会报错。 Arrays.asList01

原理

Arrays.asList 创建的 List 并不是 java.util.ArrayList 而是 java.util.Arrays.ArrayList。后者拥有前者的大部分属性、方法,但是没有 add、remove 方法。

基本数据类型数组

public static void main(String[] args) {
        asList01();
        asList02();
    }

public static void asList01(){
    int[] iarr = {1,2,3};
    List<int[]> ints = Arrays.asList(iarr);
    // 预期 list 的元素个数应该是3个
    // 元素数量:1,打印结果:[[I@26a1ab54]
    System.out.println("元素数量:" + ints.size() + ",打印结果:" + ints.toString());
}

public static void asList02(){
    Integer[] iarr = {1,2,3};
    List<Integer> integers = Arrays.asList(iarr);
    // 如果使用包装类型就没有问题
    // 元素数量:3,打印结果:[1, 2, 3]
    System.out.println("元素数量:" + integers.size() + ",打印结果:" + integers.toString());
}

// 还有种解决方法是将基本数据类型转换为包装类型 - 下面是用 boxed
public static void asList03(){
    int[] iarr = {1,2,3};
    List<Integer> collect = Arrays.stream(iarr).boxed().collect(Collectors.toList());
    // 元素数量:3,打印结果:[1, 2, 3]
    System.out.println("元素数量:" + collect.size() + ",打印结果:" + collect.toString());
}

迭代器删除元素

list 中要删除 null 不可 list.remove(null),要采用迭代器删除

public <T> List<T> removeNull(List<T> list){
    if(list == null) return list;
    if(list.size() == 0) return list;

    Iterator<T> it = list.iterator();
    while(it.hasNext()){
        T obj = it.next();
        if(obj == null) it.remove();
    }
    return list;
}

List 和 Set

List

  • 有序可重复,允许多个 null

  • 可使用 Iterator 获取元素,也可以使用 get 传入索引

    Set

  • 无序,不可重复,只允许一个 null

  • 只能通过迭代器 Iterator 进行遍历

转换 Map

public static void main(String[] args) {
    List<BillCode> list = new ArrayList<>();
    BillCode b1 = new BillCode();
    b1.setIid(100);
    b1.setSid("采购入库");

    BillCode b2 = new BillCode();
    b2.setIid(100);
    b2.setSid("采购退货");

    BillCode b3 = new BillCode();
    b3.setIid(101);
    b3.setSid("车间领料单");

    list.add(b1);list.add(b2);list.add(b3);

    // (k1,k2)->k1 表示保留重复key中第一次出现的对象,这里是保留“采购入库”
    // 相反 (k1,k2)->k2 则表示保留重复 key 中第二次出现的对象
    Map<Integer,BillCode> ret = list.stream().collect(Collectors.toMap(a->a.getIid(),a->a,(k1,k2)->k1));
    System.out.println(ret);

}

ArrayList 和 LinkedList

ArrayList

  • 基于动态数组、连续内存、适合下标访问
  • 扩容机制 超出初始容量会产生数组复制,如果在中间插入会出现元素移动
  • 在初始容量范围内,使用尾插法性能好,甚至超过 LinkedList

LinkedList

  • 基于链表,分散在内存中,适合做插入、删除操作,不适合查询
  • 不要使用 for 循环,而要使用迭代器 Iterator。前者的每次循环中都会通过 get(i) 对 list 重新遍历,性能消耗大。
  • 不要使用 indexOf 返回元素索引,会对 list 遍历,当结果为空时会导致遍历整个表