閱讀363 返回首頁    go 汽車大全


關於Java集合最被關注的10 個問題

 下麵是stackoverflow關於Java集合方麵討論最多的幾個問題,在這裏整理出來供大家參考。

1.關於LinkList和ArrayList
  • ArrayList:內部實現是個數組,其中的元素可以通過index獲取。但是,如果一個數組滿了的話,我們就必須重新分配一個更大的數組然後把所有元素移動到這個新數組,其時間複雜度為O(n)。添加或刪除一個元素時也需要移動數組中的其它元素。這就是ArrayList的缺點。
  • 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)
    除了考慮時間複雜度之外,當List比較大時,空間複雜度也不可忽略:
  • LinkList:每個節點還需要額外的兩個指針,分別指向前一個節點和下一個節點
  • ArrayList:隻需要一個數組

2.最有效移除集合元素的方式
    唯一正確的移除集合元素的方式就是使用Iterator.remove()方法:
Iterator<Integer> itr = list.iterator();
while(itr.hasNext()) {
   // do something
   itr.remove();
}

  下麵這種處理方式是錯誤的,會報出這麼一個異常:ConcurrentModificationException
for(Integer i: list) {
  list.remove(i);
}
3.如何將一個List轉換成一個int[] 數組?
     最簡單的方式就是使用Apache Commons Lang工具包下的ArrayUtils
int[] array = ArrayUtils.toPrimitive(list.toArray(new Integer[0]));
如果用jdk的話是沒有捷徑的,注意我們不能使用List.toArray()方法,因為這樣得到的是Integer[],正確的方法應該是:
int[] array = new int[list.size()];
for(int i=0; i < list.size(); i++) {
  array[i] = list.get(i);
}

4.如何將int[] 轉換成List?
     和上麵類似,我們可以使用ArrayUtils工具類:
List list = Arrays.asList(ArrayUtils.toObject(array));
或者依然沒有捷徑:
int[] array = {1,2,3,4,5};
List<Integer> list = new ArrayList<Integer>();
for(int i: array) {
  list.add(i);
}
5.最好的過濾集合的方法?  
    當然,最方便最好的方式就是使用第三方jar包,比如 Guava or Apache Commons Lang ,這兩者都提供了filter()方法。在jdk中,事情就變得沒那麼簡單了(不過Java8已經支持Predicate了),但是在Java8之前,比較通常的方式是我們必須遍曆集合中的所有元素:

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 Commons Lang,通過引入一個新的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; 
    }
});
6.把List轉換成Set的最簡單的方式有兩種方式:
Set<Integer> set = new HashSet<Integer>(list);
Set<Integer> set = new TreeSet<Integer>(aComparator);
set.addAll(list);
7.如何移除ArrayList中的重複元素  
    和上麵方法類似,如果不關心順序的話:
ArrayList** list = ... // initial a list with duplicate elements
Set<Integer> set = new HashSet<Integer>(list);
list.clear();
list.addAll(set);
如果關心順序,把上麵那個HashSet換成LinkedHashSet即可。
8.給集合排序    
   給集合排序的實現方法有很多種
	1.Collections.sort():進行一次排序
	2.PriorityQueue :始終保持隊列的順序,但是隻能從隊列的頭獲取元素
	3.TreeSet:始終保持隊列的順序,元素不重複,你可以從最頂端或最低端獲取元素,但也不能隨機獲取元素
9.Collections.emptyList() vs new Instance     
    上麵兩個方法都會返回空的List,但是Collections.emptyList()返回的List是不可變的,每次方法調用不會重新創建一個實例,而是複用原來的實例(即單例模式),所以這樣效率會高些。
10.Collections.copy     
    有兩種方式複製一個List,第一種:
ArrayList<Integer> dstList = new ArrayList<Integer>(srcList);
第二種是利用Collections.copy()方法:
ArrayList<Integer> dstList = new ArrayList<Integer>(srcList.size());
Collections.copy(dstList, srcList);
那兩者有何區別呢?  
    如果目標集合(dstList)小於源集合,使用Collections.copy()會拋出IndexOutOfBoundsException,那它有什麼好處呢?首先它保證運行效率和集合大小線性相關,第二就是可以實現集合的重用。
 

最後更新:2017-04-03 07:57:16

  上一篇:go 兒子,爸爸不是李開複
  下一篇:go C# 關於類型轉換 麵試題