Java 8流api中的条件检查

时间:2019-01-02 22:13:02

标签: java java-8 java-stream

我有以下现有的实现

CompletableFuture<Employee>[] employeeDetails =
            empIds.stream().map(empId ->
                employeeService.employeeDetails(Integer.valueOf(empId)))
            .filter(Objects::nonNull)
            .toArray(CompletableFuture[]::new);

在此代码中,我需要在HashMap中检查empId是否已经存在或如下所示-如果empId在HashMap中不存在,则调用service并将其放入HashMap中以备将来使用。

Map<String, CompletableFuture<Employee>[]> employeeCache = new HashMap<>();

..........

CompletableFuture<Employee>[] employeeDetails =
            empIds.stream().map(empId ->

            //Here I need to check in HashMap that empId is present or not if present then fetch from Map instead of calling service.

                employeeService.employeeDetails(Integer.valueOf(empId)))
            .filter(Objects::nonNull)
            .toArray(CompletableFuture[]::new);

如何添加if API(如上所示),并在stream() API中进行检查,如果存在的话,请从Map中获取。

3 个答案:

答案 0 :(得分:3)

您可以使用Map#computeIfAbsent来完成您想做的事情:

Map<String, CompletableFuture<Employee>[]> employeeCache = new HashMap<>();

CompletableFuture<Employee>[] employeeDetails = empIds.stream()
                .map(empId -> employeeCache
                        .computeIfAbsent(empId, k -> employeeService.employeeDetails(Integer.valueOf(empId))))
                        .filter(Objects::nonNull)
                        .toArray(CompletableFuture[]::new);

答案 1 :(得分:1)

您可能会使用Optional.ofNullable(因为Map中缺少密钥会返回null)和Optional.orElseGet(当值是' Map操作中的Stream.map)中显示为:

CompletableFuture<Employee>[] employeeDetails = empIds.stream()
        .map(empId -> Optional.ofNullable(employeeCache.get(empId))
                .orElseGet(() -> employeeService.employeeDetails(Integer.valueOf(empId))))
        .filter(Objects::nonNull)
        .toArray(CompletableFuture[]::new);

或如Aomine在评论中所建议的,您也可以简单地使用getOrDefault

CompletableFuture<Employee>[] employeeDetails = empIds.stream()
        .map(empId -> employeeCache.getOrDefault(empId, 
                employeeService.employeeDetails(Integer.valueOf(empId))))
        .filter(Objects::nonNull)
        .toArray(CompletableFuture[]::new);

如果您也想放入缓存,则可以简单地使用Map.putIfAbsent来放置(如果不存在):

CompletableFuture<Employee>[] employeeDetails = empIds.stream()
        .map(empId -> employeeCache.putIfAbsent(empiId, employeeService.employeeDetails(Integer.valueOf(empId))))
        .filter(Objects::nonNull)
        .toArray(CompletableFuture[]::new);

如果您还想在从服务中进行更新时也更新缓存,则最好不要在此处使用流:

List<CompletableFuture<Employee>[]> list = new ArrayList<>();
for (String empId : empIds) {
    CompletableFuture<Employee>[] completableFutures = employeeCache.putIfAbsent(employeeService.employeeDetails(Integer.valueOf(empId)));
    if (completableFutures != null) {
        list.add(completableFutures);
    }
}
CompletableFuture<Employee>[] employeeDetails = list.toArray(new CompletableFuture[0]);

此外,所有这些(如果我是您的话)我都将使用Guava的LoadingCache,即使使用自定义的CacheLoader实现,它也可以提供类似的好处。

有关其的更多详细信息,您可以阅读他们的Wiki-CachesExplained

答案 2 :(得分:0)

如果您不再需要└───genericScraper ├───spiders │ └───__pycache__ └───__pycache__ 映射,即,如果仅将其用作employeeCache操作中的本地缓存,则可以通过通用实用程序方法将其抽象化: / p>

Stream.map

这称为memoization,是一项众所周知的技术,尤其是在函数编程中。

然后,您将在示例中使用它,如下所示:

public static <T, U> Function<T, U> memoize(Function<T, U> f) {
    Map<T, U> m = new HashMap<>();
    return t -> m.computeIfAbsent(t, f);
}

如您所见,这对于调用者代码是完全透明的,并且确实会将地图用作缓存。

编辑:请注意,我只使用了常见的CompletableFuture<Employee>[] employeeDetails = empIds .stream() .map(memoize(empId -> employeeService.employeeDetails(Integer.valueOf(empId)))) .filter(Objects::nonNull) .toArray(CompletableFuture[]::new); ,因为我注意到流是按顺序运行的。如果要并行运行流,则应将缓存更改为HashMap