【问题标题】:Is it possible to apply joiner (collector, accumulator) over function using Java Guava?是否可以使用 Java Guava 在函数上应用连接器(收集器、累加器)?
【发布时间】:2016-06-02 10:06:38
【问题描述】:

是否可以在分组时收集字符串而不是收集?这就是它在 Java 8 中的工作方式:

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

我很好奇,在 Google Guava 中有简洁的方法吗?这就是我尝试在 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);
        }
    });

【问题讨论】:

  • 当您说“在 Google Guava 中执行”时,您的意思是“在没有 Java 8 语言特性的情况下执行”吗?或者你为什么不对这些函数式接口使用 lambda 表达式/方法?
  • 是的,没有 Java 8,我的目标是以更命令式的方式完成。

标签: java collections guava java-stream joiner


【解决方案1】:

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

Java 8 之前的函数式编程可以与 Guava 的函数式实用程序一起使用,但 as they warn:

从 Java 7 开始,Java 中的函数式编程只能通过笨拙和冗长地使用匿名类来近似。过度使用 Guava 的函数式编程习惯会导致冗长、混乱、不可读, 和低效的代码.... 从 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 类中提取数据 - 这些似乎是明确的候选者是实例方法。同样,您可以考虑创建一个 Discounts 类,该类包含一个或多个 DiscountOption 实例,并提供一个 toString() 返回逗号分隔的字符串。然后你只需要构造你的 Discounts 对象就可以了。

【讨论】:

  • “你不会得到比 Java 8 流 API 更简洁的东西”,除非你使用像 Kotlin 这样的东西。 Kotlin 的字节码与 Java 6 及更高版本 (FAQ - Kotlin Programming Language) 兼容。
  • @mfulton26 不允许将讨论打开到其他语言;在更简洁的语言中显然有更简洁的替代方案。问题是关于 Java 和 Guava,而不是任意 JVM 语言。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-12
  • 1970-01-01
相关资源
最近更新 更多