避免在 Java 中的 ArrayList 中插入重複項
1. 概述
在這個簡短的教學中,我們將學習如何在 Java 中使用ArrayList
時避免插入重複值。
首先,我們將了解如何使用現成的 JDK 類別來執行此操作。然後,我們將討論如何使用 Apache Commons Collections 和 Guava 等外部函式庫來實現相同的目標。
2. Set
類別
通常, Set
類別提供了應對我們的挑戰的最簡單的解決方案。從本質上講,它表示一個不允許重複元素的集合。那麼,讓我們看看它的實際效果:
@Test
void givenArrayList_whenUsingSet_thenAvoidDuplicates() {
Set<String> distinctCities = new HashSet<>(Arrays.asList("Tamassint", "Madrid", "Paris", "Tokyo"));
String newCity = "Paris";
distinctCities.add(newCity);
ArrayList<String> arrayListCities = new ArrayList<>(distinctCities);
assertThat(arrayListCities).hasSameSizeAs(distinctCities);
}
正如我們所看到的,我們嘗試將重複的城市“Paris”
添加到我們的城市Set
。但是,從Set
建立的ArrayList
不包含新新增的城市。根據經驗,使用Set
實作而不是其他集合始終是避免重複值的最佳方法。
3.List List#contains
方法
我們要查看的第二個選項是List
介面的contains()
方法。顧名思義,它檢查清單中給定元素是否存在。如果元素存在則傳回true
,否則傳回false
:
@Test
void givenArrayList_whenUsingContains_thenAvoidDuplicates() {
List<String> distinctCities = Arrays.asList("Tamassint", "Madrid", "Paris", "Tokyo");
ArrayList<String> arrayListCities = new ArrayList<>(distinctCities);
String newCity = "Madrid";
if (!arrayListCities.contains(newCity)) {
arrayListCities.add(newCity);
}
assertThat(arrayListCities).hasSameSizeAs(distinctCities);
}
在這裡,我們檢查arrayListCities
是否已包含新城市“Madrid”
。由於該城市已在列表中,因此條件計算結果為false
,因此不會執行arrayListCities.add()
,並且不會再次添加“Madrid”
。
4. Stream#anyMatch
方法
Java 8 Stream API 提供了一個回答核心問題的便利方法。它帶有anyMatch()
方法,我們可以使用它來檢查流的任何元素是否與指定的謂詞相符。
那麼,讓我們在實踐中來看看:
@Test
void givenArrayList_whenUsingAnyMatch_thenAvoidDuplicates() {
List<String> distinctCities = Arrays.asList("Tamassint", "Madrid", "Paris", "Tokyo");
ArrayList<String> arrayListCities = new ArrayList<>(distinctCities);
String newCity = "Tamassint";
boolean isCityPresent = arrayListCities.stream()
.anyMatch(city -> city.equals(newCity));
if (!isCityPresent) {
arrayListCities.add(newCity);
}
assertThat(arrayListCities).hasSameSizeAs(distinctCities);
}
類似地,我們使用anyMatch()
來檢查ArrayList
是否包含新城市“Tamassint”
。由於它已經存在, anyMatch()
傳回true
,並且不會呼叫方法add()
,這可以避免新增重複的 city 。
5. Stream#filter
方法
或者,我們可以使用filter()
方法來實現相同的結果。簡而言之,此方法根據提供的謂詞過濾元素Stream
:
@Test
void givenArrayList_whenUsingFilterAndFindFirst_thenAvoidDuplicates() {
List<String> distinctCities = Arrays.asList("Tamassint", "Madrid", "Paris", "Tokyo");
ArrayList<String> arrayListCities = new ArrayList<>(distinctCities);
String newCity = "Tamassint";
Optional<String> optionalCity = arrayListCities.stream()
.filter(city -> city.equals(newCity))
.findFirst();
if (optionalCity.isEmpty()) {
arrayListCities.add(newCity);
}
assertThat(arrayListCities).hasSameSizeAs(distinctCities);
}
簡而言之,我們從ArrayList
創建了一個流。此外,我們使用filter()
方法來尋找等於新加入的城市“Tamassint”
的任何元素。然後,我們呼叫findFirst()
,它傳回一個包含過濾流的第一個元素的Optional
。
此外,我們檢查傳回的Optional
物件是否為空。因此,不會添加“Tamassint”
因為它已經存在於**ArrayList** .
6. 使用番石榴
另一種解決方案是使用番石榴。要使用這個函式庫,我們首先需要將其Maven 依賴項加入到我們的pom.xml
中:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.2.0-jre</version>
</dependency>
Guava 提供了Iterables
實用程式類,其中包含對集合進行操作的靜態方法。在這些方法中,我們找到contains()
方法。因此,讓我們舉例說明如何使用此實用方法來避免插入重複元素:
@Test
void givenArrayList_whenUsingIterablesContains_thenAvoidDuplicates() {
List<String> distinctCities = Arrays.asList("Tamassint", "Madrid", "Paris", "Tokyo");
ArrayList<String> arrayListCities = new ArrayList<>(distinctCities);
String newCity = "Paris";
boolean isCityPresent = Iterables.contains(arrayListCities, newCity);
if (!isCityPresent) {
arrayListCities.add(newCity);
}
assertThat(arrayListCities).hasSameSizeAs(distinctCities);
}
這種方法簡單易讀。然而,考慮到相同的內建 Java 方法可用,只有當我們已經在使用 Guava 時才可能使用它。
7. 使用 Apache Commons 集合
我們的最終解決方案是使用CollectionUtils
類別中的containsAny()
方法。與往常一樣,讓我們將Apache Commons Collections 相依性新增至pom.xml
檔中:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.5.0-M1</version>
</dependency>
從根本上講, containsAny()
驗證給定元素是否存在於指定的集合中。它在底層使用intersection()
方法,如果交集不為空則傳回true
:
@Test
void givenArrayList_whenUsingCollectionUtilsContainsAny_thenAvoidDuplicates() {
List<String> distinctCities = Arrays.asList("Tamassint", "Madrid", "Paris", "Tokyo");
ArrayList<String> arrayListCities = new ArrayList<>(distinctCities);
String newCity = "Tokyo";
boolean isCityPresent = CollectionUtils.containsAny(arrayListCities, newCity);
if (!isCityPresent) {
arrayListCities.add(newCity);
}
assertThat(arrayListCities).hasSameSizeAs(distinctCities);
}
正如預期的那樣,測試成功執行。
八、結論
在本文中,我們看到Set
介面是避免添加重複元素的最通用的解決方案。此外,我們還探索了不同的替代方案來實現相同的結果,例如 Stream API、Guava 和 Apache Commons Collections。
與往常一樣,範例的完整程式碼可在 GitHub 上取得。