99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學院 頭像
蘋果6袋
6
麥子學院

Java集合問題匯總

發(fā)布時間:2016-06-23 21:55  回復:0  查看:2619   最后回復:2016-06-23 21:55  

以下是一些在Stackoverflow上經常被問起的與Java語言集合相關的問題。

 

什么時候優(yōu)先選擇LinkedList,而不是ArrayList

ArrayList本質上是一個數(shù)組,它的元素可以直接通過索引訪問。但是,當數(shù)組滿的時候,需要申請新的更大的數(shù)組空間,并將所有元素復制到新數(shù)組中,這將花費O(n)的時間。另外,插入和刪除元素需要移動數(shù)組中的其它元素,這也許是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中,每個節(jié)點需要兩個額外的指針指向前節(jié)點和后節(jié)點,然而ArrayList只需要一個存放元素的數(shù)組即可。

 迭代遍歷集合的時候,正確的刪除元素

在迭代集合的時候,唯一正確的方法修改集合的方法是通過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 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去實現(xiàn)這個功能,兩者都提供了filter()方法(GuavaCollections2ApacheCollectionUtils類)。filter()方法會返回匹配的元素。

在JDK中,這將會變得困難,好消息是,在java 8中,增加了Predicate接口,可以實現(xiàn)該功能。但是現(xiàn)在,我們只能使用迭代器去遍歷整個集合:

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,這可能是高級開發(fā)人員才會做的事,如下:

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最簡單的方法

有兩種方法來實現(xiàn)該功能,取決于你如何定義“相等。第一種方法將list存入HashSet,元素的重復主要由hashCode()來區(qū)分,大多數(shù)情況下,這是可行的。但是,如果你需要自己定義相等的比較方式,最好使用第二種方法,定義自己的比較器。

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來實現(xiàn)該功能。

對集合排序

Java中有幾種方式來維持集合中元素的順序,它們提供了默認的排序順序或者通過指定比較器來排序。不過即使是默認的排序,集合中的任何元素也需要實現(xiàn)Comparable接口。

Collections.sort()方法能夠對一個List集合進行排序,正如javadoc中描述的,這種排序方法是穩(wěn)定且能保證排序性能為n log(n)。

PriorityQueue為一個有序隊列,它與Collections.sort()的區(qū)別是PriorityQueue隊列一直是有序的,但是你只能訪問隊頭和隊尾,不能隨即訪問元素,如PriorityQueue.get(4)之類的操作。

如果集合中沒有重復的元素,TreeSet是另外一種選擇。跟PriorityQueue類似,它能一直維護元素的順序,你能直接獲取TreeSet中的第一個和最后一個元素,但是你仍然不能隨即訪問集合中的元素。

簡單的說,Collections.sort()提供了對List的一次性排序,PriorityQueueTreeSet能一直維持集合中元素的順序,但是不能隨即訪問元素。

Collections.emptyList()與直接new一個實例的區(qū)別

該問題也適用于emptyMap()emptySet()

這兩種方式都返回了一個空集合,但是Collections.emptyList()返回的是???個不可變集合,意味著你不能往這個空集合新增元素。事實上,每次調用Collections.emptyList()并不會創(chuàng)建一個空集合,而是復用已經存在的空集合實例。如果你熟悉單例模式的話,你應該知道我所說的,如果你頻繁調用的話,這將會提供更好的性能。

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

這兩種方法都使用淺拷貝,那么這兩種方法的區(qū)別是什么呢?

首先,當目標集合沒有足夠的空間存放源集合中的元素時,Collections.copy()方法不會對目標集合擴容,它會拋出一個IndexOutOfBoundsException異常。

Collections.copy()的參數(shù)類型只能是List接口的實現(xiàn)類,而ArrayList的構造方法可以接受Collection接口的實現(xiàn)類作為入?yún)?,因此更加普通?/span>

 

原文來自:Linux公社

您還未登錄,請先登錄

熱門帖子

最新帖子

?