简体   繁体   English

如何比较stream中的两个列表

[英]How to compare two lists in stream

I want to compare (assert equals) for training purposes two lists in stream. So every id from sampleUsers() with every id from body of response entity should be compared.为了训练目的,我想比较(断言等于)stream 中的两个列表。因此,应该比较来自 sampleUsers() 的每个 id 和来自响应实体正文的每个 id。 Should I create another stream?我应该创建另一个 stream 吗? If yes then how to use it?如果是那么如何使用它?

@Test
  void findAllUsers() {
    when(userService.findAll()).thenReturn(sampleUsers());
    ResponseEntity<List<UserDto>> responseEntity = userController.findAll();

    //first assert
    assertEquals(responseEntity.getStatusCode().value(), 200);

    //second assert
    assertEquals(responseEntity.getBody().size(), sampleUsers().size());

    //third assert
    responseEntity.getBody().stream()
          .filter(user -> user.getId() != null)
          .filter(user -> user.getUsername() != null)
          //TODO check for each user if: 
          //     user.getId is equal to id from sampleUsers() list
          //     something like: assert equals user.getId(), sampleUsers.get(0).getId()
    }

There are many ways to do that assertion.有很多方法可以做这个断言。 You could override equals() in UserDto class.您可以将 UserD 中的 equals() 重写为 class。

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || this.getClass() != o.getClass()) return false;
    UserDto userDto = (UserDto) o;
    return this.id.equals(userDto.id);
}

And implement a Comparator for UserDto class. This is going to be used to sort both lists.并为 UserDto class 实现一个比较器。这将用于对两个列表进行排序。

public class UserDtoComparatorById implements Comparator<UserDto> {
    @Override
    public int compare(UserDto o1, UserDto o2) {
        return o1.getId().compareTo(o2.getId());
    }
}

Finally.最后。

@Test
void findAllUsers() {
    when(userService.findAll()).thenReturn(sampleUsers());
    ResponseEntity<List<UserDto>> responseEntity = userController.findAll();

    //first assert
    assertEquals(responseEntity.getStatusCode().value(), 200);

    //second assert (this is optional)
    assertEquals(responseEntity.getBody().size(), sampleUsers().size());
   
    // to prevent false negatives, in case both lists have same objects
    // but different orders 
    Comparator<UserDto> comparator = new UserDtoComparatorById();
    sampleUsers.sort(comparator);
    responseEntity.getBody().sort(comparator);

    //third assert
    assertEquals(responseEntity.getBody(), sampleUsers);

    //same assertion but using streams
    AtomicInteger i = new AtomicInteger(0);
    assertEquals(
        list1.stream()
             .filter(user -> user.equals(list2.get(i.getAndIncrement())))
             // or: filter(user -> user.getId().equals(list2.get(i.getAndIncrement()).getId()))
             .count(), 
        list1.size()
    );
}

The third assert will work because both lists are sorted and assertEquals() will invoke UserDto.equals() for each element in the same position. As UserDto.equals() is overridden to check only UserDto.id , it will check the id instead of the Object pointer (address in memory), therefore returning true.第三个断言将起作用,因为两个列表都已排序并且 assertEquals() 将为同一 position 中的每个元素调用UserDto.equals() 。由于 UserDto.equals() 被覆盖以仅检查UserDto.id ,它将检查id而不是Object pointer (内存中的地址),因此返回 true。

Note that in the second alternative you can not use int i because variables inside lambda functions need to be final.请注意,在第二种选择中,您不能使用int i ,因为 lambda 函数中的变量需要是最终变量。 A simple workaround is using AtomicInteger .一个简单的解决方法是使用AtomicInteger

One way is to assert each element of the stream separately which can be done with the help of following code.一种方法是分别断言 stream 的每个元素,这可以在以下代码的帮助下完成。 You can write a function for asserting streams.您可以编写一个 function 来断言流。

static void assertStreamEquals(Stream<User> s1, Stream<User> s2) {
    Iterator<Student> iter1 = s1.iterator(), iter2 = s2.iterator();
    while(iter1.hasNext() && iter2.hasNext())
        assertEquals(iter1.next().id, iter2.next().id);
    assert !iter1.hasNext() && !iter2.hasNext();
}

and call it by passing your two streams.并通过传递你的两个流来调用它。

@Test
void findAllUsers() {
    when(userService.findAll()).thenReturn(sampleUsers());
    ResponseEntity<List<UserDto>> responseEntity = userController.findAll();

    //first assert
    assertEquals(responseEntity.getStatusCode().value(), 200);

    //second assert
    assertEquals(responseEntity.getBody().size(), sampleUsers().size());

    //third assert
    assertStreamEquals(responseEntity.getBody(),sampleUsers);

(Assuming User is the class name for users) (假设User为class用户名)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM