我有一個B和C類型元素的集合,它們都擴展爲A.我需要過濾集合以獲取僅B類型的元素。Java:從集合中只選擇提供的類型的元素
有沒有辦法做到這一點,除了:
for (A a : initCollection) {
if (a instanceof B) {
newCollection.add(a)?
}
}
感謝
我有一個B和C類型元素的集合,它們都擴展爲A.我需要過濾集合以獲取僅B類型的元素。Java:從集合中只選擇提供的類型的元素
有沒有辦法做到這一點,除了:
for (A a : initCollection) {
if (a instanceof B) {
newCollection.add(a)?
}
}
感謝
據我所知,沒有這樣做無需添加代碼類A,B沒有純的方式,和C. 實問題是:爲什麼你需要過濾出特定類型的元素?它違背了在OOP中進行子分類的想法。
爲什麼會這樣呢?我有一個超級類型的集合,當然可以有不同的子類型實例。現在我想要有確切的課程。爲什麼不?錯在哪裏? – glaz666 2010-04-27 15:19:05
這不是一個錯誤。雖然面向對象的純粹主義者可能會說,無論您想要做什麼操作,都要使主集合中的每個對象實現一種方法來實現它(使用實現noop方法的更高級別的對象),這常常足以執行性能要求你問的很頻繁。 – DJClayworth 2010-04-27 16:39:15
+1這樣做的願望對我來說似乎是一種代碼味道。在某些情況下它可能是正確的方法,但我認爲在大多數情況下,更改設計將是更好的選擇。 – 2010-04-27 17:37:57
根據您的示例,我沒有發現任何問題。但是,如果您想要使用Google的Guava library,特別是Collections2
,則可以對您的收藏進行功能風格的過濾。你可以提供你自己的謂詞,這當然可以做instanceof
的事情。
Collection<Object> newCollection = Collections2.filter(initCollection, new Predicate<Object>() {
public boolean apply(Object o) {
return !(o instanceof String);
}
});
如果您不希望創建新的集合,你可以從現有的去除奇數元素:
Iterator<A> it = initCollection.iterator();
while (it.hasNext()){
if (it.next() instanceof C) {
it.remove();
}
}
Guava被提到了在其他的答案,但沒有具體的解決方案,這是連簡單的比人們意識到:
Iterable<B> onlyBs = Iterables.filter(initCollection, B.class);
這很簡單,乾淨,做正確的事,只創建一個實例,並沒有複製,而不會引起任何警告。
(該Collections2.filter()
方法不具有這種特殊的過載,雖然如此,如果你真的想要一個Collection
,你必須提供Predicates.instanceOf(B.class)
所得徵收仍然是可悲類型Collection<A>
的。)
請注意,使用此解決方案時,每次迭代overBs時,都會執行過濾邏輯。這可以是一件好事(如果initCollection已更新,並且只希望B反映這些更改),或者是一件壞事(如果您期待拷貝或僅將某些代碼傳遞給某些遍歷它的代碼)。如果你想要一個副本,只需從filter()的輸出中創建一個集合。 – NamshubWriter 2010-06-23 20:58:03
這是一個古老的問題,但我想我會添加這個以防萬一找到它。
可以使用純Java 8及其Stream
就做這個。
List<B> filtered = listOfA.stream()
.filter(a -> a instanceof B)
.map(a -> (B) a)
.collect(Collectors.toList());
你爲什麼不喜歡現在製作的方式? – Roman 2010-04-27 15:19:12
您也可以等待Java7。這可以用[閉包](http://javac.info)來縮短,我想。 – BalusC 2010-04-27 15:24:54