Java-8使用lambdas过滤两组

时间:2017-11-05 12:18:46

标签: java lambda java-8 java-stream

我有两套角色。一个来自数据库,另一个来自UI。我还根据角色的名称编写了两个角色的比较方法。

问题:如果比较值使用lambdas表达式返回true,我想提取角色(保留数据库中的一个)。

matchingRoleNames效果很好,但我没有寻找最好的lambdas做法,而没有循环。 这是我的设定结果,工作正常:

Set<Role> rolesFromUI = user.getRolesFromUI();
Stream <Role> roleStreamFromDB = roleService.getAllRolesStreamFromDatabase();

Set<Role> matchingRoleNames = roleStreamFromDB.filter(role-> 
        {   
            for(Role roleTmp:rolesFromUI){
                if(roleTmp.compareTo(role)==0){
                    return true;
                }
            }
            return false;
        })

public int compareTo(Role role){
      return this.roleName.compareTo(role.getRoleName());       
}

谢谢

2 个答案:

答案 0 :(得分:1)

而不是在第一个流的filter中间操作中使用for each循环,您可以只流过另一个集合,看看其中的任何元素是否与第一个流的任何元素匹配。

即:

Set<Role> matchingRoleNames = roleStreamFromDB.filter(e -> rolesFromUI.stream().anyMatch( x -> x.compareTo(e) == 0))
                                              .collect(Collectors.toSet());

答案 1 :(得分:1)

正如您所说,您希望按名称比较角色,您可以通过首先将UI角色的名称收集到Set来执行您想要的操作,然后在过滤数据库角色时,只需检查是否当前角色的名称位于集合中:

// Collect UI role names
Set<String> uiRoleNames = user.getRolesFromUI().stream()
    .map(Role::getRoleName)
    .collect(Collectors.toSet());

// Filter DB roles
Set<Role> filteredRoles = roleService.getAllRolesStreamFromDatabase()
    .filter(role -> uiRoleNames.contains(role.getRoleName()))
    .collect(Collectors.toSet());

这既简单又有效,因为Set返回的Collectors.toSet()预计会有效查找(这意味着其contains方法将为O(1)平均情况)。

如果您想100%确定O(1)的返回集合为contains,您可以按如下方式收集UI角色名称:

Set<String> uiRoleNames = user.getRolesFromUI().stream()
    .map(Role::getRoleName)
    .collect(Collectors.toCollection(HashSet::new));