操做集合是一個 Java 編程人員幾乎天天都在重複的事情。今天咱們來研究一下從 Java Collection 中刪除元素的方法。我構建了一個簡單的集合,咱們以此爲例子來展開探索。html
List<String> servers = new ArrayList<>(); servers.add("Felordcn"); servers.add("Tomcat"); servers.add("Jetty"); servers.add("Undertow"); servers.add("Resin");
讓咱們使用傳統的 foreach
循環移除 F
開頭的假服務器,可是你會發現這種操做引起了 ConcurrentModificationException
異常。java
// 錯誤的示範 千萬不要使用 for (String server : servers) { if (server.startsWith("F")) { servers.remove(server); } }
難道 for 循環就不能移除元素了嗎?固然不是!咱們若是能肯定須要被移除的元素的索引仍是能夠的。編程
// 這種方式是可行 for (int i = 0; i < servers.size(); i++) { if (servers.get(i).startsWith("F")) { servers.remove(i); } }
可是這種方式我目前只演示了 ArrayList
,其它的類型並無嚴格測試,留給你本身探索。segmentfault
在傳統方式中咱們使用 Iterator
是能夠保證刪除元素的:api
Iterator<String> iterator = servers.iterator(); while (iterator.hasNext()) { String next = iterator.next(); if (next.startsWith("F")) { iterator.remove(); } }
ConcurrentModificationException
異常。ArrayList
在刪除元素的速度上不如鏈表結構的 LinkedList
。Java 8 提供了新的集合操做 API 和 Stream 來幫助咱們解決這個問題。我在之前的文章中已經介紹了 Java 8 Stream API,若是有興趣能夠去看看。數組
新的 Collection
Api removeIf(Predicate<? super E> filter)
。該 Api 提供了一種更簡潔的使用 Predicate
(斷言)刪除元素的方法,因而咱們能夠更加簡潔的實現開始的需求:服務器
servers.removeIf(s-> s.startsWith("F"));
同時根據測試,ArrayList
和 LinkedList
的性能接近。通常推薦使用這種方式進行操做。數據結構
和上面全部移除操做不一樣的是,其實任何操做都不會改變 Stream
源,咱們僅僅是使用 Stream
Api 操做數據源的副本。遵循了 數據源 -> 中間操做 -> 概括終止
的生命週期。咱們來看看使用 Stream
如何實現咱們的意圖。性能
咱們能夠使用 Stream
的 filter
斷言。filter
斷言會把符合斷言的流元素聚集成一個新的流,而後概括起來便可,因而咱們能夠這麼寫:測試
// 跟以上不一樣的是 該方式中的斷言是取反的操做。 List<String> newServers = servers.stream().filter(s -> !s.startsWith("F")).collect(Collectors.toList());
這個優勢上面已經說了不會影響原始數據,生成的是一個副本。缺點就是可能會有內存佔用問題。
這種方法雖然能夠知足須要可是我感受有點投機取巧的成份。Collectors.partitioningBy()
方法本意是作二分類的。該方法會將流中符合斷言的、不符合斷言的元素分別概括到兩個 key
分別爲 true
和 false
的 Map
中,咱們能夠歸類獲得符合和不符合的元素集。實現以下:
Map<Boolean, List<String>> f = servers.stream().collect(Collectors.partitioningBy(s -> !s.startsWith("F"))); List<String> trues = f.get(Boolean.TRUE); System.out.println("不以 F 開頭的: " + trues); List<String> falses = f.get(Boolean.FALSE); System.out.println("以 F 開頭的: " + falses);
通常該方式不推薦在此場景使用,並不符合該 Api 的設計意圖。
今天咱們研究了一些從 Collections
中刪除元素的方法 及其注意事項。不知道你有沒有其它的實現方式,不妨經過公衆號:Felordcn 告訴我。
關注公衆號:Felordcn 獲取更多資訊