使用 Java 8 從另一種類型創建對象列表
1. 概述
當我們使用 Java 時,有時我們想要從另一個對象列表生成一個列表。 Java 8 引入了一組新功能來簡化此類操作。
因此,在本教程中,我們將探索如何使用 Java 8 及更高版本中引入的強大功能基於給定列表創建不同類型的對象列表。
2.問題介紹
像往常一樣,讓我們通過示例來理解問題。
假設一家公司正在尋求啟動內部網球錦標賽。現在,賽事組委會希望從公司全體員工中獲得一份選手候選名單。因此,我們將接受此任務並創建一個程序來建立玩家候選列表。
Employee
類已準備就緒:
@Getter
class Employee {
private final String name;
private final Set<String> hobbies = new HashSet<>();
private final String email;
private String department;
// ... other attributes
public Employee(String name, String email, Collection<String> hobbies) {
this.name = name;
this.email = email;
this.hobbies.addAll(hobbies);
}
}
如上面的代碼所示,我們使用Lombok的@Getter
註解使Employee
類的所有屬性都具有getter方法。
每個Employee
對像都帶有hobbies
Set
,它在String
中保存員工的愛好。我們的任務包括遍歷員工。如果員工將“ Tennis
”列為其愛好之一,我們就會認為他們是作為網球運動員參加錦標賽的潛在候選人。因此,最後,我們將得到一個TennisPlayerCandidate
實例的列表:
class TennisPlayerCandidate {
private final String name;
private final String email;
private final Boolean confirmed = Boolean.FALSE;
public TennisPlayerCandidate(String name, String email) {
this.name = name;
this.email = email;
}
// equals() and hashcode() methods are omitted
}
作為我們的輸入,我們假設EMPLOYEES
列表包含五個對象:
final static List<Employee> EMPLOYEES = Lists.newArrayList(
new Employee("Kai", "[email protected]", Lists.newArrayList("Football", "Reading", "Chess")),
new Employee("Eric", "[email protected]", Lists.newArrayList("Tennis", "Baseball", "Singing")),
new Employee("Saajan", "[email protected]", Lists.newArrayList("Tennis", "Baseball", "Reading")),
new Employee("Kevin", "[email protected]", Lists.newArrayList("Dancing", "Computer Games", "Tennis")),
new Employee("Amanda", "[email protected]", Lists.newArrayList("Painting", "Yoga", "Dancing"))
);
基於此輸入,我們的目標是獲取TennisPlayerCandidate
實例的列表:
final static List<TennisPlayerCandidate> EXPECTED = Lists.newArrayList(
new TennisPlayerCandidate("Eric", "[email protected]"),
new TennisPlayerCandidate("Saajan", "[email protected]"),
new TennisPlayerCandidate("Kevin", "[email protected]")
);
接下來,讓我們看看從給定的List<Employee>
構建預期的List<TennisPlayerCandidate>
的不同解決方案。
為簡單起見,我們將使用單元測試斷言來驗證每種方法是否可以產生預期結果。
3.使用List.forEach()
方法
解決此問題的一種直接方法是首先初始化一個空的候選列表。然後,我們遍歷EMPLOYEES
列表,為每個將網球列為愛好的員工創建一個TennisPlayerCandidate
對象。如果員工符合此標準,我們會將其添加到候選人名單中。
Java 8 引入了forEach()
方法,它允許我們在遍歷列表時方便地執行操作:
List<TennisPlayerCandidate> result = new ArrayList<>();
EMPLOYEES.forEach(e -> {
if (e.getHobbies().contains("Tennis")) {
result.add(new TennisPlayerCandidate(e.getName(), e.getEmail()));
}
});
assertEquals(EXPECTED, result);
正如我們所看到的,這種方法有效地完成了工作。
除了forEach()
方法之外,自 Java 8 以來,Stream API 徹底改變了我們操作和轉換數據集合的方式。
接下來我們使用Stream API來解決這個問題。
4. 使用Stream.map()
或Collectors.mapping()
我們可以這樣解釋這個問題:過濾出愛好網球的員工,並將這些Employee
對象轉換為TennisPlayerCandidate
對象。
Stream的filter()
和map()
方法可以幫助我們輕鬆完成任務。接下來,讓我們將這個想法“翻譯”成Java代碼:
List<TennisPlayerCandidate> result = EMPLOYEES.stream()
.filter(e -> e.getHobbies().contains("Tennis"))
.map(e -> new TennisPlayerCandidate(e.getName(), e.getEmail()))
.collect(Collectors.toList());
assertEquals(EXPECTED, result);
如上面的代碼所示,沒有必要為TennisPlayerCandidate
對象準備一個空列表。 filter().map()
管道提供TennisPlayerCandidate
實例的Stream
。我們需要做的只是將對象收集到一個列表中。
或者,我們可以將映射邏輯移至收集階段。換句話說,當我們收集過濾後的Employee
實例時,我們會將它們轉換為TennisPlayerCandidate
。
Collectors.mapping()
方法允許我們從Stream
執行對象轉換和收集:
List<TennisPlayerCandidate> result = EMPLOYEES.stream()
.filter(e -> e.getHobbies().contains("Tennis"))
.collect(Collectors.mapping(e -> new TennisPlayerCandidate(e.getName(), e.getEmail()), Collectors.toList()));
assertEquals(EXPECTED, result);
5. 結論
在本文中,我們探討了根據給定列表創建不同類型的對象列表的三種方法。通過示例,我們了解到 Stream API 在使用 Java 中的列表時提高了代碼的生產力和可讀性。
與往常一樣,示例的完整源代碼可在 GitHub 上獲取。