Можно ли применить joiner (сборщик, аккумулятор) над функцией с помощью Java Guava?
Можно ли собирать строки поверх коллекции во время группировки? Вот как это работает в Java 8:
Map<String, String> discountOptions = p.getDiscountOptions().Stream()
.collect(groupingBy(
this::getDiscountName,
Collectors.mapping(this::getValue, Collectors.joining(","))));
Мне любопытно, есть ли краткий способ сделать это в Google 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);
}
});
1 ответ
Вы не получите ничего более краткого, чем API потоков Java 8, поскольку причина, по которой он существует, заключается в улучшении такого рода операций.
Функциональное программирование до Java 8 может быть связано с функциональными утилитами Guava, но, как они предупреждают:
Начиная с 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
объекты, и вы хорошо идти.