提问者:小点点

Java Streams:收集一个long流的复杂度和基于Set::contains过滤它的复杂度一样吗?


我有一个应用程序,它接受员工ID作为用户输入,然后过滤员工列表以查找匹配的ID。用户输入应该是3-4个id,员工列表是几千个。

基于性能考虑,我使用Streams过滤器提出了以下两种方法。

方法1

这里的动机是不要为每个员工运行过滤器,而是在请求的id列表上运行它,该列表保证非常短。

private static Set<Long> identifyEmployees(CustomRequest request)
  List<Long> requestedIds = request.getRequestedIDs();                            
  if (!requestedIds.isEmpty()) {
      Set<Long> allEmployeeIds = 
              employeeInfoProvider
                .getEmployeeInfoList()  // returns List<EmployeeInfo>
                .stream()
                .map(EmployeeInfo::getEmpId)  // getEmpId() returns a Long
                .collect(Collectors.toSet());

      return requestedIds.stream().filter(allEmployeeIds::contains).collect(Collectors.toSet());         
  }
  return Collections.emptySet();
}

方法2

这里的动机是用过滤器替换Method1中的collect(),因为复杂性是相同的。这里的collect()实际上运行在非常少的元素上。

private static Set<Long> identifyEmployees(CustomRequest request)
  Set<Long> requestedIds = request.getRequestedIDs()   // returns List<Long>
                          .stream()
                          .collect(Collectors.toSet());
  if (!requestedIds.isEmpty()) {
      return employeeInfoProvider
               .getEmployeeInfoList()  // returns List<EmployeeInfo>
               .stream()
               .map(EmployeeInfo::getEmpId)  // getEmpId() returns a Long
               .filter(requestedIds::contains)
               .collect(Collectors.toSet());
  }
  return Collections.emptySet();
}

方法2的表现和方法1一样好吗?还是方法1表现更好?


共2个答案

匿名用户

我希望 Method2 在所有情况下都能表现得一样好或更好。

收集到中间集会增加分配开销。如果有许多重复,它减少了您以后必须执行的< code > requested ids::contains 调用的数量,但是即使这样,您也是将每个< code>Set::add调用交换为一个< code>Set::contains调用,每个调用都应该是一个小小的胜利。

匿名用户

一个可能更快(不是更干净)的选择是在检测到所有requestedIds后立即返回,但我不确定是否可以用Stream API实现。

private static Set<Long> identifyEmployees(CustomRequest request) {
    Set<Long> requestedIds = request.getRequestedIDs()   // returns List<Long>
            .stream()
            .collect(Collectors.toSet());
    Set<Long> result = new HashSet<>();
    if (!requestedIds.isEmpty()) {
        Iterator<EmployeeInfo> employees = employeeInfoProvider.getEmployeeInfoList().iterator();
        while (result.size() < requestedIds.size() && employees.hasNext()) {
            Long employeeId = employees.next().getEmpId();
            if (requestedIds.contains(employeeId)) {
                result.add(employeeId);
            }
        }
    }
    return result;
}

但是,只有当employeeInfoProvider.get员工信息列表()返回具有相同ID的多个员工重复项时才有意义。否则,如上所述,方法2是更好的选择。