
shz.ToList Maven / Gradle / Ivy
package shz;
import shz.model.TreeNode;
import shz.model.TreeNodeMetadata;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@SuppressWarnings("unchecked")
public final class ToList {
private final List list;
private ToList(int initialCapacity, int idx) {
list = new ArrayList<>(reduce(initialCapacity, idx));
}
private int reduce(int cap, int idx) {
if (idx <= 0 || cap < 3) return cap;
int newCap = cap;
for (int i = idx; i > 0; --i) newCap = (newCap << 1) / 3;
while (calc(newCap, idx) < cap) ++newCap;
return newCap;
}
private int calc(int newCap, int idx) {
while (idx > 0) {
newCap = newCap + (newCap >> 1);
--idx;
}
return newCap;
}
public static ToList get(int initialCapacity, int idx) {
return new ToList<>(initialCapacity, idx);
}
public static ToList get(int initialCapacity) {
return new ToList<>(initialCapacity, 0);
}
public T build() {
return (T) list;
}
public ToList add(Collection extends E> c) {
list.addAll(c);
return this;
}
public final ToList add(EE e) {
list.add(e);
return this;
}
/**
* 大致确定元素个数时的收集器
*
* @param initialCapacity 大致确定的初始容量
* @param idx 初始容量衰减次数
*/
public static Collector> collector(int initialCapacity, int idx) {
return Collector.of(
//提供初始化容量的ArraysList
() -> get(initialCapacity, idx).build(),
List::add,
(left, right) -> {
left.addAll(right);
return left;
}
);
}
public static Collector> collector(int initialCapacity) {
return collector(initialCapacity, 0);
}
/**
* 大致确定元素个数时的流收集
*/
public static List explicitCollect(Stream stream, int initialCapacity, int idx) {
List list = stream.collect(collector(initialCapacity, idx));
return list.isEmpty() ? Collections.emptyList() : list;
}
public static List explicitCollect(Stream stream, int initialCapacity) {
return explicitCollect(stream, initialCapacity, 0);
}
/**
* 无法确定元素个数时的收集器
* 使用ArrayList 由于频繁扩容的原因,将会在此过程使用new 申请额外的数组内存
* 若流中元素不超过73,在此过程中最多申请192个元素容量的数组内存(扩容5次),最终最多申请109个元素容量的数组内存,可以接受
* 若流中元素超过366,在此过程中最少申请1623个元素容量的数组内存(扩容10次),最终最少申请549个元素容量的数组内存,勉强可以接受
*
* 以下情况建议使用此方法,可大幅度减少过程中的内存消耗
* 若流中元素超过823,在此过程中最少申请3680个元素容量的数组内存(扩容12次),最终最少申请1234个元素容量的数组内存,难以接受
* 若流中元素超过9369,在此过程中最少申请42139个元素容量的数组内存(扩容18次),最终最少申请14053个元素容量的数组内存,极难接受
* 若流中元素超过21079,在此过程中最少申请94836个元素容量的数组内存(扩容20次),最终最少申请31618个元素容量的数组内存,不可接受
* 若流中元素超过47427,在此过程中最少申请213403个元素容量的数组内存(扩容22次),最终最少申请71140个元素容量的数组内存,绝无可能
*
* 特别在并发时优势更明显
* 若有10个用户在操作,则在这个过程中最少申请的内存就要*10,最终额外声请的内存消耗也要*10
* 频繁的扩容不仅导致过程中申请大量的数组内存,垃圾回收器并不会立马回收,还会影响性能
*/
public static Collector> collector() {
return Collector.of(
//使用LinkedList替换默认的ArrayList
LinkedList::new,
List::add,
(left, right) -> {
left.addAll(right);
return left;
}
);
}
/**
* 无法确定元素个数时的流收集
*
* @param extra 是否需要添加额外元素
*/
public static List collect(Stream stream, boolean extra) {
List list = stream.collect(collector());
return list.isEmpty()
? extra ? new LinkedList<>() : Collections.emptyList()
: list;
}
public static List collect(Stream stream) {
return collect(stream, false);
}
/**
* 无法确定元素个数时的流收集(需要频繁的进行索引查询时选择此方法收集流)
*
* @param extra 申请额外空间
*/
public static List collectArray(Stream stream, int extra) {
int size = Math.max(extra, 0);
List list = stream.collect(collector());
if (list.isEmpty()) return size == 0 ? Collections.emptyList() : new ArrayList<>(size);
if (size == 0) return new ArrayList<>(list);
//转ArrayList 提供更快的索引查询
List result = new ArrayList<>(size + list.size());
result.addAll(list);
return result;
}
public static List collectArray(Stream stream) {
return collectArray(stream, 0);
}
/**
* 获取分组树
*
* @param list 需要分组的数据
* @param mapper 数据映射器
* @param lastMapper 最后分组数据映射器
* @param lastCollector 最后分组数据收集器
* @param classifiers 分组函数集
*/
public static , R> List groupTree(List extends T> list, BiFunction super K, List, ? extends E> mapper,
BiFunction super K, ? super R, ? extends E> lastMapper,
Collector super T, ?, ? extends R> lastCollector,
Function super T, ? extends K>... classifiers) {
if (Validator.isEmpty(list)) return Collections.emptyList();
Validator.requireNonEmpty(classifiers);
Collector super T, ?, ? extends Map extends K, ?>> collector = Collectors.groupingBy(classifiers[classifiers.length - 1], lastCollector);
for (int i = classifiers.length - 2; i >= 0; --i) collector = Collectors.groupingBy(classifiers[i], collector);
return mergeGroup(list.stream().collect(collector), mapper, lastMapper);
}
private static , R> List mergeGroup(Map extends K, ?> group, BiFunction super K, List, ? extends E> mapper,
BiFunction super K, ? super R, ? extends E> lastMapper) {
return explicitCollect(group.keySet().stream().map(k -> {
Object nextGroup = group.get(k);
return nextGroup instanceof Map
? mapper.apply(k, mergeGroup((Map) nextGroup, mapper, lastMapper))
: lastMapper.apply(k, (R) nextGroup);
}), group.size());
}
/**
* 排序分组树
*/
public static > void sort(List nodes, Comparator comparator) {
if (Validator.isEmpty(nodes)) return;
nodes.sort(comparator);
nodes.forEach(node -> sort(node.getChildes(), comparator));
}
/**
* 合并分组树
*/
public static > List mergeTree(List nodes, List otherNodes, BiFunction merger) {
if (Validator.isEmpty(nodes)) return Validator.isEmpty(otherNodes) ? Collections.emptyList() : otherNodes;
if (Validator.isEmpty(otherNodes)) return nodes;
Map map = ToMap.collect(nodes.stream(), TreeNode::getId, Function.identity());
Map otherMap = ToMap.collect(otherNodes.stream(), TreeNode::getId, Function.identity());
Set ids = new HashSet<>(map.keySet());
Set otherIds = new HashSet<>(otherMap.keySet());
if (!otherIds.removeAll(ids) || !otherIds.isEmpty()) ids.addAll(otherIds);
return explicitCollect(ids.stream().map(k -> {
E e = map.get(k);
E other = otherMap.get(k);
if (e == null) return other;
else if (other == null) return e;
E result = merger.apply(e, other);
result.setChildes(mergeTree(e.getChildes(), other.getChildes(), merger));
return result;
}), ids.size());
}
/**
* 获取分组树(用于分组特殊设计表结构)
*/
public static > List groupTree(List list) {
Map> map = list.stream().collect(Collectors.groupingBy(TreeNodeMetadata::getLevel, collector()));
int level = 1;
List es = map.get(level);
map.remove(level);
while (!map.isEmpty()) {
for (E e : map.get(++level)) {
E root = null;
for (E e1 : es) {
if (e.getRootId().equals(e1.getId())) {
root = e1;
break;
}
}
Objects.requireNonNull(root);
E parent = root;
while (true) {
List child = parent.getChildes();
if (child == null) {
child = new LinkedList<>();
parent.setChildes(child);
child.add(e);
break;
}
if (e.getParentId().equals(parent.getId())) {
child.add(e);
break;
}
boolean flag = true;
for (E e1 : child) {
if (e.getTag().startsWith(parent.getTag())) {
parent = e1;
flag = false;
break;
}
}
Validator.requireNon(flag);
}
}
map.remove(level);
}
return es;
}
}