Skip to content

Instantly share code, notes, and snippets.

@gakuzzzz
Last active September 25, 2023 06:40
Show Gist options
  • Save gakuzzzz/9f35617943decf2893ea to your computer and use it in GitHub Desktop.
Save gakuzzzz/9f35617943decf2893ea to your computer and use it in GitHub Desktop.
MapStreamSyntax

Java8 の Stream で Map を操作するサポート作った

MapStreamSyntax というクラスで基本的に static import して使います。

具体例を見てもらえばどの辺が便利なのか伝わるでしょうか?

Case.1

// JDK標準APIのみ
public Map<Integer, String> Case1_Before(final Map<Integer, String> map) {
    return map.entrySet().stream()
        .filter(entry -> !entry.getValue().isEmpty())
        .map(entry -> new SimpleImmutableEntry<>(entry.getKey(), entry.getValue().toUpperCase()))
        .collect(toMap(Entry::getKey, Entry::getValue));
}
// MapStreamSyntax使用
public Map<Integer, String> Case1_After(final Map<Integer, String> map) {
    return map.entrySet().stream()
        .filter(byValue(value -> !value.isEmpty()))
        .map(values(String::toUpperCase))
        .collect(entryToMap());
}

Case.2

// JDK標準APIのみ
public String Case2_Before(final Map<Integer, String> map) {
    return map.entrySet().stream()
        .map(entry -> entry.getKey() + " = " + entry.getValue())
        .collect(joining(", "));
}
// MapStreamSyntax使用
public String Case2_After(final Map<Integer, String> map) {
    return map.entrySet().stream()
        .map(toAny((key, value) -> key + " = " + value))
        .collect(joining(", "));
}

Case.3

// JDK標準APIのみ
public Map<ID<User>, Name<Organization>> Case3_Before(final List<User> users) {
    return users.stream()
        .map(user -> new SimpleImmutableEntry<>(user.getId(), primaryOrganization(user)))
        .filter(entry -> entry.getValue().isOpened())
        .map(entry -> new SimpleImmutableEntry<>(entry.getKey(), entry.getValue().getName())))
        .collect(toMap(Entry::getKey, Entry::getValue));
}
// MapStreamSyntax使用
public Map<ID<User>, Name<Organization>> Case3_After(final List<User> users) {
    return users.stream()
        .map(toEntry(User::getId, this::primaryOrganization))
        .filter(byValue(Organization::isOpened))
        .map(values(Organization::getName))
        .collect(entryToMap());
}
// 関連コード
public static final class User {
    private final ID<User> id;
    private final Name<User> name;
    // Constructor, Getter 省略
}
public static final class Organization {
    private final ID<Organization> id;
    private final Name<Organization> name;
    private final boolean opened;
    // Constructor, Getter 省略
}

// ちょっと重いので同じUserに対して何回も繰り返し呼びたくない
private Organization primaryOrganization(final User user) {...}

MIT License にしとくので適当にコピペして使ってください。

/*
* MapStreamSyntax
*
* Copyright(c) gakuzzzz
*
* This software is released under the MIT License.
* http://opensource.org/licenses/mit-license.php
*/
package jp.t2v.lab.syntax;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
public class MapStreamSyntax {
public static <E, K, V> Function<E, Map.Entry<K, V>> toEntry(final Function<? super E, ? extends K> ketFactory, final Function<? super E, ? extends V> valueFactory) {
return e -> new SimpleImmutableEntry<>(ketFactory.apply(e), valueFactory.apply(e));
}
public static <K1, V1, R> Function<Map.Entry<K1, V1>, R> toAny(final BiFunction<? super K1, ? super V1, ? extends R> f) {
return e -> f.apply(e.getKey(), e.getValue());
}
public static <K1, K2, V> Function<Map.Entry<K1, V>, Map.Entry<K2, V>> keys(final Function<? super K1, ? extends K2> f) {
return e -> new SimpleImmutableEntry<>(f.apply(e.getKey()), e.getValue());
}
public static <K, V, R> Function<Map.Entry<K, V>, R> keyToAny(final Function<? super K, ? extends R> f) {
return e -> f.apply(e.getKey());
}
public static <K, V> Predicate<Map.Entry<K, V>> byKey(final Predicate<? super K> f) {
return e -> f.test(e.getKey());
}
public static <K, V1, V2> Function<Map.Entry<K, V1>, Map.Entry<K, V2>> values(final Function<? super V1, ? extends V2> f) {
return e -> new SimpleImmutableEntry<>(e.getKey(), f.apply(e.getValue()));
}
public static <K, V, R> Function<Map.Entry<K, V>, R> valueToAny(final Function<? super V, ? extends R> f) {
return e -> f.apply(e.getValue());
}
public static <K, V> Predicate<Map.Entry<K, V>> byValue(final Predicate<? super V> f) {
return e -> f.test(e.getValue());
}
public static <K, V> Collector<Map.Entry<K, V>, ?, Map<K, V>> entryToMap() {
return Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue);
}
public static <K, V> Collector<Map.Entry<K, V>, ?, Map<K, V>> entryToMap(final BinaryOperator<V> mergeFunction) {
return Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, mergeFunction);
}
public static <K, V, M extends Map<K, V>> Collector<Map.Entry<K, V>, ?, M> entryToMap(final BinaryOperator<V> mergeFunction, final Supplier<M> mapSupplier) {
return Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, mergeFunction, mapSupplier);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment