使用 Java Streams 取得第一個元素匹配布林值的索引
一、簡介
從資料結構中尋找元素的索引是開發人員的常見任務。在本教程中,我們將使用 Java Stream API 和第三方函式庫來尋找List
中與布林條件相符的第一個元素的索引。
2. 設定
在本文中,我們將使用下面提到的 User 物件編寫一些測試案例來實現我們的目標:
public class User {
private String userName;
private Integer userId;
// constructor and getters
}
此外,我們將建立一個User
物件的ArrayList
以在所有測試用例中使用。之後,我們將找到第一個使用者的索引,其名字是“John”
:
List<User> userList = List.of(new User(1, "David"), new User(2, "John"), new User(3, "Roger"), new User(4, "John"));
String searchName = "John";
3.使用Java Stream API
Java Stream API 是 Java 8 中引入的最佳功能之一。它提供了多種方法來迭代、過濾、映射、匹配和收集資料。考慮到這一點,讓我們使用這些方法從List
中尋找索引。
3.1.使用*stream()*和filter()
讓我們使用Stream
類別的基本函數編寫一個測試案例來取得索引:
@Test
public void whenUsingStream_thenFindFirstMatchingUserIndex() {
AtomicInteger counter = new AtomicInteger(-1);
int index = userList.stream()
.filter(user -> {
counter.getAndIncrement();
return searchName.equals(user.getUserName());
})
.mapToInt(user -> counter.get())
.findFirst()
.orElse(-1);
assertEquals(1, index);
}
在這裡,我們可以從List
建立一個Stream
並應用一個filter()
方法。在filter()
方法中,我們增加AtomicInteger
來追蹤元素的索引。最後,我們映射計數器值並使用findFirst()
方法來取得第一個匹配元素的索引。
3.2.使用IntStream
或者,我們可以使用IntStream
類別迭代List
元素並使用與上一節中提到的類似邏輯來取得索引:
@Test
public void whenUsingIntStream_thenFindFirstMatchingUserIndex() {
int index = IntStream.range(0, userList.size() - 1)
.filter(streamIndex -> searchName.equals(userList.get(streamIndex).getUserName()))
.findFirst()
.orElse(-1);
assertEquals(1, index);
}
3.3.使用Stream takeWhile()
takeWhile()
方法傳回數據,直到謂詞保持true
。然而,一旦謂詞失敗,它就會停止迭代以收集迭代資料:
@Test
public void whenUsingTakeWhile_thenFindFirstMatchingUserIndex() {
long predicateIndex = userList.stream()
.takeWhile(user -> !user.getUserName().equals(searchName))
.count();
assertEquals(1, predicateIndex);
}
上面的範例顯示takeWhile()
方法收集元素,直到找到名為“John”
的User
對象,然後停止迭代。之後,我們可以使用count()
方法來取得第一個符合元素的索引。
讓我們考慮另一種情況,列表中不存在匹配元素。在這種情況下,迭代繼續直到最後一個元素,輸出值為4,
這是輸入清單中迭代的元素總數:
@Test
public void whenUsingTakeWhile_thenFindIndexFromNoMatchingElement() {
long predicateIndex = userList.stream()
.takeWhile(user -> !user.getUserName().equals(searchName))
.count();
assertEquals(4, predicateIndex);
}
takeWhile()
方法是在 Java 9 中引入的。
4.使用第三方函式庫
儘管 Java Stream API 足以實現我們的目標,但它僅在 Java 1.8 版本中可用。如果應用程式運行在舊版本的 Java 上,那麼外部程式庫就會變得有用。
4.1.來自 Google Guava 的Iterables
我們將最新的Maven 依賴項新增至pom.xml
:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.2-jre</version>
</dependency>
Guava 函式庫中的Iterables
類別有一個名為indexOf(),
該方法傳回指定可迭代物件中與給定謂詞相符的第一個元素的索引:
@Test
public void whenUsingGoogleGuava_thenFindFirstMatchingUserIndex() {
int index = Iterables.indexOf(userList, user -> searchName.equals(user.getUserName()));
assertEquals(1, index);
}
4.2.來自 Apache 通用集合的IterableUtils
類似地,Apache Common Collections 函式庫中的IterableUtils
類別也提供了取得索引的功能。讓我們在pom.xml
中加入Maven 依賴項:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
IterableUtils.
indexOf()
方法接受一個可迭代集合和一個謂詞,然後傳回第一個符合元素的索引:
@Test
public void whenUsingApacheCommons_thenFindFirstMatchingUserIndex() {
int index = IterableUtils.indexOf(userList, user -> searchName.equals(user.getUserName()));
assertEquals(1, index);
}
如果沒有元素滿足謂詞條件,兩個函式庫中的indexOf()
方法都會回傳-1
。
5. 結論
在本文中,我們學習了查找List
中與布林條件相符的第一個元素的索引的不同方法。我們使用了 Java Stream API、Google Guava 中的Iterables
類別以及 Apache Commons Collections 中的IterableUtils
類別。
與往常一樣,參考代碼可以在 GitHub 上取得。