是否可以使用 Java Guava 将连接器(收集器、累加器)应用于函数?

Is it possible to apply joiner (collector, accumulator) over function using Java Guava?

是否可以在分组时通过集合收集字​​符串?这就是它在 Java 8:

中的工作方式
Map<String, String> discountOptions = p.getDiscountOptions().Stream()
    .collect(groupingBy(
        this::getDiscountName,
        Collectors.mapping(this::getValue, Collectors.joining(","))));

我很好奇,GoogleGuava 有没有简洁的方法?这就是我尝试在 Guava 中复制它的方式:

Map<String, Collection<String>> stringCollectionMap = Multimaps.transformValues(
    Multimaps.index(p.getDiscountOptions(), 
        new Function<DiscountOption, String>() {
            @Override
            public String apply(DiscountOption d) {
                return getDiscountName(d);
            }
        }),
    new Function<DiscountOption, String>() {
        @Override
        public String apply(DiscountOption d) {
            return getValue(d);
        }
    }).asMap();

Map<String, String> discountOptions =  Maps.transformValues(
    stringCollectionMap,
    new Function<Collection<String>, String>() {
        @Override
        public String apply(Collection<String> strings) {
            return Joiner.on(",").join(strings);
        }
    });

你不会得到比 Java 8 个流 API 更简洁的东西,因为它存在的原因是为了改进这些操作。

Pre-Java 8 函数式编程可以使用 Guava 的函数式实用程序进行临时装配,但是 as they warn:

As of Java 7, functional programming in Java can only be approximated through awkward and verbose use of anonymous classes.... Excessive use of Guava's functional programming idioms can lead to verbose, confusing, unreadable, and inefficient code.... Imperative code should be your default, your first choice as of Java 7.

这是您的代码的命令式翻译:

private static final Joiner COMMA_JOINER = Joiner.on(",");

ListMultimap<String, String> groupedByDiscountName = ArrayListMultimap.create();
for (DiscountOption option : p.getDiscountOptions()) {
  groupedByDiscountName.put(getDiscountName(option), getValue(option));
}

ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
for (Entry<String, Collection<String>> e : groupedByDiscountName.asMap().entrySet()) {
  builder.put(e.getKey(), COMMA_JOINER.join(e.getValues());
}
Map<String, String> discountOptions = builder.build();

它更短更易于阅读。鉴于您目前的 API 这大概是您使用 Java 7.

所能做的最好的事情了

也就是说您可能会考虑重新检查您的 API - 特别是您使用静态方法(getDiscountName()getValue())从您的 DiscountOption class - 这些似乎是实例方法的明确候选者。同样,您可能会考虑创建一个 Discounts class,其中包含一个或多个 DiscountOption 实例,并提供一个 toString() returns 您的逗号分隔字符串。然后你只需要构建你的 Discounts 对象就可以了。