我正在使用Cay S. Horstmann的书“
Java SE 8 for the Really Impatient”进行练习.有两个练习要求同一算法的不同实现,一个使用合并,另一个使用computeIfAbsent.我已经使用merge实现了该程序,但无法弄清楚如何使用computeIfAbsent来做同样的事情.在我看来,computeIfPresent更适合,因为merge仅在密钥存在时才有效,而computeIfPresent也是如此.
问题陈述:
Write an application in which multiple threads read all words from a
collection of files. Use aConcurrentHashMap<String, Set<File>>
to
track in which files each word occurs. Use themerge
method to update
the map.
我的代码使用merge:
public static Map<String, Set<File>> reverseIndexUsingMerge(final Path path)
throws IOException {
final ConcurrentHashMap<String, Set<File>> map = new ConcurrentHashMap<>();
final BiConsumer<? super String, ? super Set<File>> action = (key,
value) -> map.merge(key, value, (existingValue, newValue) -> {
LOGGER.info("Received key: {}, existing value: {}, new value: {}.",
key, existingValue, newValue);
newValue.addAll(existingValue);
return newValue;
});
commonPool().invokeAll(
find(path, 1,
(p, fileAttributes) -> fileAttributes.isRegularFile())
.map(p -> new ReverseIndex(p, action))
.collect(toList()));
return unmodifiableMap(map);
}
private static class ReverseIndex implements Callable<Void> {
private final Path p;
private final BiConsumer<? super String, ? super Set<File>> action;
private static final Pattern AROUND_WHITESPACE = compile("\\s");
private ReverseIndex(final Path p,
final BiConsumer<? super String, ? super Set<File>> action) {
this.p = p;
this.action = action;
}
@Override
public Void call() throws Exception {
reverseIndex().forEach(action);
return null;
}
private Map<String, Set<File>> reverseIndex() {
/* File stream needs to be closed. */
try (Stream<String> lines = lines(p, UTF_8)) {
return lines.flatMap(AROUND_WHITESPACE::splitAsStream)
.collect(
groupingBy(String::toString,
mapping(word -> p.toFile(), toSet())));
} catch (IOException e) {
LOGGER.error("Something went wrong. Get the hell outta here.",
e);
throw new UncheckedIOException(e);
}
}
}
最佳答案 如果价值不存在,请关注必须做的事情.您需要做的是为缺席条目创建新的Set值.当然,如果您使用具有原子性保证的操作来创建Set,则添加到Set将同时发生,这需要使用并发Set.您可以利用ConcurrentHashMap通过映射到固定值来创建事实上的ConcurrentHashSet(在该表单中不存在),如果您让值信令存在为Boolean,则这一点特别简单.TRUE:
ConcurrentHashMap<String, Set<File>> map=new ConcurrentHashMap<>();
final BiConsumer<? super String, ? super Set<File>> action =
(key, value) -> map.computeIfAbsent(key, x->ConcurrentHashMap.newKeySet())
.addAll(value);