我有以下现有的实现
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中获取。
答案 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
。