楼主: z74646
1156 0

[其他] 最常被问起的10个java集合问题 [推广有奖]

  • 0关注
  • 1粉丝

本科生

75%

还不是VIP/贵宾

-

威望
0
论坛币
300 个
通用积分
0
学术水平
0 点
热心指数
1 点
信用等级
0 点
经验
890 点
帖子
55
精华
0
在线时间
12 小时
注册时间
2014-2-26
最后登录
2016-7-2

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

以下是一些在Stackoverflow上经常被问起的与Java语言http://www.*/course/804/集合相关的问题。

什么时候优先选择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只需要一个存放元素的数组即可。

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

在迭代集合的时候,唯一正确的方法修改集合的方法是通过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 = list.get(i);

}

怎样将int[]转成List

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

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);

}

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

同样,你可以使用第三方库,如googleGuava库或Apache Commons Lang去实现这个功能,两者都提供了filter()方法(GuavaCollections2ApacheCollectionUtils类)。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();

    }

}

当然,你可以模仿GuavaApache的操作方法,通过引入一个新的接口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();

            }

        }

    }

}

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

filter(list, new Predicate<Integer>() {

    public boolean test(Integer i) {

        return i <= 5;

    }

});

ListSet最简单的方法

有两种方法来实现该功能,取决于你如何定义相等。第一种方法将list存入HashSet,元素的重复主要由hashCode()来区分,大多数情况下,这是可行的。但是,如果你需要自己定义相等的比较方式,最好使用第二种方法,定义自己的比较器。

Set<Integer> set = new HashSet<Integer>(list);

Set<Integer> set = new TreeSet<Integer>(aComparator);

set.addAll(list);

ArrayList中删除重复元素

这个问题和上一个很像,如果你不关心ArrayList中元素的顺序的话,一个聪明的方法是通过将list元素存入set集合中来去除重复元素,然后将set集合的元素移回到List中。如下代码:

ArrayList** list = ... // initial a list with duplicate elements

Set<Integer> set = new HashSet<Integer>(list);

list.clear();

list.addAll(set);

如果你关心元素的顺序的话,可以使用标准JDK中的LinkedHashSet来实现该功能。

对集合排序

Java中有几种方式来维持集合中元素的顺序,它们提供了默认的排序顺序或者通过指定比较器来排序。不过即使是默认的排序,集合中的任何元素也需要实现Comparable接口。

Collections.sort()方法能够对一个List集合进行排序,正如javadoc中描述的,这种排序方法是稳定且能保证排序性能为n log(n)

PriorityQueue为一个有序队列,它与Collections.sort()的区别是PriorityQueue队列一直是有序的,但是你只能访问队头和队尾,不能随即访问元素,如PriorityQueue.get(4)之类的操作。

如果集合中没有重复的元素,TreeSet是另外一种选择。跟PriorityQueue类似,它能一直维护元素的顺序,你能直接获取TreeSet中的第一个和最后一个元素,但是你仍然不能随即访问集合中的元素。

简单的说,Collections.sort()提供了对List的一次性排序,PriorityQueueTreeSet能一直维持集合中元素的顺序,但是不能随即访问元素。

Collections.emptyList()与直接new一个实例的区别

该问题也适用于emptyMap()emptySet()

这两种方式都返回了一个空集合,但是Collections.emptyList()返回的是���个不可变集合,意味着你不能往这个空集合新增元素。事实上,每次调用Collections.emptyList()并不会创建一个空集合,而是复用已经存在的空集合实例。如果你熟悉单例模式的话,你应该知道我所说的,如果你频繁调用的话,这将会提供更好的性能。

Collections.copy方法

有两种方法讲一个List集合拷贝到另外一个List集合,其中一种是使用ArrayList的构造方法,如下:

ArrayList<Integer> dstList = new ArrayList<Integer>(srcList);

另一种是使用Collections.copy()方法(如下),注意第一行,我们分配了一个和源List集合长度相等的初始容量。

ArrayList<Integer> dstList = new ArrayList<Integer>(srcList.size());

Collections.copy(dstList, srcList);

这两种方法都使用浅拷贝,那么这两种方法的区别是什么呢?

首先,当目标集合没有足够的空间存放源集合中的元素时,Collections.copy()方法不会对目标集合扩容,它会抛出一个IndexOutOfBoundsException异常。

Collections.copy()的参数类型只能是List接口的实现类,而ArrayList的构造方法可以接受Collection接口的实现类作为入参,因此更加普通。

原文来自:Linux公社


二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:Java jav Modification collections Collection java

已有 1 人评分热心指数 收起 理由
guo.bailing + 1 鼓励积极发帖讨论

总评分: 热心指数 + 1   查看全部评分

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-4-25 08:18