List和数组使用过程中的常见的坑
1.从整型值List中删除等于某个值的元素,应当先转型
删除指定索引的元素int remove(int index)和删除某个元素int remove(Object e)都可以用于从List中删除指定的元素。
对于整型值List,如果我们想要从中删除掉某个值:
// 删除掉entry中值等于target的元素
LinkedList<Integer> entry = new LinekdList<>();
entry.add(1);
entry.add(10);
entry.add(100);
int target = 100;
entry.remove(target);
将会报错IndexOutOfBounds,因为java仅当没有可以在没有强制/自动装箱的情况下调用的方法时,才会执行自动装箱和隐式向上转换。在上面的代码中优先调用的是remove(int index)方法,而entry中没有index等于100的元素。
如果想要从该List中删除值等于target的元素,正确的做法应该为:
entry.remove((Integer)target);
或
entry.remove(Integer.valueOf(target));
2.创建泛型数组不能直接用new操作符
在创建ArrayList的数组时,使用
public static ArrayList<myObject>[] a = new ArrayList<myObject>[2];
会报错 Generic array creation。Java不支持直接用new操作符创建带泛型的数组,必须强制转型,例如:
@SuppressWarnings("unchecked")
public static ArrayList<myObject>[] a = (ArrayList<myObject>[])new ArrayList<?>[2];
(更多内容请参考:
https://stackoverflow.com/questions/7131652/generic-array-creation-error/23034391
https://www.liaoxuefeng.com/wiki/1252599548343744/1265105940850016)
3.List和数组之间的相互转换
3.1 List转换为数组最好不要直接用toArray方法
通过for循环遍历将List转换为数组,可以将list的元素依次加入数组中;但是这样的话,代码会很长,使用List的toArray()方法似乎是更明智的选择:
List<String> stringList = new ArrayList<>(){{add("a"); add("b"); add("c");}};
String[] strings = (String[]) stringList.toArray();
然而,这样会直接报java.lang.ClassCastException。这是因为直接调用toArray()方法返回的是Object[],而Object[]是无法直接向下转型为String[]的。
更合适的方法应该是使用List的toArray(T[])方法:
String[] strings = stringList.toArray(new String[stringList.size()]);
这种写法可以进一步简化为List接口定义的T[] toArray(IntFunction<T[]> generator)方法:
String[] strings = stringList.toArray(String[]::new);
然而,峰回路转,这个办法依然埋着一个深不见底的坑。如果我们对于int[]和Integer列表进行转换的话:
List<Integer> numList = new ArrayList<>(){{add(1); add(2); add(3);}}
int[] nums = (int[]) numList.toArray(new int[numList.size()]);
很可惜,还是会报错,因为toArray(T[])中的泛型类型int与List的泛型类型Integer不匹配。只能写成如下的格式:
Integer[] nums = (Integer[]) numList.toArray(new Integer[numList.size()]);
那如果一定要求转换为int[]而不是Integer[]该怎么办呢?聪明的同学们可能会想到:
int[] nums = numList.stream().mapToInt(Integer::intValue).toArray();
这种写法倒确实可以行得通。可惜的是执行这一行代码的耗时远远超过了通过for循环将List转化为数组的时间。看来将List转化为int数组,只能老老实实通过for循环实现了。
3.2 数组转换为List最好不要直接用asList方法
同样,可以使用for循环,但是有没有更简洁的办法呢?不难想到Arrays类的asList()方法或者List的ofList方法:
List<String> stringList1 = strings.asList();
List<String> stringList2 = List.ofList(strings);
然而,用上面两个方法返回的List对象都是只读List,只读List调用add()、remove()方法会抛出UnsupportedOperationException。
因此,推荐使用以下方法:
ArrayList<String> stringList3 = new ArrayList<String>(Arrays.asList(strings));
或者:
List<String> stringList4 = new ArrayList<String>(strings.length);
Collections.addAll(stringList4, strings);