Commit 45cda665 authored by ma yanling's avatar ma yanling
Browse files

project commit

parent ad2fb30a
Pipeline #2354 failed with stages
in 0 seconds
package cn.hutool.core.collection;
import cn.hutool.core.comparator.PinyinComparator;
import cn.hutool.core.comparator.PropertyComparator;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Matcher;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PageUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.RandomAccess;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
/**
* List相关工具类
*
* @author looly
*/
public class ListUtil {
/**
* 新建一个空List
*
* @param <T> 集合元素类型
* @param isLinked 是否新建LinkedList
* @return List对象
* @since 4.1.2
*/
public static <T> List<T> list(boolean isLinked) {
return isLinked ? new LinkedList<>() : new ArrayList<>();
}
/**
* 新建一个List
*
* @param <T> 集合元素类型
* @param isLinked 是否新建LinkedList
* @param values 数组
* @return List对象
* @since 4.1.2
*/
@SafeVarargs
public static <T> List<T> list(boolean isLinked, T... values) {
if (ArrayUtil.isEmpty(values)) {
return list(isLinked);
}
final List<T> arrayList = isLinked ? new LinkedList<>() : new ArrayList<>(values.length);
Collections.addAll(arrayList, values);
return arrayList;
}
/**
* 新建一个List
*
* @param <T> 集合元素类型
* @param isLinked 是否新建LinkedList
* @param collection 集合
* @return List对象
* @since 4.1.2
*/
public static <T> List<T> list(boolean isLinked, Collection<T> collection) {
if (null == collection) {
return list(isLinked);
}
return isLinked ? new LinkedList<>(collection) : new ArrayList<>(collection);
}
/**
* 新建一个List<br>
* 提供的参数为null时返回空{@link ArrayList}
*
* @param <T> 集合元素类型
* @param isLinked 是否新建LinkedList
* @param iterable {@link Iterable}
* @return List对象
* @since 4.1.2
*/
public static <T> List<T> list(boolean isLinked, Iterable<T> iterable) {
if (null == iterable) {
return list(isLinked);
}
return list(isLinked, iterable.iterator());
}
/**
* 新建一个List<br>
* 提供的参数为null时返回空{@link ArrayList}
*
* @param <T> 集合元素类型
* @param isLinked 是否新建LinkedList
* @param iter {@link Iterator}
* @return ArrayList对象
* @since 4.1.2
*/
public static <T> List<T> list(boolean isLinked, Iterator<T> iter) {
final List<T> list = list(isLinked);
if (null != iter) {
while (iter.hasNext()) {
list.add(iter.next());
}
}
return list;
}
/**
* 新建一个List<br>
* 提供的参数为null时返回空{@link ArrayList}
*
* @param <T> 集合元素类型
* @param isLinked 是否新建LinkedList
* @param enumration {@link Enumeration}
* @return ArrayList对象
* @since 3.0.8
*/
public static <T> List<T> list(boolean isLinked, Enumeration<T> enumration) {
final List<T> list = list(isLinked);
if (null != enumration) {
while (enumration.hasMoreElements()) {
list.add(enumration.nextElement());
}
}
return list;
}
/**
* 新建一个ArrayList
*
* @param <T> 集合元素类型
* @param values 数组
* @return ArrayList对象
*/
@SafeVarargs
public static <T> ArrayList<T> toList(T... values) {
return (ArrayList<T>) list(false, values);
}
/**
* 新建LinkedList
*
* @param values 数组
* @param <T> 类型
* @return LinkedList
* @since 4.1.2
*/
@SafeVarargs
public static <T> LinkedList<T> toLinkedList(T... values) {
return (LinkedList<T>) list(true, values);
}
/**
* 数组转为一个不可变List<br>
* 类似于Java9中的List.of
*
* @param ts 对象
* @param <T> 对象类型
* @return 不可修改List
* @since 5.4.3
*/
@SafeVarargs
public static <T> List<T> of(T... ts) {
if (ArrayUtil.isEmpty(ts)) {
return Collections.emptyList();
}
return Collections.unmodifiableList(toList(ts));
}
/**
* 新建一个CopyOnWriteArrayList
*
* @param <T> 集合元素类型
* @param collection 集合
* @return {@link CopyOnWriteArrayList}
*/
public static <T> CopyOnWriteArrayList<T> toCopyOnWriteArrayList(Collection<T> collection) {
return (null == collection) ? (new CopyOnWriteArrayList<>()) : (new CopyOnWriteArrayList<>(collection));
}
/**
* 新建一个ArrayList
*
* @param <T> 集合元素类型
* @param collection 集合
* @return ArrayList对象
*/
public static <T> ArrayList<T> toList(Collection<T> collection) {
return (ArrayList<T>) list(false, collection);
}
/**
* 新建一个ArrayList<br>
* 提供的参数为null时返回空{@link ArrayList}
*
* @param <T> 集合元素类型
* @param iterable {@link Iterable}
* @return ArrayList对象
* @since 3.1.0
*/
public static <T> ArrayList<T> toList(Iterable<T> iterable) {
return (ArrayList<T>) list(false, iterable);
}
/**
* 新建一个ArrayList<br>
* 提供的参数为null时返回空{@link ArrayList}
*
* @param <T> 集合元素类型
* @param iterator {@link Iterator}
* @return ArrayList对象
* @since 3.0.8
*/
public static <T> ArrayList<T> toList(Iterator<T> iterator) {
return (ArrayList<T>) list(false, iterator);
}
/**
* 新建一个ArrayList<br>
* 提供的参数为null时返回空{@link ArrayList}
*
* @param <T> 集合元素类型
* @param enumeration {@link Enumeration}
* @return ArrayList对象
* @since 3.0.8
*/
public static <T> ArrayList<T> toList(Enumeration<T> enumeration) {
return (ArrayList<T>) list(false, enumeration);
}
/**
* 对指定List分页取值
*
* @param <T> 集合元素类型
* @param pageNo 页码,第一页的页码取决于{@link PageUtil#getFirstPageNo()},默认0
* @param pageSize 每页的条目数
* @param list 列表
* @return 分页后的段落内容
* @since 4.1.20
*/
public static <T> List<T> page(int pageNo, int pageSize, List<T> list) {
if (CollUtil.isEmpty(list)) {
return new ArrayList<>(0);
}
int resultSize = list.size();
// 每页条目数大于总数直接返回所有
if (resultSize <= pageSize) {
if (pageNo < (PageUtil.getFirstPageNo() + 1)) {
return unmodifiable(list);
} else {
// 越界直接返回空
return new ArrayList<>(0);
}
}
// 相乘可能会导致越界 临时用long
if (((long) (pageNo - PageUtil.getFirstPageNo()) * pageSize) > resultSize) {
// 越界直接返回空
return new ArrayList<>(0);
}
final int[] startEnd = PageUtil.transToStartEnd(pageNo, pageSize);
if (startEnd[1] > resultSize) {
startEnd[1] = resultSize;
if (startEnd[0] > startEnd[1]) {
return new ArrayList<>(0);
}
}
return sub(list, startEnd[0], startEnd[1]);
}
/**
* 对指定List进行分页,逐页返回数据
*
* @param <T> 集合元素类型
* @param list 源数据列表
* @param pageSize 每页的条目数
* @param pageListConsumer 单页数据函数式返回
* @since 5.7.10
*/
public static <T> void page(List<T> list, int pageSize, Consumer<List<T>> pageListConsumer) {
if (CollUtil.isEmpty(list) || pageSize <= 0) {
return;
}
final int total = list.size();
final int totalPage = PageUtil.totalPage(total, pageSize);
for (int pageNo = PageUtil.getFirstPageNo(); pageNo < totalPage + PageUtil.getFirstPageNo(); pageNo++) {
// 获取当前页在列表中对应的起止序号
final int[] startEnd = PageUtil.transToStartEnd(pageNo, pageSize);
if (startEnd[1] > total) {
startEnd[1] = total;
}
// 返回数据
pageListConsumer.accept(sub(list, startEnd[0], startEnd[1]));
}
}
/**
* 针对List排序,排序会修改原List
*
* @param <T> 元素类型
* @param list 被排序的List
* @param c {@link Comparator}
* @return 原list
* @see Collections#sort(List, Comparator)
*/
public static <T> List<T> sort(List<T> list, Comparator<? super T> c) {
if (CollUtil.isEmpty(list)) {
return list;
}
list.sort(c);
return list;
}
/**
* 根据Bean的属性排序
*
* @param <T> 元素类型
* @param list List
* @param property 属性名
* @return 排序后的List
* @since 4.0.6
*/
public static <T> List<T> sortByProperty(List<T> list, String property) {
return sort(list, new PropertyComparator<>(property));
}
/**
* 根据汉字的拼音顺序排序
*
* @param list List
* @return 排序后的List
* @since 4.0.8
*/
public static List<String> sortByPinyin(List<String> list) {
return sort(list, new PinyinComparator());
}
/**
* 反序给定List,会在原List基础上直接修改
*
* @param <T> 元素类型
* @param list 被反转的List
* @return 反转后的List
* @since 4.0.6
*/
public static <T> List<T> reverse(List<T> list) {
Collections.reverse(list);
return list;
}
/**
* 反序给定List,会创建一个新的List,原List数据不变
*
* @param <T> 元素类型
* @param list 被反转的List
* @return 反转后的List
* @since 4.0.6
*/
public static <T> List<T> reverseNew(List<T> list) {
List<T> list2 = ObjectUtil.clone(list);
if (null == list2) {
// 不支持clone
list2 = new ArrayList<>(list);
}
try {
return reverse(list2);
} catch (final UnsupportedOperationException e) {
// 提供的列表不可编辑,新建列表
return reverse(list(false, list));
}
}
/**
* 设置或增加元素。当index小于List的长度时,替换指定位置的值,否则在尾部追加
*
* @param <T> 元素类型
* @param list List列表
* @param index 位置
* @param element 新元素
* @return 原List
* @since 4.1.2
*/
public static <T> List<T> setOrAppend(List<T> list, int index, T element) {
Assert.notNull(list, "List must be not null !");
if (index < list.size()) {
list.set(index, element);
} else {
list.add(element);
}
return list;
}
/**
* 在指定位置设置元素。当index小于List的长度时,替换指定位置的值,否则追加{@code null}直到到达index后,设置值
*
* @param <T> 元素类型
* @param list List列表
* @param index 位置
* @param element 新元素
* @return 原List
* @since 5。8.4
*/
public static <T> List<T> setOrPadding(List<T> list, int index, T element) {
return setOrPadding(list, index, element, null);
}
/**
* 在指定位置设置元素。当index小于List的长度时,替换指定位置的值,否则追加{@code paddingElement}直到到达index后,设置值
*
* @param <T> 元素类型
* @param list List列表
* @param index 位置
* @param element 新元素
* @param paddingElement 填充的值
* @return 原List
* @since 5。8.4
*/
public static <T> List<T> setOrPadding(List<T> list, int index, T element, T paddingElement) {
Assert.notNull(list, "List must be not null !");
final int size = list.size();
if (index < size) {
list.set(index, element);
} else {
for (int i = size; i < index; i++) {
list.add(paddingElement);
}
list.add(element);
}
return list;
}
/**
* 截取集合的部分
*
* @param <T> 集合元素类型
* @param list 被截取的数组
* @param start 开始位置(包含)
* @param end 结束位置(不包含)
* @return 截取后的数组,当开始位置超过最大时,返回空的List
*/
public static <T> List<T>
sub(List<T> list, int start, int end) {
return sub(list, start, end, 1);
}
/**
* 截取集合的部分<br>
* 此方法与{@link List#subList(int, int)} 不同在于子列表是新的副本,操作子列表不会影响原列表。
*
* @param <T> 集合元素类型
* @param list 被截取的数组
* @param start 开始位置(包含)
* @param end 结束位置(不包含)
* @param step 步进
* @return 截取后的数组,当开始位置超过最大时,返回空的List
* @since 4.0.6
*/
public static <T> List<T> sub(List<T> list, int start, int end, int step) {
if (list == null) {
return null;
}
if (list.isEmpty()) {
return new ArrayList<>(0);
}
final int size = list.size();
if (start < 0) {
start += size;
}
if (end < 0) {
end += size;
}
if (start == size) {
return new ArrayList<>(0);
}
if (start > end) {
int tmp = start;
start = end;
end = tmp;
}
if (end > size) {
if (start >= size) {
return new ArrayList<>(0);
}
end = size;
}
if (step < 1) {
step = 1;
}
final List<T> result = new ArrayList<>();
for (int i = start; i < end; i += step) {
result.add(list.get(i));
}
return result;
}
/**
* 获取匹配规则定义中匹配到元素的最后位置<br>
* 此方法对于某些无序集合的位置信息,以转换为数组后的位置为准。
*
* @param <T> 元素类型
* @param list List集合
* @param matcher 匹配器,为空则全部匹配
* @return 最后一个位置
* @since 5.6.6
*/
public static <T> int lastIndexOf(List<T> list, Matcher<T> matcher) {
if (null != list) {
final int size = list.size();
if (size > 0) {
for (int i = size - 1; i >= 0; i--) {
if (null == matcher || matcher.match(list.get(i))) {
return i;
}
}
}
}
return -1;
}
/**
* 获取匹配规则定义中匹配到元素的所有位置
*
* @param <T> 元素类型
* @param list 列表
* @param matcher 匹配器,为空则全部匹配
* @return 位置数组
* @since 5.2.5
*/
public static <T> int[] indexOfAll(List<T> list, Matcher<T> matcher) {
return CollUtil.indexOfAll(list, matcher);
}
/**
* 将对应List转换为不可修改的List
*
* @param list List
* @param <T> 元素类型
* @return 不可修改List
* @since 5.2.6
*/
public static <T> List<T> unmodifiable(List<T> list) {
if (null == list) {
return null;
}
return Collections.unmodifiableList(list);
}
/**
* 获取一个空List,这个空List不可变
*
* @param <T> 元素类型
* @return 空的List
* @see Collections#emptyList()
* @since 5.2.6
*/
public static <T> List<T> empty() {
return Collections.emptyList();
}
/**
* 通过传入分区长度,将指定列表分区为不同的块,每块区域的长度相同(最后一块可能小于长度)<br>
* 分区是在原List的基础上进行的,返回的分区是不可变的抽象列表,原列表元素变更,分区中元素也会变更。
*
* <p>
* 需要特别注意的是,此方法调用{@link List#subList(int, int)}切分List,
* 此方法返回的是原List的视图,也就是说原List有变更,切分后的结果也会变更。
* </p>
*
* @param <T> 集合元素类型
* @param list 列表,为空时返回{@link #empty()}
* @param size 每个段的长度,当长度超过list长度时,size按照list长度计算,即只返回一个节点
* @return 分段列表
* @since 5.4.5
*/
public static <T> List<List<T>> partition(List<T> list, int size) {
if (CollUtil.isEmpty(list)) {
return empty();
}
return (list instanceof RandomAccess)
? new RandomAccessPartition<>(list, size)
: new Partition<>(list, size);
}
/**
* 对集合按照指定长度分段,每一个段为单独的集合,返回这个集合的列表
*
* <p>
* 需要特别注意的是,此方法调用{@link List#subList(int, int)}切分List,
* 此方法返回的是原List的视图,也就是说原List有变更,切分后的结果也会变更。
* </p>
*
* @param <T> 集合元素类型
* @param list 列表,为空时返回{@link #empty()}
* @param size 每个段的长度,当长度超过list长度时,size按照list长度计算,即只返回一个节点
* @return 分段列表
* @see #partition(List, int)
* @since 5.4.5
*/
public static <T> List<List<T>> split(List<T> list, int size) {
return partition(list, size);
}
/**
* 将集合平均分成多个list,返回这个集合的列表
* <p>例:</p>
* <pre>
* ListUtil.splitAvg(null, 3); // []
* ListUtil.splitAvg(Arrays.asList(1, 2, 3, 4), 2); // [[1, 2], [3, 4]]
* ListUtil.splitAvg(Arrays.asList(1, 2, 3), 5); // [[1], [2], [3], [], []]
* ListUtil.splitAvg(Arrays.asList(1, 2, 3), 2); // [[1, 2], [3]]
* </pre>
*
* @param <T> 集合元素类型
* @param list 集合
* @param limit 要均分成几个list
* @return 分段列表
* @author lileming
* @since 5.7.10
*/
public static <T> List<List<T>> splitAvg(List<T> list, int limit) {
if (CollUtil.isEmpty(list)) {
return empty();
}
return (list instanceof RandomAccess)
? new RandomAccessAvgPartition<>(list, limit)
: new AvgPartition<>(list, limit);
}
/**
* 将指定元素交换到指定索引位置,其他元素的索引值不变<br>
* 交换会修改原List<br>
* 如果集合中有多个相同元素,只交换第一个找到的元素
*
* @param <T> 元素类型
* @param list 列表
* @param element 需交换元素
* @param targetIndex 目标索引
* @since 5.7.13
*/
public static <T> void swapTo(List<T> list, T element, Integer targetIndex) {
if (CollUtil.isNotEmpty(list)) {
final int index = list.indexOf(element);
if (index >= 0) {
Collections.swap(list, index, targetIndex);
}
}
}
/**
* 将指定元素交换到指定元素位置,其他元素的索引值不变<br>
* 交换会修改原List<br>
* 如果集合中有多个相同元素,只交换第一个找到的元素
*
* @param <T> 元素类型
* @param list 列表
* @param element 需交换元素
* @param targetElement 目标元素
*/
public static <T> void swapElement(List<T> list, T element, T targetElement) {
if (CollUtil.isNotEmpty(list)) {
final int targetIndex = list.indexOf(targetElement);
if (targetIndex >= 0) {
swapTo(list, element, targetIndex);
}
}
}
}
package cn.hutool.core.collection;
import cn.hutool.core.lang.Assert;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* 包装 {@link NodeList} 的{@link Iterator}
* <p>
* 此 iterator 不支持 {@link #remove()} 方法。
*
* @author apache commons,looly
* @see NodeList
* @since 5.8.0
*/
public class NodeListIter implements ResettableIter<Node> {
private final NodeList nodeList;
/**
* 当前位置索引
*/
private int index = 0;
/**
* 构造, 根据给定{@link NodeList} 创建{@code NodeListIterator}
*
* @param nodeList {@link NodeList},非空
*/
public NodeListIter(final NodeList nodeList) {
this.nodeList = Assert.notNull(nodeList, "NodeList must not be null.");
}
@Override
public boolean hasNext() {
return nodeList != null && index < nodeList.getLength();
}
@Override
public Node next() {
if (nodeList != null && index < nodeList.getLength()) {
return nodeList.item(index++);
}
throw new NoSuchElementException("underlying nodeList has no more elements");
}
/**
* Throws {@link UnsupportedOperationException}.
*
* @throws UnsupportedOperationException always
*/
@Override
public void remove() {
throw new UnsupportedOperationException("remove() method not supported for a NodeListIterator.");
}
@Override
public void reset() {
this.index = 0;
}
}
package cn.hutool.core.collection;
import cn.hutool.core.lang.Assert;
import java.util.AbstractList;
import java.util.List;
/**
* 列表分区或分段<br>
* 通过传入分区长度,将指定列表分区为不同的块,每块区域的长度相同(最后一块可能小于长度)<br>
* 分区是在原List的基础上进行的,返回的分区是不可变的抽象列表,原列表元素变更,分区中元素也会变更。
* 参考:Guava的Lists#Partition
*
* @param <T> 元素类型
* @author looly, guava
* @since 5.7.10
*/
public class Partition<T> extends AbstractList<List<T>> {
protected final List<T> list;
protected final int size;
/**
* 列表分区
*
* @param list 被分区的列表,非空
* @param size 每个分区的长度,必须&gt;0
*/
public Partition(List<T> list, int size) {
this.list = Assert.notNull(list);
this.size = Math.min(list.size(), size);
}
@Override
public List<T> get(int index) {
final int start = index * size;
final int end = Math.min(start + size, list.size());
return list.subList(start, end);
}
@Override
public int size() {
// 此处采用动态计算,以应对list变
final int size = this.size;
if(0 == size){
return 0;
}
final int total = list.size();
// 类似于判断余数,当总数非整份size时,多余的数>=1,则相当于被除数多一个size,做到+1目的
// 类似于:if(total % size > 0){length += 1;}
return (total + size - 1) / size;
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
}
package cn.hutool.core.collection;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* 分批迭代工具,可以分批处理数据
* <ol>
* <li>比如调用其他客户的接口,传入的入参有限,需要分批</li>
* <li>比如mysql/oracle用in语句查询,超过1000可以分批</li>
* <li>比如数据库取出游标,可以把游标里的数据一批一批处理</li>
* </ol>
*
* @param <T> 字段类型
* @author qiqi.chen
* @since 5.7.10
*/
public class PartitionIter<T> implements IterableIter<List<T>>, Serializable {
private static final long serialVersionUID = 1L;
/**
* 被分批的迭代器
*/
protected final Iterator<T> iterator;
/**
* 实际每批大小
*/
protected final int partitionSize;
/**
* 创建分组对象
*
* @param iterator 迭代器
* @param partitionSize 每批大小,最后一批不满一批算一批
*/
public PartitionIter(Iterator<T> iterator, int partitionSize) {
this.iterator = iterator;
this.partitionSize = partitionSize;
}
@Override
public boolean hasNext() {
return this.iterator.hasNext();
}
@Override
public List<T> next() {
final List<T> list = new ArrayList<>(this.partitionSize);
for (int i = 0; i < this.partitionSize; i++) {
if (false == iterator.hasNext()) {
break;
}
list.add(iterator.next());
}
return list;
}
}
package cn.hutool.core.collection;
import java.util.List;
import java.util.RandomAccess;
/**
* 列表分区或分段(可随机访问列表)<br>
* 通过传入分区个数,将指定列表分区为不同的块,每块区域的长度均匀分布(个数差不超过1)<br>
* <pre>
* [1,2,3,4] -》 [1,2], [3, 4]
* [1,2,3,4] -》 [1,2], [3], [4]
* [1,2,3,4] -》 [1], [2], [3], [4]
* [1,2,3,4] -》 [1], [2], [3], [4], []
* </pre>
* 分区是在原List的基础上进行的,返回的分区是不可变的抽象列表,原列表元素变更,分区中元素也会变更。
*
* @param <T> 元素类型
* @author looly
* @since 5.7.10
*/
public class RandomAccessAvgPartition<T> extends AvgPartition<T> implements RandomAccess {
/**
* 列表分区
*
* @param list 被分区的列表
* @param limit 分区个数
*/
public RandomAccessAvgPartition(List<T> list, int limit) {
super(list, limit);
}
}
package cn.hutool.core.collection;
import java.util.List;
import java.util.RandomAccess;
/**
* 列表分区或分段(可随机访问列表)<br>
* 通过传入分区长度,将指定列表分区为不同的块,每块区域的长度相同(最后一块可能小于长度)<br>
* 分区是在原List的基础上进行的,返回的分区是不可变的抽象列表,原列表元素变更,分区中元素也会变更。
* 参考:Guava的Lists#RandomAccessPartition
*
* @param <T> 元素类型
* @author looly, guava
* @since 5.7.10
*/
public class RandomAccessPartition<T> extends Partition<T> implements RandomAccess {
/**
* 构造
*
* @param list 被分区的列表,必须实现{@link RandomAccess}
* @param size 每个分区的长度
*/
public RandomAccessPartition(List<T> list, int size) {
super(list, size);
}
}
package cn.hutool.core.collection;
import java.util.Iterator;
/**
* 支持重置的{@link Iterator} 接口<br>
* 通过实现{@link #reset()},重置此{@link Iterator}后可实现复用重新遍历
*
* @param <E> 元素类型
* @since 5.8.0
*/
public interface ResettableIter<E> extends Iterator<E> {
/**
* 重置,重置后可重新遍历
*/
void reset();
}
package cn.hutool.core.collection;
import cn.hutool.core.lang.Assert;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* 集合索引环形获取工具类
*
* @author ZhouChuGang
* @since 5.7.15
*/
public class RingIndexUtil {
/**
* 通过cas操作 实现对指定值内的回环累加
*
* @param object 集合
* <ul>
* <li>Collection - the collection size
* <li>Map - the map size
* <li>Array - the array size
* <li>Iterator - the number of elements remaining in the iterator
* <li>Enumeration - the number of elements remaining in the enumeration
* </ul>
* @param atomicInteger 原子操作类
* @return 索引位置
*/
public static int ringNextIntByObj(Object object, AtomicInteger atomicInteger) {
Assert.notNull(object);
int modulo = CollUtil.size(object);
return ringNextInt(modulo, atomicInteger);
}
/**
* 通过cas操作 实现对指定值内的回环累加
*
* @param modulo 回环周期值
* @param atomicInteger 原子操作类
* @return 索引位置
*/
public static int ringNextInt(int modulo, AtomicInteger atomicInteger) {
Assert.notNull(atomicInteger);
Assert.isTrue(modulo > 0);
if (modulo <= 1) {
return 0;
}
for (; ; ) {
int current = atomicInteger.get();
int next = (current + 1) % modulo;
if (atomicInteger.compareAndSet(current, next)) {
return next;
}
}
}
/**
* 通过cas操作 实现对指定值内的回环累加<br>
* 此方法一般用于大量数据完成回环累加(如数据库中的值大于int最大值)
*
* @param modulo 回环周期值
* @param atomicLong 原子操作类
* @return 索引位置
*/
public static long ringNextLong(long modulo, AtomicLong atomicLong) {
Assert.notNull(atomicLong);
Assert.isTrue(modulo > 0);
if (modulo <= 1) {
return 0;
}
for (; ; ) {
long current = atomicLong.get();
long next = (current + 1) % modulo;
if (atomicLong.compareAndSet(current, next)) {
return next;
}
}
}
}
package cn.hutool.core.collection;
import java.util.Spliterator;
import java.util.function.Function;
/**
* {@link Spliterator}相关工具类
*
* @author looly
* @since 5.4.3
*/
public class SpliteratorUtil {
/**
* 使用给定的转换函数,转换源{@link Spliterator}为新类型的{@link Spliterator}
*
* @param <F> 源元素类型
* @param <T> 目标元素类型
* @param fromSpliterator 源{@link Spliterator}
* @param function 转换函数
* @return 新类型的{@link Spliterator}
*/
public static <F, T> Spliterator<T> trans(Spliterator<F> fromSpliterator, Function<? super F, ? extends T> function) {
return new TransSpliterator<>(fromSpliterator, function);
}
}
package cn.hutool.core.collection;
import cn.hutool.core.lang.Assert;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* 使用给定的转换函数,转换源集合为新类型的集合
*
* @param <F> 源元素类型
* @param <T> 目标元素类型
* @author looly
* @since 5.4.3
*/
public class TransCollection<F, T> extends AbstractCollection<T> {
private final Collection<F> fromCollection;
private final Function<? super F, ? extends T> function;
/**
* 构造
*
* @param fromCollection 源集合
* @param function 转换函数
*/
public TransCollection(Collection<F> fromCollection, Function<? super F, ? extends T> function) {
this.fromCollection = Assert.notNull(fromCollection);
this.function = Assert.notNull(function);
}
@Override
public Iterator<T> iterator() {
return IterUtil.trans(fromCollection.iterator(), function);
}
@Override
public void clear() {
fromCollection.clear();
}
@Override
public boolean isEmpty() {
return fromCollection.isEmpty();
}
@Override
public void forEach(Consumer<? super T> action) {
Assert.notNull(action);
fromCollection.forEach((f) -> action.accept(function.apply(f)));
}
@Override
public boolean removeIf(Predicate<? super T> filter) {
Assert.notNull(filter);
return fromCollection.removeIf(element -> filter.test(function.apply(element)));
}
@Override
public Spliterator<T> spliterator() {
return SpliteratorUtil.trans(fromCollection.spliterator(), function);
}
@Override
public int size() {
return fromCollection.size();
}
}
\ No newline at end of file
package cn.hutool.core.collection;
import cn.hutool.core.lang.Assert;
import java.util.Iterator;
import java.util.function.Function;
/**
* 使用给定的转换函数,转换源{@link Iterator}为新类型的{@link Iterator}
*
* @param <F> 源元素类型
* @param <T> 目标元素类型
* @author looly
* @since 5.4.3
*/
public class TransIter<F, T> implements Iterator<T> {
private final Iterator<? extends F> backingIterator;
private final Function<? super F, ? extends T> func;
/**
* 构造
*
* @param backingIterator 源{@link Iterator}
* @param func 转换函数
*/
public TransIter(final Iterator<? extends F> backingIterator, final Function<? super F, ? extends T> func) {
this.backingIterator = Assert.notNull(backingIterator);
this.func = Assert.notNull(func);
}
@Override
public final boolean hasNext() {
return backingIterator.hasNext();
}
@Override
public final T next() {
return func.apply(backingIterator.next());
}
@Override
public final void remove() {
backingIterator.remove();
}
}
package cn.hutool.core.collection;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* 使用给定的转换函数,转换源{@link Spliterator}为新类型的{@link Spliterator}
*
* @param <F> 源元素类型
* @param <T> 目标元素类型
* @author looly
* @since 5.4.3
*/
public class TransSpliterator<F, T> implements Spliterator<T> {
private final Spliterator<F> fromSpliterator;
private final Function<? super F, ? extends T> function;
public TransSpliterator(Spliterator<F> fromSpliterator, Function<? super F, ? extends T> function) {
this.fromSpliterator = fromSpliterator;
this.function = function;
}
@Override
public boolean tryAdvance(Consumer<? super T> action) {
return fromSpliterator.tryAdvance(
fromElement -> action.accept(function.apply(fromElement)));
}
@Override
public void forEachRemaining(Consumer<? super T> action) {
fromSpliterator.forEachRemaining(fromElement -> action.accept(function.apply(fromElement)));
}
@Override
public Spliterator<T> trySplit() {
Spliterator<F> fromSplit = fromSpliterator.trySplit();
return (fromSplit != null) ? new TransSpliterator<>(fromSplit, function) : null;
}
@Override
public long estimateSize() {
return fromSpliterator.estimateSize();
}
@Override
public int characteristics() {
return fromSpliterator.characteristics()
& ~(Spliterator.DISTINCT | Spliterator.NONNULL | Spliterator.SORTED);
}
}
package cn.hutool.core.collection;
import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.util.ObjectUtil;
import java.io.Serializable;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Function;
/**
* 唯一键的Set<br>
* 通过自定义唯一键,通过{@link #uniqueGenerator}生成节点对象对应的键作为Map的key,确定唯一<br>
* 此Set与HashSet不同的是,HashSet依赖于{@link Object#equals(Object)}确定唯一<br>
* 但是很多时候我们无法对对象进行修改,此时在外部定义一个唯一规则,即可完成去重。
* <pre>
* {@code Set<UniqueTestBean> set = new UniqueKeySet<>(UniqueTestBean::getId);}
* </pre>
*
* @param <K> 唯一键类型
* @param <V> 值对象
* @author looly
* @since 5.7.23
*/
public class UniqueKeySet<K, V> extends AbstractSet<V> implements Serializable {
private static final long serialVersionUID = 1L;
private Map<K, V> map;
private final Function<V, K> uniqueGenerator;
//region 构造
/**
* 构造
*
* @param uniqueGenerator 唯一键生成规则函数,用于生成对象对应的唯一键
*/
public UniqueKeySet(Function<V, K> uniqueGenerator) {
this(false, uniqueGenerator);
}
/**
* 构造
*
* @param uniqueGenerator 唯一键生成规则函数,用于生成对象对应的唯一键
* @param c 初始化加入的集合
* @since 5.8.0
*/
public UniqueKeySet(Function<V, K> uniqueGenerator, Collection<? extends V> c) {
this(false, uniqueGenerator, c);
}
/**
* 构造
*
* @param isLinked 是否保持加入顺序
* @param uniqueGenerator 唯一键生成规则函数,用于生成对象对应的唯一键
*/
public UniqueKeySet(boolean isLinked, Function<V, K> uniqueGenerator) {
this(MapBuilder.create(isLinked), uniqueGenerator);
}
/**
* 构造
*
* @param isLinked 是否保持加入顺序
* @param uniqueGenerator 唯一键生成规则函数,用于生成对象对应的唯一键
* @param c 初始化加入的集合
* @since 5.8.0
*/
public UniqueKeySet(boolean isLinked, Function<V, K> uniqueGenerator, Collection<? extends V> c) {
this(isLinked, uniqueGenerator);
addAll(c);
}
/**
* 构造
*
* @param initialCapacity 初始容量
* @param loadFactor 增长因子
* @param uniqueGenerator 唯一键生成规则函数,用于生成对象对应的唯一键
*/
public UniqueKeySet(int initialCapacity, float loadFactor, Function<V, K> uniqueGenerator) {
this(MapBuilder.create(new HashMap<>(initialCapacity, loadFactor)), uniqueGenerator);
}
/**
* 构造
*
* @param builder 初始Map,定义了Map类型
* @param uniqueGenerator 唯一键生成规则函数,用于生成对象对应的唯一键
*/
public UniqueKeySet(MapBuilder<K, V> builder, Function<V, K> uniqueGenerator) {
this.map = builder.build();
this.uniqueGenerator = uniqueGenerator;
}
//endregion
@Override
public Iterator<V> iterator() {
return map.values().iterator();
}
@Override
public int size() {
return map.size();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public boolean contains(Object o) {
//noinspection unchecked
return map.containsKey(this.uniqueGenerator.apply((V) o));
}
@Override
public boolean add(V v) {
return null == map.put(this.uniqueGenerator.apply(v), v);
}
/**
* 加入值,如果值已经存在,则忽略之
*
* @param v 值
* @return 是否成功加入
*/
public boolean addIfAbsent(V v) {
return null == map.putIfAbsent(this.uniqueGenerator.apply(v), v);
}
/**
* 加入集合中所有的值,如果值已经存在,则忽略之
*
* @param c 集合
* @return 是否有一个或多个被加入成功
*/
public boolean addAllIfAbsent(Collection<? extends V> c) {
boolean modified = false;
for (V v : c)
if (addIfAbsent(v)) {
modified = true;
}
return modified;
}
@Override
public boolean remove(Object o) {
//noinspection unchecked
return null != map.remove(this.uniqueGenerator.apply((V) o));
}
@Override
public void clear() {
map.clear();
}
@Override
@SuppressWarnings("unchecked")
public UniqueKeySet<K, V> clone() {
try {
UniqueKeySet<K, V> newSet = (UniqueKeySet<K, V>) super.clone();
newSet.map = ObjectUtil.clone(this.map);
return newSet;
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
}
/**
* 集合以及Iterator封装,包括集合工具CollUtil,Iterator和Iterable工具IterUtil
*
* @author looly
*
*/
package cn.hutool.core.collection;
\ No newline at end of file
package cn.hutool.core.comparator;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Comparator;
/**
* Bean字段排序器<br>
* 参阅feilong-core中的PropertyComparator
*
* @param <T> 被比较的Bean
* @author jiangzeyin
* @deprecated 此类不再需要,使用FuncComparator代替更加灵活
*/
@Deprecated
public abstract class BaseFieldComparator<T> implements Comparator<T>, Serializable {
private static final long serialVersionUID = -3482464782340308755L;
/**
* 比较两个对象的同一个字段值
*
* @param o1 对象1
* @param o2 对象2
* @param field 字段
* @return 比较结果
*/
protected int compareItem(T o1, T o2, Field field) {
if (o1 == o2) {
return 0;
} else if (null == o1) {// null 排在后面
return 1;
} else if (null == o2) {
return -1;
}
Comparable<?> v1;
Comparable<?> v2;
try {
v1 = (Comparable<?>) ReflectUtil.getFieldValue(o1, field);
v2 = (Comparable<?>) ReflectUtil.getFieldValue(o2, field);
} catch (Exception e) {
throw new ComparatorException(e);
}
return compare(o1, o2, v1, v2);
}
@SuppressWarnings({"rawtypes", "unchecked"})
private int compare(T o1, T o2, Comparable fieldValue1, Comparable fieldValue2) {
int result = ObjectUtil.compare(fieldValue1, fieldValue2);
if (0 == result) {
//避免TreeSet / TreeMap 过滤掉排序字段相同但是对象不相同的情况
result = CompareUtil.compare(o1, o2, true);
}
return result;
}
}
package cn.hutool.core.comparator;
import java.io.Serializable;
import java.util.Comparator;
/**
* 针对 {@link Comparable}对象的默认比较器
*
* @param <E> 比较对象类型
* @author Looly
* @since 3.0.7
*/
public class ComparableComparator<E extends Comparable<? super E>> implements Comparator<E>, Serializable {
private static final long serialVersionUID = 3020871676147289162L;
/** 单例 */
@SuppressWarnings("rawtypes")
public static final ComparableComparator INSTANCE = new ComparableComparator<>();
/**
* 构造
*/
public ComparableComparator() {
}
/**
* 比较两个{@link Comparable}对象
*
* <pre>
* obj1.compareTo(obj2)
* </pre>
*
* @param obj1 被比较的第一个对象
* @param obj2 the second object to compare
* @return obj1小返回负数,大返回正数,否则返回0
* @throws NullPointerException obj1为{@code null}或者比较中抛出空指针异常
*/
@Override
public int compare(final E obj1, final E obj2) {
return obj1.compareTo(obj2);
}
@Override
public int hashCode() {
return "ComparableComparator".hashCode();
}
@Override
public boolean equals(final Object object) {
return this == object || null != object && object.getClass().equals(this.getClass());
}
}
\ No newline at end of file
package cn.hutool.core.comparator;
import cn.hutool.core.lang.Chain;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
/**
* 比较器链。此链包装了多个比较器,最终比较结果按照比较器顺序综合多个比较器结果。<br>
* 按照比较器链的顺序分别比较,如果比较出相等则转向下一个比较器,否则直接返回<br>
* 此类copy from Apache-commons-collections
*
* @author looly
* @since 3.0.7
*/
public class ComparatorChain<E> implements Chain<Comparator<E>, ComparatorChain<E>>, Comparator<E>, Serializable {
private static final long serialVersionUID = -2426725788913962429L;
/**
* 比较器链.
*/
private final List<Comparator<E>> chain;
/**
* 对应比较器位置是否反序.
*/
private final BitSet orderingBits;
/**
* 比较器是否被锁定。锁定的比较器链不能再添加新的比较器。比较器会在开始比较时开始加锁。
*/
private boolean lock = false;
//------------------------------------------------------------------------------------- Static method start
/**
* 构建 {@link ComparatorChain}
*
* @param <E> 被比较对象类型
* @param comparator 比较器
* @return {@link ComparatorChain}
* @since 5.4.3
*/
public static <E> ComparatorChain<E> of(Comparator<E> comparator) {
return of(comparator, false);
}
/**
* 构建 {@link ComparatorChain}
*
* @param <E> 被比较对象类型
* @param comparator 比较器
* @param reverse 是否反向
* @return {@link ComparatorChain}
* @since 5.4.3
*/
public static <E> ComparatorChain<E> of(Comparator<E> comparator, boolean reverse) {
return new ComparatorChain<>(comparator, reverse);
}
/**
* 构建 {@link ComparatorChain}
*
* @param <E> 被比较对象类型
* @param comparators 比较器数组
* @return {@link ComparatorChain}
* @since 5.4.3
*/
@SafeVarargs
public static <E> ComparatorChain<E> of(Comparator<E>... comparators) {
return of(Arrays.asList(comparators));
}
/**
* 构建 {@link ComparatorChain}
*
* @param <E> 被比较对象类型
* @param comparators 比较器列表
* @return {@link ComparatorChain}
* @since 5.4.3
*/
public static <E> ComparatorChain<E> of(List<Comparator<E>> comparators) {
return new ComparatorChain<>(comparators);
}
/**
* 构建 {@link ComparatorChain}
*
* @param <E> 被比较对象类型
* @param comparators 比较器列表
* @param bits {@link Comparator} 列表对应的排序boolean值,true表示正序,false反序
* @return {@link ComparatorChain}
* @since 5.4.3
*/
public static <E> ComparatorChain<E> of(List<Comparator<E>> comparators, BitSet bits) {
return new ComparatorChain<>(comparators, bits);
}
//------------------------------------------------------------------------------------- Static method start
/**
* 构造空的比较器链,必须至少有一个比较器,否则会在compare时抛出{@link UnsupportedOperationException}
*/
public ComparatorChain() {
this(new ArrayList<>(), new BitSet());
}
/**
* 构造,初始化单一比较器。比较器为正序
*
* @param comparator 在比较器链中的第一个比较器
*/
public ComparatorChain(final Comparator<E> comparator) {
this(comparator, false);
}
/**
* 构造,初始化单一比较器。自定义正序还是反序
*
* @param comparator 在比较器链中的第一个比较器
* @param reverse 是否反序,true表示反序,false正序
*/
public ComparatorChain(final Comparator<E> comparator, final boolean reverse) {
chain = new ArrayList<>(1);
chain.add(comparator);
orderingBits = new BitSet(1);
if (reverse == true) {
orderingBits.set(0);
}
}
/**
* 构造,使用已有的比较器列表
*
* @param list 比较器列表
* @see #ComparatorChain(List, BitSet)
*/
public ComparatorChain(final List<Comparator<E>> list) {
this(list, new BitSet(list.size()));
}
/**
* 构造,使用已有的比较器列表和对应的BitSet<br>
* BitSet中的boolean值需与list中的{@link Comparator}一一对应,true表示正序,false反序
*
* @param list {@link Comparator} 列表
* @param bits {@link Comparator} 列表对应的排序boolean值,true表示正序,false反序
*/
public ComparatorChain(final List<Comparator<E>> list, final BitSet bits) {
chain = list;
orderingBits = bits;
}
/**
* 在链的尾部添加比较器,使用正向排序
*
* @param comparator {@link Comparator} 比较器,正向
* @return this
*/
public ComparatorChain<E> addComparator(final Comparator<E> comparator) {
return addComparator(comparator, false);
}
/**
* 在链的尾部添加比较器,使用给定排序方式
*
* @param comparator {@link Comparator} 比较器
* @param reverse 是否反序,true表示正序,false反序
* @return this
*/
public ComparatorChain<E> addComparator(final Comparator<E> comparator, final boolean reverse) {
checkLocked();
chain.add(comparator);
if (reverse == true) {
orderingBits.set(chain.size() - 1);
}
return this;
}
/**
* 替换指定位置的比较器,保持原排序方式
*
* @param index 位置
* @param comparator {@link Comparator}
* @return this
* @throws IndexOutOfBoundsException if index &lt; 0 or index &gt;= size()
*/
public ComparatorChain<E> setComparator(final int index, final Comparator<E> comparator) throws IndexOutOfBoundsException {
return setComparator(index, comparator, false);
}
/**
* 替换指定位置的比较器,替换指定排序方式
*
* @param index 位置
* @param comparator {@link Comparator}
* @param reverse 是否反序,true表示正序,false反序
* @return this
*/
public ComparatorChain<E> setComparator(final int index, final Comparator<E> comparator, final boolean reverse) {
checkLocked();
chain.set(index, comparator);
if (reverse == true) {
orderingBits.set(index);
} else {
orderingBits.clear(index);
}
return this;
}
/**
* 更改指定位置的排序方式为正序
*
* @param index 位置
* @return this
*/
public ComparatorChain<E> setForwardSort(final int index) {
checkLocked();
orderingBits.clear(index);
return this;
}
/**
* 更改指定位置的排序方式为反序
*
* @param index 位置
* @return this
*/
public ComparatorChain<E> setReverseSort(final int index) {
checkLocked();
orderingBits.set(index);
return this;
}
/**
* 比较器链中比较器个数
*
* @return Comparator count
*/
public int size() {
return chain.size();
}
/**
* 是否已经被锁定。当开始比较时(调用compare方法)此值为true
*
* @return true = ComparatorChain cannot be modified; false = ComparatorChain can still be modified.
*/
public boolean isLocked() {
return lock;
}
@Override
public Iterator<Comparator<E>> iterator() {
return this.chain.iterator();
}
@Override
public ComparatorChain<E> addChain(Comparator<E> element) {
return this.addComparator(element);
}
/**
* 执行比较<br>
* 按照比较器链的顺序分别比较,如果比较出相等则转向下一个比较器,否则直接返回
*
* @param o1 第一个对象
* @param o2 第二个对象
* @return -1, 0, or 1
* @throws UnsupportedOperationException 如果比较器链为空,无法完成比较
*/
@Override
public int compare(final E o1, final E o2) throws UnsupportedOperationException {
if (lock == false) {
checkChainIntegrity();
lock = true;
}
final Iterator<Comparator<E>> comparators = chain.iterator();
Comparator<? super E> comparator;
int retval;
for (int comparatorIndex = 0; comparators.hasNext(); ++comparatorIndex) {
comparator = comparators.next();
retval = comparator.compare(o1, o2);
if (retval != 0) {
// invert the order if it is a reverse sort
if (true == orderingBits.get(comparatorIndex)) {
retval = (retval > 0) ? -1 : 1;
}
return retval;
}
}
// if comparators are exhausted, return 0
return 0;
}
@Override
public int hashCode() {
int hash = 0;
if (null != chain) {
hash ^= chain.hashCode();
}
if (null != orderingBits) {
hash ^= orderingBits.hashCode();
}
return hash;
}
@Override
public boolean equals(final Object object) {
if (this == object) {
return true;
}
if (null == object) {
return false;
}
if (object.getClass().equals(this.getClass())) {
final ComparatorChain<?> otherChain = (ComparatorChain<?>) object;
//
return Objects.equals(this.orderingBits, otherChain.orderingBits)
&& this.chain.equals(otherChain.chain);
}
return false;
}
//------------------------------------------------------------------------------------------------------------------------------- Private method start
/**
* 被锁定时抛出异常
*
* @throws UnsupportedOperationException 被锁定抛出此异常
*/
private void checkLocked() {
if (lock == true) {
throw new UnsupportedOperationException("Comparator ordering cannot be changed after the first comparison is performed");
}
}
/**
* 检查比较器链是否为空,为空抛出异常
*
* @throws UnsupportedOperationException 为空抛出此异常
*/
private void checkChainIntegrity() {
if (chain.size() == 0) {
throw new UnsupportedOperationException("ComparatorChains must contain at least one Comparator");
}
}
//------------------------------------------------------------------------------------------------------------------------------- Private method start
}
package cn.hutool.core.comparator;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
/**
* 比较异常
* @author xiaoleilu
*/
public class ComparatorException extends RuntimeException{
private static final long serialVersionUID = 4475602435485521971L;
public ComparatorException(Throwable e) {
super(ExceptionUtil.getMessage(e), e);
}
public ComparatorException(String message) {
super(message);
}
public ComparatorException(String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params));
}
public ComparatorException(String message, Throwable throwable) {
super(message, throwable);
}
public ComparatorException(Throwable throwable, String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params), throwable);
}
}
package cn.hutool.core.comparator;
import java.util.Comparator;
import java.util.Objects;
import java.util.function.Function;
/**
* 比较工具类
*
* @author looly
*/
public class CompareUtil {
/**
* 获取自然排序器,即默认排序器
*
* @param <E> 排序节点类型
* @return 默认排序器
* @since 5.7.21
*/
@SuppressWarnings("unchecked")
public static <E extends Comparable<? super E>> Comparator<E> naturalComparator() {
return ComparableComparator.INSTANCE;
}
/**
* 对象比较,比较结果取决于comparator,如果被比较对象为null,传入的comparator对象应处理此情况<br>
* 如果传入comparator为null,则使用默认规则比较(此时被比较对象必须实现Comparable接口)
*
* <p>
* 一般而言,如果c1 &lt; c2,返回数小于0,c1==c2返回0,c1 &gt; c2 大于0
*
* @param <T> 被比较对象类型
* @param c1 对象1
* @param c2 对象2
* @param comparator 比较器
* @return 比较结果
* @see java.util.Comparator#compare(Object, Object)
* @since 4.6.9
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static <T> int compare(T c1, T c2, Comparator<T> comparator) {
if (null == comparator) {
return compare((Comparable) c1, (Comparable) c2);
}
return comparator.compare(c1, c2);
}
/**
* {@code null}安全的对象比较,{@code null}对象小于任何对象
*
* @param <T> 被比较对象类型
* @param c1 对象1,可以为{@code null}
* @param c2 对象2,可以为{@code null}
* @return 比较结果,如果c1 &lt; c2,返回数小于0,c1==c2返回0,c1 &gt; c2 大于0
* @see java.util.Comparator#compare(Object, Object)
*/
public static <T extends Comparable<? super T>> int compare(T c1, T c2) {
return compare(c1, c2, false);
}
/**
* {@code null}安全的对象比较
*
* @param <T> 被比较对象类型(必须实现Comparable接口)
* @param c1 对象1,可以为{@code null}
* @param c2 对象2,可以为{@code null}
* @param isNullGreater 当被比较对象为null时是否排在后面,true表示null大于任何对象,false反之
* @return 比较结果,如果c1 &lt; c2,返回数小于0,c1==c2返回0,c1 &gt; c2 大于0
* @see java.util.Comparator#compare(Object, Object)
*/
public static <T extends Comparable<? super T>> int compare(T c1, T c2, boolean isNullGreater) {
if (c1 == c2) {
return 0;
} else if (c1 == null) {
return isNullGreater ? 1 : -1;
} else if (c2 == null) {
return isNullGreater ? -1 : 1;
}
return c1.compareTo(c2);
}
/**
* 自然比较两个对象的大小,比较规则如下:
*
* <pre>
* 1、如果实现Comparable调用compareTo比较
* 2、o1.equals(o2)返回0
* 3、比较hashCode值
* 4、比较toString值
* </pre>
*
* @param <T> 被比较对象类型
* @param o1 对象1
* @param o2 对象2
* @param isNullGreater null值是否做为最大值
* @return 比较结果,如果o1 &lt; o2,返回数小于0,o1==o2返回0,o1 &gt; o2 大于0
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public static <T> int compare(T o1, T o2, boolean isNullGreater) {
if (o1 == o2) {
return 0;
} else if (null == o1) {// null 排在后面
return isNullGreater ? 1 : -1;
} else if (null == o2) {
return isNullGreater ? -1 : 1;
}
if (o1 instanceof Comparable && o2 instanceof Comparable) {
//如果bean可比较,直接比较bean
return ((Comparable) o1).compareTo(o2);
}
if (o1.equals(o2)) {
return 0;
}
int result = Integer.compare(o1.hashCode(), o2.hashCode());
if (0 == result) {
result = compare(o1.toString(), o2.toString());
}
return result;
}
/**
* 中文比较器
*
* @param keyExtractor 从对象中提取中文(参与比较的内容)
* @param <T> 对象类型
* @return 中文比较器
* @since 5.4.3
*/
public static <T> Comparator<T> comparingPinyin(Function<T, String> keyExtractor) {
return comparingPinyin(keyExtractor, false);
}
/**
* 中文(拼音)比较器
*
* @param keyExtractor 从对象中提取中文(参与比较的内容)
* @param reverse 是否反序
* @param <T> 对象类型
* @return 中文比较器
* @since 5.4.3
*/
public static <T> Comparator<T> comparingPinyin(Function<T, String> keyExtractor, boolean reverse) {
Objects.requireNonNull(keyExtractor);
PinyinComparator pinyinComparator = new PinyinComparator();
if (reverse) {
return (o1, o2) -> pinyinComparator.compare(keyExtractor.apply(o2), keyExtractor.apply(o1));
}
return (o1, o2) -> pinyinComparator.compare(keyExtractor.apply(o1), keyExtractor.apply(o2));
}
/**
* 索引比较器<br>
* 通过keyExtractor函数,提取对象的某个属性或规则,根据提供的排序数组,完成比较<br>
*
* @param keyExtractor 从对象中提取中文(参与比较的内容)
* @param objs 参与排序的数组,数组的元素位置决定了对象的排序先后
* @param <T> 对象类型
* @param <U> 数组对象类型
* @return 索引比较器
* @since 5.8.0
*/
@SuppressWarnings("unchecked")
public static <T, U> Comparator<T> comparingIndexed(Function<? super T, ? extends U> keyExtractor, U... objs) {
return comparingIndexed(keyExtractor, false, objs);
}
/**
* 索引比较器<br>
* 通过keyExtractor函数,提取对象的某个属性或规则,根据提供的排序数组,完成比较<br>
*
* @param keyExtractor 从对象中提取排序键的函数(参与比较的内容)
* @param atEndIfMiss 如果不在列表中是否排在后边
* @param objs 参与排序的数组,数组的元素位置决定了对象的排序先后
* @param <T> 对象类型
* @param <U> 数组对象类型
* @return 索引比较器
* @since 5.8.0
*/
@SuppressWarnings("unchecked")
public static <T, U> Comparator<T> comparingIndexed(Function<? super T, ? extends U> keyExtractor, boolean atEndIfMiss, U... objs) {
Objects.requireNonNull(keyExtractor);
IndexedComparator<U> indexedComparator = new IndexedComparator<>(atEndIfMiss, objs);
return (o1, o2) -> indexedComparator.compare(keyExtractor.apply(o1), keyExtractor.apply(o2));
}
}
package cn.hutool.core.comparator;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import java.lang.reflect.Field;
/**
* Bean字段排序器<br>
* 参阅feilong-core中的PropertyComparator
*
* @param <T> 被比较的Bean
* @author Looly
*/
public class FieldComparator<T> extends FuncComparator<T> {
private static final long serialVersionUID = 9157326766723846313L;
/**
* 构造
*
* @param beanClass Bean类
* @param fieldName 字段名
*/
public FieldComparator(Class<T> beanClass, String fieldName) {
this(getNonNullField(beanClass, fieldName));
}
/**
* 构造
*
* @param field 字段
*/
public FieldComparator(Field field) {
this(true, field);
}
/**
* 构造
*
* @param nullGreater 是否{@code null}在后
* @param field 字段
*/
public FieldComparator(boolean nullGreater, Field field) {
super(nullGreater, (bean) ->
(Comparable<?>) ReflectUtil.getFieldValue(bean,
Assert.notNull(field, "Field must be not null!")));
}
/**
* 获取字段,附带检查字段不存在的问题。
*
* @param beanClass Bean类
* @param fieldName 字段名
* @return 非null字段
*/
private static Field getNonNullField(Class<?> beanClass, String fieldName) {
final Field field = ClassUtil.getDeclaredField(beanClass, fieldName);
if (field == null) {
throw new IllegalArgumentException(StrUtil.format("Field [{}] not found in Class [{}]", fieldName, beanClass.getName()));
}
return field;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment