Seb*_* S. 12 comparison lambda java-8 java-stream
在单元测试中,我想验证两个列表包含相同的元素.要测试的列表是Person对象列表的构建,其中String提取了一个类型的字段.另一个列表包含String文字.
人们经常会找到以下代码片段来完成此任务(请参阅此答案):
List<Person> people = getPeopleFromDatabasePseudoMethod();
List<String> expectedValues = Arrays.asList("john", "joe", "bill");
assertTrue(people.stream().map(person -> person.getName()).collect(Collectors.toList()).containsAll(expectedValues));
Run Code Online (Sandbox Code Playgroud)
该Person课程如下:
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
// other getters and setters
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,使用Java 8技术将人员(或人员)列表转换为字符串列表,并且以旧式方式进行比较.
现在我想知道,如果有更直接或更有效的方法使用其他Java 8语句进行比较,例如allMatch()或某些Predicate<T>或其他东西.
Hol*_*ger 20
您的问题代码并未反映您在评论中描述的内容.在评论中,您说所有名称都应该存在且大小应该匹配,换句话说,只有订单可能不同.
你的代码是
List<Person> people = getPeopleFromDatabasePseudoMethod();
List<String> expectedValues = Arrays.asList("john", "joe", "bill");
assertTrue(people.stream().map(person -> person.getName())
.collect(Collectors.toList()).containsAll(expectedValues));
Run Code Online (Sandbox Code Playgroud)
缺乏对大小的测试people,换句话说允许重复.此外,使用containsAll组合两个Lists的效率非常低.如果您使用反映您意图的集合类型,即没有重复,不关心订单并且具有高效查找,则会好得多:
Set<String> expectedNames=new HashSet<>(expectedValues);
assertTrue(people.stream().map(Person::getName)
.collect(Collectors.toSet()).equals(expectedNames));
Run Code Online (Sandbox Code Playgroud)
使用此解决方案,您无需手动测试大小,已经暗示如果它们匹配,则集合具有相同的大小,只有顺序可能不同.
有一个解决方案,不需要收集以下名称persons:
Set<String> expectedNames=new HashSet<>(expectedValues);
assertTrue(people.stream().allMatch(p->expectedNames.remove(p.getName()))
&& expectedNames.isEmpty());
Run Code Online (Sandbox Code Playgroud)
但它只有在expectedNames是由预期名称的静态集合创建的临时集时才有效.一旦您决定用a替换静态集合Set,第一个解决方案不需要临时设置,后者没有优势.