我正在练习书#34; Java SE 8 for the Really Impatient"作者:Cay S. Horstmann。有2个练习要求使用同一算法的不同实现,一个使用merge
,另一个使用computeIfAbsent
。我已使用merge
实施了该计划,但无法弄清楚如何使用computeIfAbsent
执行相同的操作。在我看来computeIfPresent
会更合适,因为merge
仅在密钥存在时才有效,computeIfPresent
也是如此。
问题陈述:
编写一个应用程序,其中多个线程读取a中的所有单词 文件集合。使用
ConcurrentHashMap<String, Set<File>>
来 跟踪每个单词出现的文件。使用merge
方法进行更新 地图。
我的代码使用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);
}
}
}
答案 0 :(得分:2)
专注于必须完成的事情,如果值不存在。您需要做的是为缺席条目创建新的Set
值。当然,如果您使用仅对Set
的创建具有原子性保证的操作,则会同时添加Set
,这需要使用并发{ {1}}。您可以通过映射到固定值来利用Set
来创建事实上的ConcurrentHashMap
(在该格式中不存在),如果您让值信令存在为{{ {1}}:
ConcurrentHashSet
答案 1 :(得分:0)
我使用function get_write_user_values() {
var promise = $.ajax({ ... }) // remove the success and error handlers
.then(onSuccess, onError)
function onSuccess(data) {
// do stuff to the data
return processed_data;
}
function onError(err) {
console.log('An error with the api');
return err;
}
return promise;
}
function get_non_authorized_bulk_edit_option_values() {
get_write_user_values()
.then (function (processed_data) {
alert(processed_data);
});
}
并按扩展名“.txt”过滤文件。
结果显示在控制台中。
对于IntelliJ IDEA IDE:如果结果不完整,则检查并增加“覆盖控制台循环缓冲区大小”(文件/设置/编辑器/常规/控制台)。
导入列表:
computeIfAbsent
我解决了这个任务:
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
致电public static void printMap(Path path){
try (Stream<Path> stream = Files.walk(path)){
ConcurrentHashMap<String, Set<File>> map = new ConcurrentHashMap<>();
stream.parallel()
.filter(p -> !(Files.isDirectory(p)) & p.getFileName()
.toString()
.toLowerCase()
.endsWith(".txt"))
.collect(Collectors.toList())
.forEach((p) -> {
try {
Files.lines(p, StandardCharsets.UTF_8)
.flatMap(s -> Arrays.asList(s.split("\\PL+")).stream())
.filter(w -> w.length() > 0)
.map(String::toLowerCase)
.parallel()
.forEach(
key -> {
Set<File> tempSet = new HashSet<>();
tempSet.add(new File(p.toString()));
map.computeIfAbsent(key, x -> ConcurrentHashMap.newKeySet())
.addAll(tempSet);
});
} catch (IOException e){
} catch (UncheckedIOException e){}
});
map.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.forEach(System.out::println);
} catch (IOException e){}
}
:
printMap()
如果需要使用public static void main(String[] args){
Path path = Paths.get(*somePathName*);
printMap(path);
}
,则只需替换
merge
到
map.computeIfAbsent(key, x -> ConcurrentHashMap.newKeySet()).addAll(tempSet);