在收集流时搜索 JDK 等价物进行转换

Searching for JDK equivalent for transforming while collecting stream

问题

我有一个 ListRequest 个对象,其中每个请求都包含原始主机和请求的 URL。我想将其转换为 Map<String, Set<String>>,其中键是主机,值是主机调用的唯一 URL。

我自己的解决方案

我发现您可以使用 Collectors.groupingByList 转换为 Map。这似乎是工作的方法,但它不符合我的全部需求。我不得不创建一个额外的功能:

    private static <T, K> Collector<T, ?, Set<K>> toSet(Function<? super T, ? extends K> mapper) {
        return Collector.of(
                HashSet::new,
                (list, item) -> list.add(mapper.apply(item)),
                (list1, list2) -> {
                    list1.addAll(list2);
                    return list1;
                }
        );
    }

使用这个函数,我可以这样做:

Map<String, Set<String>> hostUrls = getRequests().stream()
    .map(r -> new ImmutablePair<>(r.getOriginHost(), r.getRequestUrl()))
    .collect(Collectors.groupingBy(ImmutablePair::getLeft, toSet(ImmutablePair::getRight)));

问题

有没有什么方法可以在不创建这个额外的 toSet 函数的情况下进行这种转换?

我的愿望似乎没有那么极端。在将所有内容收集到一个 Set 之前,我想要一些额外的映射(当然也可以是任何其他类型的集合)。我觉得我缺少一些功能,但我看不到哪个。

您不需要定义任何额外的方法。您可以在 groupingBy 之后执行 Collectors.mapping,如下所示。

Collectors.mapping 有两个参数。第一个是映射器,第二个是下游。

 Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,
                               Collector<? super U, A, R> downstream)

通过使用 toSet 下游,您可以完成您的任务。

Map<String, Set<String>> map = getRequests().stream()
          .collect(Collectors.groupingBy(Request::getOriginHost,
                 Collectors.mapping(Request::getRequestUrl, Collectors.toSet())));