2009-01-06 66 views
14

我經常做一個收集場不可修改,從一個getter方法返回之前:如何創建一個深度不可修改的集合?

private List<X> _xs; 
.... 
List<X> getXs(){ 
    return Collections.unmodifiableList(_xs); 
} 

但我想不出做的一種便捷方式,如果上面的X本身就是一個列表:

private List<List<Y>> _yLists; 
..... 
List<List<Y>> getYLists() { 
    return Collections.unmodifiableList(_yLists); 
} 

上面的問題當然是,雖然客戶端不能修改列表列表,但它可以從嵌入列表中添加/刪除Y對象。

有什麼想法?

回答

7

我可以拿出最好的用途ForwardingList from Google Collections。歡迎評論。

private static <T> List<List<T>> unmodifiableList2(final List<List<T>> input) { 
    return Collections.unmodifiableList(new ForwardingList<List<T>>() { 
     @Override protected List<List<T>> delegate() { 
      return Collections.unmodifiableList(input); 
     } 
     @Override public List<T> get(int index) { 
      return Collections.unmodifiableList(delegate().get(index)); 
     } 
    }); 
} 
+0

這很好。 – 2009-01-06 10:36:04

+0

特別是在我使外部列表不可修改的情況下:-) – 2009-01-06 10:39:18

3

不幸的是,在java中沒有簡單的方法獲得深度常量。您必須始終確保列表中的列表不可修改。

我也很感興趣,知道任何優雅的解決方案。

+0

和我一樣! – 2009-01-06 10:19:51

0

如果你看一下Collections.unmodifiable *(...)方法的實現,你可以看到它們只是包裝集合。以相同的方式做一個深層次的實用工具應該是可行的。

這樣做的不足之處在於它增加了對集合訪問的額外方法調用,因此影響性能。

0

如果您在這裏唯一的目標是執行封裝,典型的解決方案是使用克隆()或類似返回一個結構,它是不是對象的內部狀態。這顯然只適用於所有對象都可以被克隆,並且複製的結構足夠小的情況。

如果這是一個相當常用的數據結構,另一種選擇是使訪問它的API更加具體,以便更具體地控制特定的調用。編寫自己的List實現,如上所述,一個這樣做的方法,但是如果您可以縮小對特定用例的調用範圍,則可以公開特定的訪問API而不是List接口。

0

萬一有人有興趣在這裏是一個簡單的解決辦法:

public List<List<Double>> toUnmodifiable(List<List<Double>> nestedList) { 
     List<List<Double>> listWithUnmodifiableLists = new ArrayList<>(); 
      for (List<Double> list : nestedList) {    
       listWithUnmodifiableLists 
        .add(Collections.unmodifiableList(list)); 
      } 
     return Collections.unmodifiableList(listWithUnmodifiableLists); 
    } 

這可以用來例如作爲解決辦法,如果ü要用getList()方法公開一個列表,你可以返回:toUnmodifiable(mNestedList),其中mNestedList是類中的私有列表。

我個人發現這在實現用於在Android中使用GSON進行解析的類時非常有用,因爲它無法修改響應,在本例中爲反序列化的json,我將此方法用作一種使用getter公開列表的方法,並確保列表不會被修改。