Java集合的10个最常见问题

以下是一些在Stackoverflow上经常被问起的与Java集合相关的问题。在你查阅这些问题之前,最好先去看看【Simple Java】Java集合框架的接口和类层次关系结构图

什么时候优先选择LinkedList,而不是ArrayList

ArrayList本质上是一个数组,它的元素可以直接通过索引访问。但是,当数组满的时候,需要申请新的更大的数组空间,并将所有元素复制到新数组中,这将花费O(n)的时间。另外,插入和删除元素需要移动数组中的其它元素,这也许是ArrayList最大的劣势。

LinkedList是一个双向链表,因此,当访问链表中间的元素的时候,它需要从链表的头结点处开始搜索。但好的一方面是,对于插入和删除操作,LinkedList相对更快,因为它只需要改变链表的局部位置。

总的来说,在最差情况下,两者的时间复杂度比较如下:

| Arraylist | LinkedList ------------------------------------------ get(index) | O(1) | O(n) add(E) | O(n) | O(1) add(E, index) | O(n) | O(n) remove(index) | O(n) | O(n) Iterator.remove() | O(n) | O(1) Iterator.add(E) | O(n) | O(1)

除了运行时间外,内存空间的使用也应该被考虑,特别是对于大的列表。在LinkedList中,每个节点需要两个额外的指针指向前节点和后节点,然而ArrayList只需要一个存放元素的数组即可。

其它List之间的比较,可查阅:【Simple Java】ArrayList vs LinkedList vs Vector

迭代遍历集合的时候,正确的删除元素

在迭代集合的时候,唯一正确的方法修改集合的方法是通过Iterator.remove()方法,如下示例:

Iterator<Integer> itr = list.iterator(); while(itr.hasNext()) { // do something itr.remove(); }

另外,举一个常见的错误代码:

1

2

3

 

for(Integer i: list) {

    list.remove(i);

}

 

运行以上错误代码,你将会得到ConcurrentModificationException异常,这是因为以上代码产生了一个迭代器(由for语句产生)去遍历列表,但是同时,列表被修改了(通过Iterator.remove())。在Java中,一个线程在迭代遍历集合的过程中,是不允许另外一个线程去修改集合的。

怎样将List转成int[]

最简单的方法是使用Apache Commons Lang库下的ArrayUtils工具类,如下:

int[] array = ArrayUtils.toPrimitive(list.toArray(new Integer[0]));

在JDK中,没有捷径去做以上转换。注意你不能使用List.toArray()方法,因为这将会把List转成Integer[]。正确的方法如下:

int[] array = new int[list.size()]; for(int i=0; i < list.size(); i++) { array[i] = list.get(i); }

怎样将int[]转成List

最简单的方法仍然是使用Apache Commons Lang的ArrayUtils工具类,如下:

List list = Arrays.asList(ArrayUtils.toObject(array));

在JDK中,仍然没有捷径,只能使用如下方法:

int[] array = {1,2,3,4,5}; List<Integer> list = new ArrayList<Integer>(); for(int i: array) { list.add(i); }

什么是过滤集合最好的方法

同样,你可以使用第三方库,如google的Guava库或Apache Commons Lang去实现这个功能,两者都提供了filter()方法(Guava的Collections2或Apache的CollectionUtils类)。filter()方法会返回匹配的元素。

在JDK中,这将会变得困难,好消息是,在java 8中,增加了Predicate接口,可以实现该功能。但是现在,我们只能使用迭代器去遍历整个集合:

Iterator<Integer> itr = list.iterator(); while(itr.hasNext()) { int i = itr.next(); if (i > 5) { // filter all ints bigger than 5 itr.remove(); } }

当然,你可以模仿Guava或Apache的操作方法,通过引入一个新的接口Predicate,这可能是高级开发人员才会做的事,如下:

public interface Predicate<T> { boolean test(T o); } public static <T> void filter(Collection<T> collection, Predicate<T> predicate) { if ((collection != null) && (predicate != null)) { Iterator<T> itr = collection.iterator(); while(itr.hasNext()) { T obj = itr.next(); if (!predicate.test(obj)) { itr.remove(); } } } }

然后,我们使用如下代码去过滤集合:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/9033077551713e772cf416abb9caebd7.html