All Downloads are FREE. Search and download functionalities are using the official Maven repository.

shz.ToMap Maven / Gradle / Ivy

package shz;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Stream;

@SuppressWarnings("unchecked")
public final class ToMap {
    private final Map map;

    private ToMap(int initialCapacity, int idx, boolean dummy) {
        map = dummy ? new LinkedHashMap<>(reduce(initialCapacity, idx), 1.0f)
                : new HashMap<>(reduce(initialCapacity, idx), 1.0f);
    }

    private static final int MAX = 1 << 30;

    static int reduce(int cap, int idx) {
        if (idx <= 0 || cap == 1) return (int) Math.ceil(cap / 0.75f);
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        n = n >= MAX ? MAX : n + 1;
        while (idx-- > 0) {
            if (n < 2) break;
            n >>>= 1;
        }
        return (int) Math.ceil(n / 0.75f);
    }

    public static  ToMap get(int initialCapacity, int idx, boolean dummy) {
        return new ToMap<>(initialCapacity, idx, dummy);
    }

    public static  ToMap get(int initialCapacity, int idx) {
        return new ToMap<>(initialCapacity, idx, false);
    }

    public static  ToMap get(int initialCapacity) {
        return new ToMap<>(initialCapacity, 0, false);
    }

    public  T build() {
        return (T) map;
    }

    public ToMap put(Map m) {
        map.putAll(m);
        return this;
    }

    public  ToMap put(KK k, VV v) {
        map.put(k, v);
        return this;
    }

    public static > Collector collector(
            Function keyMapper, Function valueMapper,
            BinaryOperator mergeFunction, Supplier mapSupplier) {
        return Collector.of(
                mapSupplier,
                //替换默认merge方法
                (map, element) -> merge(keyMapper.apply(element), valueMapper.apply(element), map, mergeFunction),
                (m1, m2) -> {
                    for (Map.Entry e : m2.entrySet()) merge(e.getKey(), e.getValue(), m1, mergeFunction);
                    return m1;
                }
        );
    }

    private static > void merge(K key, V value, M map, BinaryOperator mergeFunction) {
        V oldValue;
        if ((oldValue = map.get(key)) == null) {
            //原key的值为null则使用新值(包括null)
            map.put(key, value);
            return;
        }
        //原key的值不为null则使用具体的取值策略
        map.put(key, mergeFunction.apply(oldValue, value));
    }

    /**
     * 大致确定元素个数时的收集器
     *
     * @param keyMapper       键映射器
     * @param valueMapper     值映射器
     * @param initialCapacity 大致确定的初始容量
     * @param idx             初始容量衰减次数
     * @param dummy           是否排序的
     */
    public static  Collector> collector(
            Function keyMapper, Function valueMapper, int initialCapacity, int idx, boolean dummy) {
        return collector(keyMapper, valueMapper,
                //原key的值不为null时的取值策略,默认策略为抛出异常,这里选择若新值不为null则替换原来的值
                (oldValue, newValue) -> newValue == null ? oldValue : newValue,
                //提供初始化容量的HashMap(若dummy为true则为LinkedHashMap)
                () -> get(initialCapacity, idx, dummy).build()
        );
    }

    public static  Collector> collector(
            Function keyMapper, Function valueMapper, int initialCapacity, int idx) {
        return collector(keyMapper, valueMapper, initialCapacity, idx, false);
    }

    public static  Collector> collector(
            Function keyMapper, Function valueMapper, int initialCapacity) {
        return collector(keyMapper, valueMapper, initialCapacity, 0, false);
    }

    /**
     * 大致确定元素个数时的流收集
     */
    public static  Map explicitCollect(
            Stream stream, Function keyMapper, Function valueMapper, int initialCapacity, int idx, boolean dummy) {
        Map map = stream.collect(collector(keyMapper, valueMapper, initialCapacity, idx, dummy));
        return map.isEmpty() ? Collections.emptyMap() : map;
    }

    public static  Map explicitCollect(
            Stream stream, Function keyMapper, Function valueMapper, int initialCapacity) {
        return explicitCollect(stream, keyMapper, valueMapper, initialCapacity, 0, false);
    }

    /**
     * 无法确定元素个数时的收集器
     */
    public static  Collector> collector(Function keyMapper, Function valueMapper, boolean dummy) {
        return collector(keyMapper, valueMapper, (t, u) -> u == null ? t : u, dummy ? LinkedHashMap::new : HashMap::new);
    }

    public static  Collector> collector(Function keyMapper, Function valueMapper) {
        return collector(keyMapper, valueMapper, false);
    }

    /**
     * 无法确定元素个数时的流收集
     *
     * @param extra 申请额外空间
     */
    public static  Map collect(Stream stream, Function keyMapper, Function valueMapper, boolean dummy, int extra) {
        int size = Math.max(extra, 0);
        Map map = stream.collect(collector(keyMapper, valueMapper, dummy));
        if (map.isEmpty()) return size == 0 ? Collections.emptyMap() : get(size, 0, dummy).build();
        if (size == 0) return map;
        //原来的初始容量
        int oldCap = reduce(map.size(), 0);
        //申请额外空间后计算需扩容一次达到指定容量的初始容量
        int newCap = reduce(size + map.size(), 1);
        //如果添加额外元素最多导致扩容一次则直接返回
        // 考虑到申请额外空间不一定会真正的去执行,因此这一次的扩容留给具体执行的方法(不一定会扩容)
        if (oldCap >= newCap) return map;
        //下面代码基本不会执行,除非申请额外空间非常大(即需要扩容两次以上)

        //初始容量避免添加额外元素时导致频繁扩容
        newCap = reduce(size + map.size(), 0);
        Map result = dummy ? new LinkedHashMap<>(newCap, 1.0f) : new HashMap<>(newCap, 1.0f);
        result.putAll(map);
        return result;
    }

    public static  Map collect(Stream stream, Function keyMapper, Function valueMapper, boolean dummy) {
        return collect(stream, keyMapper, valueMapper, dummy, 0);
    }

    public static  Map collect(Stream stream, Function keyMapper, Function valueMapper, int extra) {
        return collect(stream, keyMapper, valueMapper, false, extra);
    }

    /**
     * 如果流中具有重复的key又不想抛异常则使用该方法,否则使用对应的Collectors.toMap()即可
     */
    public static  Map collect(Stream stream, Function keyMapper, Function valueMapper) {
        return collect(stream, keyMapper, valueMapper, false, 0);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy