首页 > 解决方案 > 在收集流时搜索 JDK 等效项以进行转换

问题描述

问题

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

我自己的解决方案

我发现您可以使用Collectors.groupingBy将 aList转换为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(当然也可以是任何其他类型的集合)。我感觉我缺少一些功能,但我看不到哪个功能。

标签: javafunctional-programmingjava-streamcollectors

解决方案


您不需要定义任何额外的方法。您可以执行以下操作Collectors.mappinggroupingBy

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())));

推荐阅读