请帮我找出以下方法有什么问题以及如何解决。该方法采用
Person
对象流和 Map,其中 String 值(任务名称)作为键,int 值(标记)。该方法的目的是检查流是否包含 allHistoryTasks
变量中的特定任务,以及是否适用于该 Map。 putIfAbsentmethod(taskName, 0)
确保所有任务都出现在地图中(目的是为了稍后计算平均分)。
当我运行测试时,出现
UnsupportedOperationException
错误。当我评论从 if
语句到 forEach
(第 1、2、3、4 行)的行时,测试运行良好。我是Java新手,已经在这个问题上花了好几天了,但仍然无法解决。请告诉我这里出了什么问题。
private Set<String> allHistoryTasks = Set.of("Phalanxing", "Shieldwalling", "Tercioing", "Wedging");
private String[] historyTasks = allHistoryTasks.toArray(new String[0]);
public Map<Person, Map<String, Integer>> addHistoryIfPresent(Stream<CourseResult> stream) {
return stream.collect(Collectors.toMap(
CourseResult::getPerson,
x -> {
if (allHistoryTasks.containsAll(x.getTaskResults().keySet())) //1
IntStream.range(0, allHistoryTasks.size()) //2
.parallel() //3
.forEach(i -> x.getTaskResults().putIfAbsent(historyTasks[i], 0)); //4
return x.getTaskResults();
}
));
}
x -> {}
块是“值映射器”。它应该将流的元素转换为给定地图的值。
您有一个
CourseResult
对象流,并且想要一个 Map<Person, Map<String, Integer>>, so this function turns a
CourseResultobject into a
Map你可以通过改变事物来做到这一点,这是一个非常严重的问题。您的流函数不应该有任何副作用。幸运的是,
CourseResult
的作者远远领先于你,阻止了你犯这个错误。您正在对课程结果对象调用 .getTaskResults()
,然后尝试修改它。您不能这样做,因为 getTaskResults()
方法返回无法修改的地图。
大概,您想要克隆该地图,并修复克隆。你是怎样做的?好吧,你告诉我,API 不清楚。您可以简单地创建一个新的
ImmutableMap.builder()
,循环遍历您想要循环的任何内容,依此类推。从您的代码来看,不太清楚您想要什么最终地图。
还要注意,您在不知道自己在做什么的情况下使用权力 - 您有一个并行流,然后通过它进行 forEaching,改变同一个变量,这是您绝对不能做的:这会导致错误,其中结果为一个操作取决于一次邪恶的硬币翻转,从某种意义上说,即使您重新运行测试一百万次,但明天就会失败,它今天也可以正常工作。另外,使用
parallel()
进行此类讨论是近乎疯狂的 - 假设底层流实现实际上是并行化的(.parallel()
是一个提示,而不是需求),它只会减慢一切。 allHistoryTasks
很小。这不是并行性的用途。
这可能是您问题的答案。
Set.of
方法不会返回可变集。所以你需要像这样声明一个可变集来避免这个问题。
private Set<String> allHistoryTasks = new HashSet<>(Arrays.asList("Phalanxing", "Shieldwalling", "Tercioing", "Wedging"));
private String[] historyTasks = allHistoryTasks.toArray(new String[0]);
public Map<Person, Map<String, Integer>> addHistoryIfPresent(Stream<CourseResult> stream) {
return stream.collect(Collectors.toMap(
CourseResult::getPerson,
x -> {
if (allHistoryTasks.containsAll(x.getTaskResults().keySet())) //1
IntStream.range(0, allHistoryTasks.size()) //2
.parallel() //3
.forEach(i -> x.getTaskResults().putIfAbsent(historyTasks[i], 0)); //4
return x.getTaskResults();
}
));
}