java中List踩过的坑

remove

问题

现在的需求是移除集合中指定索引的元素,代码如下:

	@Test
    public void test01() {
        List<Integer> list = Arrays.asList(5, 6, 7, 8, 9);
        Integer index = 0;
        System.out.println(list.remove(index));
    }

一开始看不出有什么问题,要实现的是移除索引为0的元素,但是打印的值却是false。

原因

List中有两个名字为remove方法,他们的参数不同,返回值也不同,源码如下:

/**
 * Removes the element at the specified position in this list (optional
 * operation).  Shifts any subsequent elements to the left (subtracts one
 * from their indices).  Returns the element that was removed from the
 * list.
 *
 * @param index the index of the element to be removed
 * @return the element previously at the specified position
 * @throws UnsupportedOperationException if the <tt>remove</tt> operation
 *         is not supported by this list
 * @throws IndexOutOfBoundsException if the index is out of range
 *         (<tt>index &lt; 0 || index &gt;= size()</tt>)
 */
E remove(int index);
/**
 * Removes the first occurrence of the specified element from this list,
 * if it is present (optional operation).  If this list does not contain
 * the element, it is unchanged.  More formally, removes the element with
 * the lowest index <tt>i</tt> such that
 * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
 * (if such an element exists).  Returns <tt>true</tt> if this list
 * contained the specified element (or equivalently, if this list changed
 * as a result of the call).
 *
 * @param o element to be removed from this list, if present
 * @return <tt>true</tt> if this list contained the specified element
 * @throws ClassCastException if the type of the specified element
 *         is incompatible with this list
 * (<a href="Collection.html#optional-restrictions">optional</a>)
 * @throws NullPointerException if the specified element is null and this
 *         list does not permit null elements
 * (<a href="Collection.html#optional-restrictions">optional</a>)
 * @throws UnsupportedOperationException if the <tt>remove</tt> operation
 *         is not supported by this list
 */
boolean remove(Object o);

可见当传递的参数为引用类型的时候,调用的是第二个remove方法,在上面的问题中,实际上是去集合中找0对应的Integer对象,显然找不到,返回false。

Arrays.asList

Arrays.asList()方法的第一个作用是将数组转化为集合:

public static void main(String[] args) {
    String[] strs = {
            "java",
            "python",
            "c#",
            "golang"
    };
    List<String> strList = Arrays.asList(strs);
    System.out.println(strList);
}

运行结果:
运行结果
但是应该注意的是 asList() 的参数为泛型的变长参数,不能使用基本类型数组作为参数,只能使用相应的包装类型数组。

public static void main(String[] args) {
    int[] intArr = {1, 2, 3, 4, 5};
    List<int[]> list1 = Arrays.asList(intArr);
    list1.forEach(arr -> System.out.println(Arrays.toString(arr)));
    Integer[] intArr2 = {1, 2, 3, 4, 5};
    List<Integer> list2 = Arrays.asList(intArr2);
    System.out.println(list2);
}

运行结果:
运行结果
可见,如果使用基本类型数组作为参数的话,asList会把参数整体当成集合中的一个元素。
当我们想要快速构建一个集合的时候,我们可以这样写:

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    System.out.println(list); // [1, 2, 3, 4, 5]
}

当传入两个数组的时候:

public static void main(String[] args) {
    List<String[]> list2 = Arrays.asList(new String[]{"java", "python"}, new String[]{"golang", "javascript"});
    System.out.println(list2); // [[Ljava.lang.String;@2b193f2d, [Ljava.lang.String;@355da254]
}

另外就是,在这个集合中添加元素会发生UnsupportedOperationException异常:

public static void main(String[] args) {
    List<String> list = Arrays.asList("1", "2");
    list.add("3");
}

因为Arrays.asList函数返回的集合虽然名字叫做ArrayList但是,实际上它是一个内部类,并不是真正的ArrayList,使用这个内部类的时候,需要注意:

  • 该类不支持增删
  • 修改该类的元素,会影响原数组
public static void main(String[] args) {
    Integer[] arr = {1, 2, 3, 4};
    List<Integer> list = Arrays.asList(arr);
    arr[0] = 100;
    list.set(1, 200);
    System.out.println(list); // [100, 200, 3, 4]
    System.out.println(Arrays.toString(arr)); // [100, 200, 3, 4]
}

解决方法:外层嵌套一个new ArrayList()

public static void main(String[] args) {
    Integer[] arr = {1, 2, 3, 4};
    List<Integer> list = new ArrayList<>(Arrays.asList(arr));
    arr[0] = 100;
    list.set(1, 200);
    System.out.println(list); // [1, 200, 3, 4]
    System.out.println(Arrays.toString(arr)); // [100, 2, 3, 4]
}

foreach

使用foreach遍历的时候不能删除

public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    list.add("1");
    list.add("2");
    list.add("3");
    for (String s : list) {
        if ("1".equals(s)) {
            list.remove("1");
        }
    }
    // Exception in thread "main" java.util.ConcurrentModificationException
}

详细原因可参考:https://juejin.im/post/5e74413cf265da574c569935

解决方法:

1、使用迭代器删除

public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    list.add("1");
    list.add("2");
    list.add("3");
    Iterator<String> iter = list.iterator();
    while (iter.hasNext()){
        if ("1".equals(iter.next())){
            iter.remove();
        }
    }
    System.out.println(list); // [2, 3]
}

2、使用Java8中的removeIf

public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    list.add("1");
    list.add("2");
    list.add("3");
    list.removeIf("1"::equals);
    System.out.println(list); // [2, 3]
}

subList

subList分割后的集合和原集合地址相同

public static void main(String[] args) {
    ArrayList<String> l1 = new ArrayList<>();
    l1.add("1");
    l1.add("2");
    l1.add("3");
    List<String> l2 = l1.subList(0, 1);
    l1.set(0, "100");
    System.out.println(l1); // [100, 2, 3]
    System.out.println(l2); // [100]
}

参考文章:https://mp.weixin.qq.com/s/0kBhhsfb2NBVrgauzUCoLg

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值