Merge branch 'v6-dev' into refactor-stream

# Conflicts:
#	hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java
#	hutool-core/src/main/java/cn/hutool/core/stream/WrappedStream.java
This commit is contained in:
huangchengxing 2022-09-06 12:39:02 +08:00
commit b463b11364
65 changed files with 1897 additions and 647 deletions

View File

@ -3,6 +3,7 @@ package cn.hutool.core.collection.iter;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Objects;
/** /**
* 数组Iterator对象 * 数组Iterator对象
@ -75,7 +76,7 @@ public class ArrayIter<E> implements IterableIter<E>, ResettableIter<E>, Seriali
* @throws NullPointerException array对象为null * @throws NullPointerException array对象为null
*/ */
public ArrayIter(final Object array, final int startIndex, final int endIndex) { public ArrayIter(final Object array, final int startIndex, final int endIndex) {
this.endIndex = Array.getLength(array); this.endIndex = Array.getLength(Objects.requireNonNull(array));
if (endIndex > 0 && endIndex < this.endIndex) { if (endIndex > 0 && endIndex < this.endIndex) {
this.endIndex = endIndex; this.endIndex = endIndex;
} }

View File

@ -1,8 +1,10 @@
package cn.hutool.core.collection.iter; package cn.hutool.core.collection.iter;
import cn.hutool.core.collection.ListUtil; import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjUtil;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -39,12 +41,12 @@ public class CopiedIter<E> implements IterableIter<E>, Serializable {
} }
/** /**
* 构造 * 构造{@code iterator}为空时默认复制一个空迭代器
* *
* @param iterator 被复制的Iterator * @param iterator 被复制的Iterator
*/ */
public CopiedIter(final Iterator<E> iterator) { public CopiedIter(final Iterator<E> iterator) {
final List<E> eleList = ListUtil.of(iterator); final List<E> eleList = ListUtil.of(ObjUtil.defaultIfNull(iterator, Collections.emptyIterator()));
this.listIterator = eleList.iterator(); this.listIterator = eleList.iterator();
} }

View File

@ -1,7 +1,5 @@
package cn.hutool.core.collection.iter; package cn.hutool.core.collection.iter;
import cn.hutool.core.collection.iter.IterableIter;
import java.io.Serializable; import java.io.Serializable;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Iterator; import java.util.Iterator;

View File

@ -32,6 +32,7 @@ public class FilterIter<E> implements Iterator<E> {
* *
* @param iterator 被包装的{@link Iterator} * @param iterator 被包装的{@link Iterator}
* @param filter 过滤函数{@code null}表示不过滤 * @param filter 过滤函数{@code null}表示不过滤
* @throws NullPointerException {@code iterator}{@code null}时抛出
*/ */
public FilterIter(final Iterator<? extends E> iterator, final Predicate<? super E> filter) { public FilterIter(final Iterator<? extends E> iterator, final Predicate<? super E> filter) {
this.iterator = Assert.notNull(iterator); this.iterator = Assert.notNull(iterator);

View File

@ -1,11 +1,9 @@
package cn.hutool.core.collection.iter; package cn.hutool.core.collection.iter;
import cn.hutool.core.lang.Chain; import cn.hutool.core.lang.Chain;
import cn.hutool.core.util.ArrayUtil;
import java.util.ArrayList; import java.util.*;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
/** /**
* 组合{@link Iterator}将多个{@link Iterator}组合在一起便于集中遍历<br> * 组合{@link Iterator}将多个{@link Iterator}组合在一起便于集中遍历<br>
@ -28,16 +26,27 @@ public class IterChain<T> implements Iterator<T>, Chain<Iterator<T>, IterChain<T
/** /**
* 构造 * 构造
* @param iterators 多个{@link Iterator} * @param iterators 多个{@link Iterator}
* @throws IllegalArgumentException 当存在重复的迭代器或添加的迭代器中存在{@code null}时抛出
*/ */
@SafeVarargs @SafeVarargs
public IterChain(final Iterator<T>... iterators) { public IterChain(final Iterator<T>... iterators) {
if (ArrayUtil.isNotEmpty(iterators)) {
for (final Iterator<T> iterator : iterators) { for (final Iterator<T> iterator : iterators) {
addChain(iterator); addChain(iterator);
} }
} }
}
/**
* 添加迭代器
*
* @param iterator 迭代器
* @return 当前实例
* @throws IllegalArgumentException 当迭代器被重复添加或待添加的迭代器为{@code null}时抛出
*/
@Override @Override
public IterChain<T> addChain(final Iterator<T> iterator) { public IterChain<T> addChain(final Iterator<T> iterator) {
Objects.requireNonNull(iterator);
if (allIterators.contains(iterator)) { if (allIterators.contains(iterator)) {
throw new IllegalArgumentException("Duplicate iterator"); throw new IllegalArgumentException("Duplicate iterator");
} }

View File

@ -11,16 +11,7 @@ import cn.hutool.core.util.ObjUtil;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -192,32 +183,35 @@ public class IterUtil {
/** /**
* 获取指定Bean列表中某个字段生成新的列表 * 获取指定Bean列表中某个字段生成新的列表
* *
* @param <R> 返回元素类型
* @param <V> 对象类型 * @param <V> 对象类型
* @param iterable 对象列表 * @param iterable 对象列表
* @param fieldName 字段名会通过反射获取其值 * @param fieldName 字段名会通过反射获取其值
* @return 某个字段值与对象对应Map * @return 某个字段值与对象对应Map
* @since 4.6.2 * @since 4.6.2
*/ */
public static <V> List<Object> fieldValueList(final Iterable<V> iterable, final String fieldName) { public static <V, R> List<R> fieldValueList(final Iterable<V> iterable, final String fieldName) {
return fieldValueList(getIter(iterable), fieldName); return fieldValueList(getIter(iterable), fieldName);
} }
/** /**
* 获取指定Bean列表中某个字段生成新的列表 * 获取指定Bean列表中某个字段生成新的列表
* *
* @param <R> 返回元素类型
* @param <V> 对象类型 * @param <V> 对象类型
* @param iter 对象列表 * @param iter 对象列表
* @param fieldName 字段名会通过反射获取其值 * @param fieldName 字段名会通过反射获取其值
* @return 某个字段值与对象对应Map * @return 某个字段值与对象对应Map
* @since 4.0.10 * @since 4.0.10
*/ */
public static <V> List<Object> fieldValueList(final Iterator<V> iter, final String fieldName) { @SuppressWarnings("unchecked")
final List<Object> result = new ArrayList<>(); public static <V, R> List<R> fieldValueList(final Iterator<V> iter, final String fieldName) {
final List<R> result = new ArrayList<>();
if (null != iter) { if (null != iter) {
V value; V value;
while (iter.hasNext()) { while (iter.hasNext()) {
value = iter.next(); value = iter.next();
result.add(FieldUtil.getFieldValue(value, fieldName)); result.add((R)FieldUtil.getFieldValue(value, fieldName));
} }
} }
return result; return result;
@ -378,7 +372,7 @@ public class IterUtil {
} }
/** /**
* 将列表转成值为List的HashMap * 将列表转成值为List的Map集合
* *
* @param resultMap 结果Map可自定义结果Map类型 * @param resultMap 结果Map可自定义结果Map类型
* @param iterable 值列表 * @param iterable 值列表
@ -702,38 +696,40 @@ public class IterUtil {
} }
/** /**
* 判断两个{@link Iterable} 是否元素和顺序相同返回{@code true}的条件是 * <p>判断两个{@link Iterable}中的元素与其顺序是否相同 <br>
* 当满足下列情况时返回{@code true}
* <ul> * <ul>
* <li>两个{@link Iterable}必须长度相同</li> * <li>两个{@link Iterable}都为{@code null}</li>
* <li>两个{@link Iterable}元素相同index的对象必须equals满足{@link Objects#equals(Object, Object)}</li> * <li>两个{@link Iterable}满足{@code iterable1 == iterable2}</li>
* <li>两个{@link Iterable}所有具有相同下标的元素皆满足{@link Objects#equals(Object, Object)}</li>
* </ul> * </ul>
* 此方法来自Apache-Commons-Collections4 * 此方法来自Apache-Commons-Collections4
* *
* @param list1 列表1 * @param iterable1 列表1
* @param list2 列表2 * @param iterable2 列表2
* @return 是否相同 * @return 是否相同
* @since 5.6.0 * @since 5.6.0
*/ */
public static boolean isEqualList(final Iterable<?> list1, final Iterable<?> list2) { public static boolean isEqualList(final Iterable<?> iterable1, final Iterable<?> iterable2) {
if (list1 == list2) { if (iterable1 == iterable2) {
return true; return true;
} }
if (iterable1 == null || iterable2 == null) {
final Iterator<?> it1 = list1.iterator(); return false;
final Iterator<?> it2 = list2.iterator(); }
final Iterator<?> iter1 = iterable1.iterator();
final Iterator<?> iter2 = iterable2.iterator();
Object obj1; Object obj1;
Object obj2; Object obj2;
while (it1.hasNext() && it2.hasNext()) { while (iter1.hasNext() && iter2.hasNext()) {
obj1 = it1.next(); obj1 = iter1.next();
obj2 = it2.next(); obj2 = iter2.next();
if (false == Objects.equals(obj1, obj2)) { if (false == Objects.equals(obj1, obj2)) {
return false; return false;
} }
} }
// 当两个Iterable长度不一致时返回false // 当两个Iterable长度不一致时返回false
return false == (it1.hasNext() || it2.hasNext()); return false == (iter1.hasNext() || iter2.hasNext());
} }
/** /**

View File

@ -15,4 +15,5 @@ public interface IterableIter<T> extends Iterable<T>, Iterator<T> {
default Iterator<T> iterator() { default Iterator<T> iterator() {
return this; return this;
} }
} }

View File

@ -16,6 +16,8 @@ public class IteratorEnumeration<E> implements Enumeration<E>, Serializable{
private final Iterator<E> iterator; private final Iterator<E> iterator;
/** /**
* 构造 * 构造
* @param iterator {@link Iterator}对象 * @param iterator {@link Iterator}对象

View File

@ -1,11 +1,12 @@
package cn.hutool.core.collection.iter; package cn.hutool.core.collection.iter;
import cn.hutool.core.collection.iter.IterableIter; import cn.hutool.core.lang.Assert;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* 分批迭代工具可以分批处理数据 * 分批迭代工具可以分批处理数据
@ -36,9 +37,11 @@ public class PartitionIter<T> implements IterableIter<List<T>>, Serializable {
* *
* @param iterator 迭代器 * @param iterator 迭代器
* @param partitionSize 每批大小最后一批不满一批算一批 * @param partitionSize 每批大小最后一批不满一批算一批
* @throws IllegalArgumentException {@code partitionSize}小于等于0{@code iterator}{@code null}时抛出
*/ */
public PartitionIter(final Iterator<T> iterator, final int partitionSize) { public PartitionIter(final Iterator<T> iterator, final int partitionSize) {
this.iterator = iterator; Assert.isTrue(partitionSize > 0, "partition size must greater than 0");
this.iterator = Objects.requireNonNull(iterator);
this.partitionSize = partitionSize; this.partitionSize = partitionSize;
} }

View File

@ -1,6 +1,5 @@
package cn.hutool.core.collection.partition; package cn.hutool.core.collection.partition;
import cn.hutool.core.collection.partition.Partition;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import java.util.List; import java.util.List;

View File

@ -164,7 +164,7 @@ public class ZipWriter implements Closeable {
* @throws IORuntimeException IO异常 * @throws IORuntimeException IO异常
*/ */
public ZipWriter add(String path, final InputStream in) throws IORuntimeException { public ZipWriter add(String path, final InputStream in) throws IORuntimeException {
path = StrUtil.nullToEmpty(path); path = StrUtil.emptyIfNull(path);
if (null == in) { if (null == in) {
// 空目录需要检查路径规范性目录以"/"结尾 // 空目录需要检查路径规范性目录以"/"结尾
path = StrUtil.addSuffixIfNot(path, StrUtil.SLASH); path = StrUtil.addSuffixIfNot(path, StrUtil.SLASH);

View File

@ -783,11 +783,7 @@ public class DateTime extends Date {
* @since 3.0.8 * @since 3.0.8
*/ */
public boolean isIn(final Date beginDate, final Date endDate) { public boolean isIn(final Date beginDate, final Date endDate) {
final long beginMills = beginDate.getTime(); return DateUtil.isIn(this, beginDate, endDate);
final long endMills = endDate.getTime();
final long thisMills = this.getTime();
return thisMills >= Math.min(beginMills, endMills) && thisMills <= Math.max(beginMills, endMills);
} }
/** /**

View File

@ -1381,11 +1381,49 @@ public class DateUtil extends CalendarUtil {
* @since 3.0.8 * @since 3.0.8
*/ */
public static boolean isIn(final Date date, final Date beginDate, final Date endDate) { public static boolean isIn(final Date date, final Date beginDate, final Date endDate) {
if (date instanceof DateTime) { return isIn(date, beginDate, endDate, true, true);
return ((DateTime) date).isIn(beginDate, endDate);
} else {
return new DateTime(date).isIn(beginDate, endDate);
} }
/**
* 当前日期是否在日期指定范围内<br>
* 起始日期和结束日期可以互换<br>
* 通过includeBegin, includeEnd参数控制日期范围区间是否为开区间例如传入参数includeBegin=true, includeEnd=false
* 则本方法会判断 date (beginDate, endDate] 是否成立
*
* @param date 被检查的日期
* @param beginDate 起始日期
* @param endDate 结束日期
* @param includeBegin 时间范围是否包含起始日期
* @param includeEnd 时间范围是否包含结束日期
* @return 是否在范围内
* @author FengBaoheng
* @since 5.8.6
*/
public static boolean isIn(final Date date, final Date beginDate, final Date endDate,
final boolean includeBegin, final boolean includeEnd) {
if (date == null || beginDate == null || endDate == null) {
throw new IllegalArgumentException("参数不可为null");
}
final long thisMills = date.getTime();
final long beginMills = beginDate.getTime();
final long endMills = endDate.getTime();
final long rangeMin = Math.min(beginMills, endMills);
final long rangeMax = Math.max(beginMills, endMills);
// 先判断是否满足 date (beginDate, endDate)
boolean isIn = rangeMin < thisMills && thisMills < rangeMax;
// 若不满足则再判断是否在时间范围的边界上
if (false == isIn && includeBegin) {
isIn = thisMills == rangeMin;
}
if (false == isIn && includeEnd) {
isIn = thisMills == rangeMax;
}
return isIn;
} }
/** /**

View File

@ -181,11 +181,49 @@ public class TemporalAccessorUtil extends TemporalUtil{
* @param endDate 结束日期包含 * @param endDate 结束日期包含
* @return 是否在范围内 * @return 是否在范围内
*/ */
public static boolean isIn(TemporalAccessor date, TemporalAccessor beginDate, TemporalAccessor endDate){ public static boolean isIn(final TemporalAccessor date, final TemporalAccessor beginDate, final TemporalAccessor endDate){
final long thisMills = TemporalAccessorUtil.toEpochMilli(date); return isIn(date, beginDate, endDate, true, true);
final long beginMills = TemporalAccessorUtil.toEpochMilli(beginDate); }
final long endMills = TemporalAccessorUtil.toEpochMilli(endDate);
return thisMills >= Math.min(beginMills, endMills) && thisMills <= Math.max(beginMills, endMills); /**
* 当前日期是否在日期指定范围内<br>
* 起始日期和结束日期可以互换<br>
* 通过includeBegin, includeEnd参数控制日期范围区间是否为开区间例如传入参数includeBegin=true, includeEnd=false
* 则本方法会判断 date (beginDate, endDate] 是否成立
*
* @param date 被检查的日期
* @param beginDate 起始日期
* @param endDate 结束日期
* @param includeBegin 时间范围是否包含起始日期
* @param includeEnd 时间范围是否包含结束日期
* @return 是否在范围内
* @author FengBaoheng
* @since 5.8.6
*/
public static boolean isIn(final TemporalAccessor date, final TemporalAccessor beginDate, final TemporalAccessor endDate,
final boolean includeBegin, final boolean includeEnd) {
if (date == null || beginDate == null || endDate == null) {
throw new IllegalArgumentException("参数不可为null");
}
final long thisMills = toEpochMilli(date);
final long beginMills = toEpochMilli(beginDate);
final long endMills = toEpochMilli(endDate);
final long rangeMin = Math.min(beginMills, endMills);
final long rangeMax = Math.max(beginMills, endMills);
// 先判断是否满足 date (beginDate, endDate)
boolean isIn = rangeMin < thisMills && thisMills < rangeMax;
// 若不满足则再判断是否在时间范围的边界上
if (false == isIn && includeBegin) {
isIn = thisMills == rangeMin;
}
if (false == isIn && includeEnd) {
isIn = thisMills == rangeMax;
}
return isIn;
} }
} }

View File

@ -190,7 +190,7 @@ public class ResourceUtil {
* @return {@link URL} * @return {@link URL}
*/ */
public static URL getResourceUrl(String resource, final Class<?> baseClass) { public static URL getResourceUrl(String resource, final Class<?> baseClass) {
resource = StrUtil.nullToEmpty(resource); resource = StrUtil.emptyIfNull(resource);
return (null != baseClass) ? baseClass.getResource(resource) : ClassLoaderUtil.getClassLoader().getResource(resource); return (null != baseClass) ? baseClass.getResource(resource) : ClassLoaderUtil.getClassLoader().getResource(resource);
} }

View File

@ -209,7 +209,7 @@ public class ClassScanner implements Serializable {
* @param charset 编码 * @param charset 编码
*/ */
public ClassScanner(String packageName, final Predicate<Class<?>> classPredicate, final Charset charset) { public ClassScanner(String packageName, final Predicate<Class<?>> classPredicate, final Charset charset) {
packageName = StrUtil.nullToEmpty(packageName); packageName = StrUtil.emptyIfNull(packageName);
this.packageName = packageName; this.packageName = packageName;
this.packageNameWithDot = StrUtil.addSuffixIfNot(packageName, StrUtil.DOT); this.packageNameWithDot = StrUtil.addSuffixIfNot(packageName, StrUtil.DOT);
this.packageDirName = packageName.replace(CharUtil.DOT, File.separatorChar); this.packageDirName = packageName.replace(CharUtil.DOT, File.separatorChar);

View File

@ -0,0 +1,328 @@
package cn.hutool.core.map;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.reflect.TypeReference;
import java.util.Date;
import java.util.Map;
/**
* Map的getXXX封装提供针对通用型的value按照所需类型获取值
*
* @author looly
* @since 6.0.0
*/
public class MapGetUtil {
/**
* 获取Map指定key的值并转换为字符串
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static String getStr(final Map<?, ?> map, final Object key) {
return get(map, key, String.class);
}
/**
* 获取Map指定key的值并转换为字符串
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static String getStr(final Map<?, ?> map, final Object key, final String defaultValue) {
return get(map, key, String.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为Integer
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static Integer getInt(final Map<?, ?> map, final Object key) {
return get(map, key, Integer.class);
}
/**
* 获取Map指定key的值并转换为Integer
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static Integer getInt(final Map<?, ?> map, final Object key, final Integer defaultValue) {
return get(map, key, Integer.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为Double
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static Double getDouble(final Map<?, ?> map, final Object key) {
return get(map, key, Double.class);
}
/**
* 获取Map指定key的值并转换为Double
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static Double getDouble(final Map<?, ?> map, final Object key, final Double defaultValue) {
return get(map, key, Double.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为Float
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static Float getFloat(final Map<?, ?> map, final Object key) {
return get(map, key, Float.class);
}
/**
* 获取Map指定key的值并转换为Float
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static Float getFloat(final Map<?, ?> map, final Object key, final Float defaultValue) {
return get(map, key, Float.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为Short
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static Short getShort(final Map<?, ?> map, final Object key) {
return get(map, key, Short.class);
}
/**
* 获取Map指定key的值并转换为Short
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static Short getShort(final Map<?, ?> map, final Object key, final Short defaultValue) {
return get(map, key, Short.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为Bool
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static Boolean getBool(final Map<?, ?> map, final Object key) {
return get(map, key, Boolean.class);
}
/**
* 获取Map指定key的值并转换为Bool
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static Boolean getBool(final Map<?, ?> map, final Object key, final Boolean defaultValue) {
return get(map, key, Boolean.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为Character
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static Character getChar(final Map<?, ?> map, final Object key) {
return get(map, key, Character.class);
}
/**
* 获取Map指定key的值并转换为Character
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static Character getChar(final Map<?, ?> map, final Object key, final Character defaultValue) {
return get(map, key, Character.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为Long
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static Long getLong(final Map<?, ?> map, final Object key) {
return get(map, key, Long.class);
}
/**
* 获取Map指定key的值并转换为Long
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static Long getLong(final Map<?, ?> map, final Object key, final Long defaultValue) {
return get(map, key, Long.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为{@link Date}
*
* @param map Map
* @param key
* @return
* @since 4.1.2
*/
public static Date getDate(final Map<?, ?> map, final Object key) {
return get(map, key, Date.class);
}
/**
* 获取Map指定key的值并转换为{@link Date}
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 4.1.2
*/
public static Date getDate(final Map<?, ?> map, final Object key, final Date defaultValue) {
return get(map, key, Date.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为指定类型
*
* @param <T> 目标值类型
* @param map Map
* @param key
* @param type 值类型
* @return
* @since 4.0.6
*/
public static <T> T get(final Map<?, ?> map, final Object key, final Class<T> type) {
return get(map, key, type, null);
}
/**
* 获取Map指定key的值并转换为指定类型
*
* @param <T> 目标值类型
* @param map Map
* @param key
* @param type 值类型
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static <T> T get(final Map<?, ?> map, final Object key, final Class<T> type, final T defaultValue) {
return null == map ? defaultValue : Convert.convert(type, map.get(key), defaultValue);
}
/**
* 获取Map指定key的值并转换为指定类型此方法在转换失败后不抛异常返回null
*
* @param <T> 目标值类型
* @param map Map
* @param key
* @param type 值类型
* @param defaultValue 默认值
* @return
* @since 5.5.3
*/
public static <T> T getQuietly(final Map<?, ?> map, final Object key, final Class<T> type, final T defaultValue) {
return null == map ? defaultValue : Convert.convertQuietly(type, map.get(key), defaultValue);
}
/**
* 获取Map指定key的值并转换为指定类型
*
* @param <T> 目标值类型
* @param map Map
* @param key
* @param type 值类型
* @return
* @since 4.5.12
*/
public static <T> T get(final Map<?, ?> map, final Object key, final TypeReference<T> type) {
return get(map, key, type, null);
}
/**
* 获取Map指定key的值并转换为指定类型
*
* @param <T> 目标值类型
* @param map Map
* @param key
* @param type 值类型
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static <T> T get(final Map<?, ?> map, final Object key, final TypeReference<T> type, final T defaultValue) {
return null == map ? defaultValue : Convert.convert(type, map.get(key), defaultValue);
}
/**
* 获取Map指定key的值并转换为指定类型转换失败后返回null不抛异常
*
* @param <T> 目标值类型
* @param map Map
* @param key
* @param type 值类型
* @param defaultValue 默认值
* @return
* @since 5.5.3
*/
public static <T> T getQuietly(final Map<?, ?> map, final Object key, final TypeReference<T> type, final T defaultValue) {
return null == map ? defaultValue : Convert.convertQuietly(type, map.get(key), defaultValue);
}
}

View File

@ -7,7 +7,6 @@ import cn.hutool.core.collection.iter.IterUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.reflect.ConstructorUtil; import cn.hutool.core.reflect.ConstructorUtil;
import cn.hutool.core.reflect.TypeReference;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
@ -16,7 +15,6 @@ import java.util.AbstractMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.Iterator; import java.util.Iterator;
@ -25,7 +23,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.NavigableMap; import java.util.NavigableMap;
import java.util.Set;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -41,7 +38,7 @@ import java.util.stream.Collectors;
* @author Looly * @author Looly
* @since 3.1.1 * @since 3.1.1
*/ */
public class MapUtil { public class MapUtil extends MapGetUtil {
/** /**
* 默认初始大小 * 默认初始大小
@ -250,9 +247,9 @@ public class MapUtil {
if (null == mapType || mapType.isAssignableFrom(AbstractMap.class)) { if (null == mapType || mapType.isAssignableFrom(AbstractMap.class)) {
return new HashMap<>(); return new HashMap<>();
} else { } else {
try{ try {
return (Map<K, V>) ConstructorUtil.newInstance(mapType); return (Map<K, V>) ConstructorUtil.newInstance(mapType);
}catch (UtilException e){ } catch (final UtilException e) {
// 不支持的map类型返回默认的HashMap // 不支持的map类型返回默认的HashMap
return new HashMap<>(); return new HashMap<>();
} }
@ -483,14 +480,14 @@ public class MapUtil {
} }
final List<Map<K, V>> resultList = new ArrayList<>(); final List<Map<K, V>> resultList = new ArrayList<>();
for (Entry<K, ? extends Iterable<V>> entry : listMap.entrySet()) { for (final Entry<K, ? extends Iterable<V>> entry : listMap.entrySet()) {
final Iterator<V> iterator = IterUtil.getIter(entry.getValue()); final Iterator<V> iterator = IterUtil.getIter(entry.getValue());
if (IterUtil.isEmpty(iterator)) { if (IterUtil.isEmpty(iterator)) {
continue; continue;
} }
final K key = entry.getKey(); final K key = entry.getKey();
// 对已经存在的map添加元素 // 对已经存在的map添加元素
for (Map<K, V> map : resultList) { for (final Map<K, V> map : resultList) {
// 还可以继续添加元素 // 还可以继续添加元素
if (iterator.hasNext()) { if (iterator.hasNext()) {
map.put(key, iterator.next()); map.put(key, iterator.next());
@ -966,319 +963,6 @@ public class MapUtil {
return map; return map;
} }
/**
* 获取Map指定key的值并转换为字符串
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static String getStr(final Map<?, ?> map, final Object key) {
return get(map, key, String.class);
}
/**
* 获取Map指定key的值并转换为字符串
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static String getStr(final Map<?, ?> map, final Object key, final String defaultValue) {
return get(map, key, String.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为Integer
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static Integer getInt(final Map<?, ?> map, final Object key) {
return get(map, key, Integer.class);
}
/**
* 获取Map指定key的值并转换为Integer
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static Integer getInt(final Map<?, ?> map, final Object key, final Integer defaultValue) {
return get(map, key, Integer.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为Double
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static Double getDouble(final Map<?, ?> map, final Object key) {
return get(map, key, Double.class);
}
/**
* 获取Map指定key的值并转换为Double
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static Double getDouble(final Map<?, ?> map, final Object key, final Double defaultValue) {
return get(map, key, Double.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为Float
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static Float getFloat(final Map<?, ?> map, final Object key) {
return get(map, key, Float.class);
}
/**
* 获取Map指定key的值并转换为Float
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static Float getFloat(final Map<?, ?> map, final Object key, final Float defaultValue) {
return get(map, key, Float.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为Short
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static Short getShort(final Map<?, ?> map, final Object key) {
return get(map, key, Short.class);
}
/**
* 获取Map指定key的值并转换为Short
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static Short getShort(final Map<?, ?> map, final Object key, final Short defaultValue) {
return get(map, key, Short.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为Bool
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static Boolean getBool(final Map<?, ?> map, final Object key) {
return get(map, key, Boolean.class);
}
/**
* 获取Map指定key的值并转换为Bool
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static Boolean getBool(final Map<?, ?> map, final Object key, final Boolean defaultValue) {
return get(map, key, Boolean.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为Character
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static Character getChar(final Map<?, ?> map, final Object key) {
return get(map, key, Character.class);
}
/**
* 获取Map指定key的值并转换为Character
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static Character getChar(final Map<?, ?> map, final Object key, final Character defaultValue) {
return get(map, key, Character.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为Long
*
* @param map Map
* @param key
* @return
* @since 4.0.6
*/
public static Long getLong(final Map<?, ?> map, final Object key) {
return get(map, key, Long.class);
}
/**
* 获取Map指定key的值并转换为Long
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static Long getLong(final Map<?, ?> map, final Object key, final Long defaultValue) {
return get(map, key, Long.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为{@link Date}
*
* @param map Map
* @param key
* @return
* @since 4.1.2
*/
public static Date getDate(final Map<?, ?> map, final Object key) {
return get(map, key, Date.class);
}
/**
* 获取Map指定key的值并转换为{@link Date}
*
* @param map Map
* @param key
* @param defaultValue 默认值
* @return
* @since 4.1.2
*/
public static Date getDate(final Map<?, ?> map, final Object key, final Date defaultValue) {
return get(map, key, Date.class, defaultValue);
}
/**
* 获取Map指定key的值并转换为指定类型
*
* @param <T> 目标值类型
* @param map Map
* @param key
* @param type 值类型
* @return
* @since 4.0.6
*/
public static <T> T get(final Map<?, ?> map, final Object key, final Class<T> type) {
return get(map, key, type, null);
}
/**
* 获取Map指定key的值并转换为指定类型
*
* @param <T> 目标值类型
* @param map Map
* @param key
* @param type 值类型
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static <T> T get(final Map<?, ?> map, final Object key, final Class<T> type, final T defaultValue) {
return null == map ? defaultValue : Convert.convert(type, map.get(key), defaultValue);
}
/**
* 获取Map指定key的值并转换为指定类型此方法在转换失败后不抛异常返回null
*
* @param <T> 目标值类型
* @param map Map
* @param key
* @param type 值类型
* @param defaultValue 默认值
* @return
* @since 5.5.3
*/
public static <T> T getQuietly(final Map<?, ?> map, final Object key, final Class<T> type, final T defaultValue) {
return null == map ? defaultValue : Convert.convertQuietly(type, map.get(key), defaultValue);
}
/**
* 获取Map指定key的值并转换为指定类型
*
* @param <T> 目标值类型
* @param map Map
* @param key
* @param type 值类型
* @return
* @since 4.5.12
*/
public static <T> T get(final Map<?, ?> map, final Object key, final TypeReference<T> type) {
return get(map, key, type, null);
}
/**
* 获取Map指定key的值并转换为指定类型
*
* @param <T> 目标值类型
* @param map Map
* @param key
* @param type 值类型
* @param defaultValue 默认值
* @return
* @since 5.3.11
*/
public static <T> T get(final Map<?, ?> map, final Object key, final TypeReference<T> type, final T defaultValue) {
return null == map ? defaultValue : Convert.convert(type, map.get(key), defaultValue);
}
/**
* 获取Map指定key的值并转换为指定类型转换失败后返回null不抛异常
*
* @param <T> 目标值类型
* @param map Map
* @param key
* @param type 值类型
* @param defaultValue 默认值
* @return
* @since 5.5.3
*/
public static <T> T getQuietly(final Map<?, ?> map, final Object key, final TypeReference<T> type, final T defaultValue) {
return null == map ? defaultValue : Convert.convertQuietly(type, map.get(key), defaultValue);
}
/** /**
* 重命名键<br> * 重命名键<br>
* 实现方式为一处然后重新put当旧的key不存在直接返回<br> * 实现方式为一处然后重新put当旧的key不存在直接返回<br>
@ -1557,4 +1241,32 @@ public class MapUtil {
} }
return resultMap; return resultMap;
} }
/**
* 根据给定的entry列表根据entry的key进行分组;
*
* @param <K> 键类型
* @param <V> 值类型
* @param entries entry列表
* @return entries
* @since 5.8.6
*/
public static <K, V> Map<K, List<V>> grouping(final Iterable<Map.Entry<K, V>> entries) {
if (CollUtil.isEmpty(entries)) {
return zero();
}
final Map<K, List<V>> map = new HashMap<>();
for (final Map.Entry<K, V> pair : entries) {
final List<V> values;
if (map.containsKey(pair.getKey())) {
values = map.get(pair.getKey());
} else {
values = ListUtil.of();
map.put(pair.getKey(), values);
}
values.add(pair.getValue());
}
return map;
}
} }

View File

@ -579,7 +579,7 @@ public class URLUtil {
if (isEncodePath) { if (isEncodePath) {
path = RFC3986.PATH.encode(path, CharsetUtil.UTF_8); path = RFC3986.PATH.encode(path, CharsetUtil.UTF_8);
} }
return protocol + domain + StrUtil.nullToEmpty(path) + StrUtil.nullToEmpty(params); return protocol + domain + StrUtil.emptyIfNull(path) + StrUtil.emptyIfNull(params);
} }
/** /**

View File

@ -406,7 +406,7 @@ public class UrlQuery {
private void addParam(final String key, final String value, final Charset charset) { private void addParam(final String key, final String value, final Charset charset) {
if (null != key) { if (null != key) {
final String actualKey = URLDecoder.decode(key, charset, isFormUrlEncoded); final String actualKey = URLDecoder.decode(key, charset, isFormUrlEncoded);
this.query.put(actualKey, StrUtil.nullToEmpty(URLDecoder.decode(value, charset, isFormUrlEncoded))); this.query.put(actualKey, StrUtil.emptyIfNull(URLDecoder.decode(value, charset, isFormUrlEncoded)));
} else if (null != value) { } else if (null != value) {
// name为空value作为namevalue赋值null // name为空value作为namevalue赋值null
this.query.put(URLDecoder.decode(value, charset, isFormUrlEncoded), null); this.query.put(URLDecoder.decode(value, charset, isFormUrlEncoded), null);

View File

@ -133,8 +133,7 @@ public class CollectorUtil {
* @param <A> 下游操作在进行中间操作时对应类型 * @param <A> 下游操作在进行中间操作时对应类型
* @return {@link Collector} * @return {@link Collector}
*/ */
public static <T, K, A, D> public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(final Function<? super T, ? extends K> classifier,
Collector<T, ?, Map<K, D>> groupingBy(final Function<? super T, ? extends K> classifier,
final Collector<? super T, A, D> downstream) { final Collector<? super T, A, D> downstream) {
return groupingBy(classifier, HashMap::new, downstream); return groupingBy(classifier, HashMap::new, downstream);
} }
@ -147,8 +146,7 @@ public class CollectorUtil {
* @param <K> 实体中的分组依据对应类型也是Map中key的类型 * @param <K> 实体中的分组依据对应类型也是Map中key的类型
* @return {@link Collector} * @return {@link Collector}
*/ */
public static <T, K> Collector<T, ?, Map<K, List<T>>> public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(final Function<? super T, ? extends K> classifier) {
groupingBy(final Function<? super T, ? extends K> classifier) {
return groupingBy(classifier, Collectors.toList()); return groupingBy(classifier, Collectors.toList());
} }
@ -163,8 +161,7 @@ public class CollectorUtil {
* @param <U> map中value的类型 * @param <U> map中value的类型
* @return 对null友好的 toMap 操作的 {@link Collector}实现 * @return 对null友好的 toMap 操作的 {@link Collector}实现
*/ */
public static <T, K, U> public static <T, K, U> Collector<T, ?, Map<K, U>> toMap(final Function<? super T, ? extends K> keyMapper,
Collector<T, ?, Map<K, U>> toMap(final Function<? super T, ? extends K> keyMapper,
final Function<? super T, ? extends U> valueMapper, final Function<? super T, ? extends U> valueMapper,
final BinaryOperator<U> mergeFunction) { final BinaryOperator<U> mergeFunction) {
return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
@ -235,7 +232,7 @@ public class CollectorUtil {
*/ */
public static <K, V, R extends Map<K, List<V>>> Collector<Map<K, V>, ?, R> reduceListMap(final Supplier<R> mapSupplier) { public static <K, V, R extends Map<K, List<V>>> Collector<Map<K, V>, ?, R> reduceListMap(final Supplier<R> mapSupplier) {
return Collectors.reducing(mapSupplier.get(), value -> { return Collectors.reducing(mapSupplier.get(), value -> {
R result = mapSupplier.get(); final R result = mapSupplier.get();
value.forEach((k, v) -> result.computeIfAbsent(k, i -> new ArrayList<>()).add(v)); value.forEach((k, v) -> result.computeIfAbsent(k, i -> new ArrayList<>()).add(v));
return result; return result;
}, (l, r) -> { }, (l, r) -> {
@ -271,7 +268,7 @@ public class CollectorUtil {
* @since 6.0.0 * @since 6.0.0
*/ */
public static <T, K, V> Collector<T, List<T>, EntryStream<K, V>> toEntryStream( public static <T, K, V> Collector<T, List<T>, EntryStream<K, V>> toEntryStream(
Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends V> valueMapper) { final Function<? super T, ? extends K> keyMapper, final Function<? super T, ? extends V> valueMapper) {
Objects.requireNonNull(keyMapper); Objects.requireNonNull(keyMapper);
Objects.requireNonNull(valueMapper); Objects.requireNonNull(valueMapper);
return transform(ArrayList::new, list -> EntryStream.of(list, keyMapper, valueMapper)); return transform(ArrayList::new, list -> EntryStream.of(list, keyMapper, valueMapper));
@ -306,11 +303,14 @@ public class CollectorUtil {
* @since 6.0.0 * @since 6.0.0
*/ */
public static <T, R, C extends Collection<T>> Collector<T, C, R> transform( public static <T, R, C extends Collection<T>> Collector<T, C, R> transform(
Supplier<C> collFactory, Function<C, R> mapper) { final Supplier<C> collFactory, final Function<C, R> mapper) {
Objects.requireNonNull(collFactory); Objects.requireNonNull(collFactory);
Objects.requireNonNull(mapper); Objects.requireNonNull(mapper);
return new SimpleCollector<>( return new SimpleCollector<>(
collFactory, C::add, (l1, l2) -> { l1.addAll(l2); return l1; }, mapper, CH_NOID collFactory, C::add, (l1, l2) -> {
l1.addAll(l2);
return l1;
}, mapper, CH_NOID
); );
} }
@ -329,7 +329,7 @@ public class CollectorUtil {
* @return 收集器 * @return 收集器
* @since 6.0.0 * @since 6.0.0
*/ */
public static <T, R> Collector<T, List<T>, R> transform(Function<List<T>, R> mapper) { public static <T, R> Collector<T, List<T>, R> transform(final Function<List<T>, R> mapper) {
return transform(ArrayList::new, mapper); return transform(ArrayList::new, mapper);
} }

View File

@ -50,7 +50,7 @@ public class CharSequenceUtil extends StrChecker {
* @param str 被转换的字符串 * @param str 被转换的字符串
* @return 转换后的字符串 * @return 转换后的字符串
*/ */
public static String nullToEmpty(final CharSequence str) { public static String emptyIfNull(final CharSequence str) {
return ObjUtil.defaultIfNull(str, EMPTY).toString(); return ObjUtil.defaultIfNull(str, EMPTY).toString();
} }
@ -61,7 +61,7 @@ public class CharSequenceUtil extends StrChecker {
* @param str 被转换的字符串 * @param str 被转换的字符串
* @return 转换后的字符串 * @return 转换后的字符串
*/ */
public static <T extends CharSequence> T emptyToNull(final T str) { public static <T extends CharSequence> T nullIfEmpty(final T str) {
return isEmpty(str) ? null : str; return isEmpty(str) ? null : str;
} }
@ -2521,7 +2521,7 @@ public class CharSequenceUtil extends StrChecker {
* @return 包装后的字符串 * @return 包装后的字符串
*/ */
public static String wrap(final CharSequence str, final CharSequence prefix, final CharSequence suffix) { public static String wrap(final CharSequence str, final CharSequence prefix, final CharSequence suffix) {
return nullToEmpty(prefix).concat(nullToEmpty(str)).concat(nullToEmpty(suffix)); return emptyIfNull(prefix).concat(emptyIfNull(str)).concat(emptyIfNull(suffix));
} }
/** /**
@ -3990,7 +3990,7 @@ public class CharSequenceUtil extends StrChecker {
public static String concat(final boolean isNullToEmpty, final CharSequence... strs) { public static String concat(final boolean isNullToEmpty, final CharSequence... strs) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
for (final CharSequence str : strs) { for (final CharSequence str : strs) {
sb.append(isNullToEmpty ? nullToEmpty(str) : str); sb.append(isNullToEmpty ? emptyIfNull(str) : str);
} }
return sb.toString(); return sb.toString();
} }

View File

@ -1,5 +1,7 @@
package cn.hutool.core.thread; package cn.hutool.core.thread;
import cn.hutool.core.util.RuntimeUtil;
import java.lang.Thread.UncaughtExceptionHandler; import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService; import java.util.concurrent.CompletionService;
@ -129,7 +131,7 @@ public class ThreadUtil {
} }
// 最佳的线程数 = CPU可用核心数 / (1 - 阻塞系数) // 最佳的线程数 = CPU可用核心数 / (1 - 阻塞系数)
final int poolSize = (int) (Runtime.getRuntime().availableProcessors() / (1 - blockingCoefficient)); final int poolSize = (int) (RuntimeUtil.getProcessorCount() / (1 - blockingCoefficient));
return ExecutorBuilder.of().setCorePoolSize(poolSize).setMaxPoolSize(poolSize).setKeepAliveTime(0L).build(); return ExecutorBuilder.of().setCorePoolSize(poolSize).setMaxPoolSize(poolSize).setKeepAliveTime(0L).build();
} }

View File

@ -1,5 +1,6 @@
package cn.hutool.core.util; package cn.hutool.core.util;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.iter.IterUtil; import cn.hutool.core.collection.iter.IterUtil;
import cn.hutool.core.comparator.CompareUtil; import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
@ -9,15 +10,13 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.math.NumberUtil; import cn.hutool.core.math.NumberUtil;
import cn.hutool.core.reflect.ClassUtil; import cn.hutool.core.reflect.ClassUtil;
import cn.hutool.core.reflect.MethodUtil; import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import java.io.Serializable;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Collection; import java.util.*;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -29,13 +28,12 @@ import java.util.function.Supplier;
public class ObjUtil { public class ObjUtil {
/** /**
* 比较两个对象是否相等 * <p>比较两个对象是否相等满足下述任意条件即返回{@code true}
* 相同的条件有两个满足其一即可<br> * <ul>
* <ol> * <li>若两对象皆为{@link BigDecimal}且满足{@code 0 == obj1.compareTo(obj2)}</li>
* <li>obj1 == null &amp;&amp; obj2 == null</li> * <li>{@code obj1 == null && obj2 == null}</li>
* <li>obj1.equals(obj2)</li> * <li>{@code obj1.equals(obj2)}</li>
* <li>如果是BigDecimal比较0 == obj1.compareTo(obj2)</li> * </ul>
* </ol>
* *
* @param obj1 对象1 * @param obj1 对象1
* @param obj2 对象2 * @param obj2 对象2
@ -50,27 +48,27 @@ public class ObjUtil {
} }
/** /**
* 比较两个对象是否不相等<br> * 比较两个对象是否不相等
* *
* @param obj1 对象1 * @param obj1 对象1
* @param obj2 对象2 * @param obj2 对象2
* @return 是否不等 * @return 是否不等
* @since 3.0.7 * @since 3.0.7
* @see #equals(Object, Object)
*/ */
public static boolean notEquals(final Object obj1, final Object obj2) { public static boolean notEquals(final Object obj1, final Object obj2) {
return false == equals(obj1, obj2); return false == equals(obj1, obj2);
} }
/** /**
* 计算对象长度如果是字符串调用其length函数集合类调用其size函数数组调用其length属性其他可遍历对象遍历计算长度<br> * <p>计算对象长度支持类型包括
* 支持的类型包括
* <ul> * <ul>
* <li>CharSequence</li> * <li>{@code null}默认返回{@code 0}</li>
* <li>Map</li> * <li>数组返回数组长度</li>
* <li>Iterator</li> * <li>{@link CharSequence}返回{@link CharSequence#length()}</li>
* <li>Iterable</li> * <li>{@link Collection}返回{@link Collection#size()}</li>
* <li>Enumeration</li> * <li>{@link Iterator}{@link Iterable}可迭代的元素数量</li>
* <li>Array</li> * <li>{@link Enumeration}返回可迭代的元素数量</li>
* </ul> * </ul>
* *
* @param obj 被计算长度的对象 * @param obj 被计算长度的对象
@ -100,6 +98,9 @@ public class ObjUtil {
} }
return count; return count;
} }
if (obj.getClass().isArray()) {
return Array.getLength(obj);
}
if (obj instanceof Enumeration) { if (obj instanceof Enumeration) {
final Enumeration<?> enumeration = (Enumeration<?>) obj; final Enumeration<?> enumeration = (Enumeration<?>) obj;
count = 0; count = 0;
@ -109,23 +110,21 @@ public class ObjUtil {
} }
return count; return count;
} }
if (obj.getClass().isArray()) {
return Array.getLength(obj);
}
return -1; return -1;
} }
/** /**
* 对象中是否包含元素<br> * <p>检查{@code obj}中是否包含{@code element}{@code obj}{@code null}则直接返回{@code false}<br>
* 支持的对象类型包括 * 支持类型包括
* <ul> * <ul>
* <li>String</li> * <li>{@code null}默认返回{@code false}</li>
* <li>Collection</li> * <li>{@link String}等同{@link String#contains(CharSequence)}</li>
* <li>Map</li> * <li>{@link Collection}等同{@link Collection#contains(Object)}</li>
* <li>Iterator</li> * <li>{@link Map}等同{@link Map#containsValue(Object)}</li>
* <li>Iterable</li> * <li>
* <li>Enumeration</li> * {@link Iterator}{@link Iterable}{@link Enumeration}或数组
* <li>Array</li> * 等同于遍历后对其元素调用{@link #equals(Object, Object)}方法
* </li>
* </ul> * </ul>
* *
* @param obj 对象 * @param obj 对象
@ -182,12 +181,7 @@ public class ObjUtil {
} }
/** /**
* 检查对象是否为null<br> * 检查对象是否为{@code null}
* 判断标准为
*
* <pre>
* 1. == null
* </pre>
* *
* @param obj 对象 * @param obj 对象
* @return 是否为null * @return 是否为null
@ -197,7 +191,7 @@ public class ObjUtil {
} }
/** /**
* 检查对象是否不为null * 检查对象是否不为{@code null}
* *
* @param obj 对象 * @param obj 对象
* @return 是否为null * @return 是否为null
@ -207,19 +201,26 @@ public class ObjUtil {
} }
/** /**
* 判断指定对象是否为空支持 * 判断指定对象是否为空支持类型包括
* * <ul>
* <pre> * <li>{@code null}默认返回{@code true}</li>
* 1. CharSequence * <li>数组等同于{@link ArrayUtil#isEmpty(Object)}</li>
* 2. Map * <li>{@link CharSequence}等同于{@link CharSequenceUtil#isEmpty(CharSequence)}</li>
* 3. Iterable * <li>{@link Collection}等同于{@link CollUtil#isEmpty(Collection)}</li>
* 4. Iterator * <li>{@link Map}等同于{@link MapUtil#isEmpty(Map)}</li>
* 5. Array * <li>
* </pre> * {@link Iterator}{@link Iterable}等同于{@link IterUtil#isEmpty(Iterator)}
* {@link IterUtil#isEmpty(Iterable)}
* </li>
* </ul>
* *
* @param obj 被判断的对象 * @param obj 被判断的对象
* @return 是否为空如果类型不支持返回false * @return 是否为空如果类型不支持返回false
* @since 4.5.7 * @since 4.5.7
* @see StrUtil#isEmpty(CharSequence)
* @see MapUtil#isEmpty(Map)
* @see IterUtil#isEmpty(Iterable)
* @see IterUtil#isEmpty(Iterator)
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public static boolean isEmpty(final Object obj) { public static boolean isEmpty(final Object obj) {
@ -229,7 +230,9 @@ public class ObjUtil {
if (obj instanceof CharSequence) { if (obj instanceof CharSequence) {
return StrUtil.isEmpty((CharSequence) obj); return StrUtil.isEmpty((CharSequence) obj);
} else if (obj instanceof Map) { } else if(obj instanceof Collection){
return CollUtil.isEmpty((Collection)obj);
}else if (obj instanceof Map) {
return MapUtil.isEmpty((Map) obj); return MapUtil.isEmpty((Map) obj);
} else if (obj instanceof Iterable) { } else if (obj instanceof Iterable) {
return IterUtil.isEmpty((Iterable) obj); return IterUtil.isEmpty((Iterable) obj);
@ -243,34 +246,26 @@ public class ObjUtil {
} }
/** /**
* 判断指定对象是否为非空支持 * 判断指定对象是否为非空
*
* <pre>
* 1. CharSequence
* 2. Map
* 3. Iterable
* 4. Iterator
* 5. Array
* </pre>
* *
* @param obj 被判断的对象 * @param obj 被判断的对象
* @return 是否为空如果类型不支持返回true * @return 是否为空如果类型不支持返回true
* @since 4.5.7 * @since 4.5.7
* @see #isEmpty(Object)
*/ */
public static boolean isNotEmpty(final Object obj) { public static boolean isNotEmpty(final Object obj) {
return false == isEmpty(obj); return false == isEmpty(obj);
} }
/** /**
* 如果给定对象为{@code null}返回默认值 * <p>如果给定对象为{@code null}返回默认值
* * <pre>{@code
* <pre> * ObjectUtil.defaultIfNull(null, null); // = null
* ObjectUtil.defaultIfNull(null, null) = null * ObjectUtil.defaultIfNull(null, ""); // = ""
* ObjectUtil.defaultIfNull(null, "") = "" * ObjectUtil.defaultIfNull(null, "zz"); // = "zz"
* ObjectUtil.defaultIfNull(null, "zz") = "zz" * ObjectUtil.defaultIfNull("abc", *); // = "abc"
* ObjectUtil.defaultIfNull("abc", *) = "abc" * ObjectUtil.defaultIfNull(Boolean.TRUE, *); // = Boolean.TRUE
* ObjectUtil.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE * }</pre>
* </pre>
* *
* @param <T> 对象类型 * @param <T> 对象类型
* @param object 被检查对象可能为{@code null} * @param object 被检查对象可能为{@code null}
@ -333,14 +328,20 @@ public class ObjUtil {
} }
/** /**
* 克隆对象<br> * <p>克隆对象
* 如果对象实现Cloneable接口调用其clone方法<br> * <ol>
* 如果实现Serializable接口执行深度克隆<br> * <li>如果对象是数组则等同于{@link ArrayUtil#clone(Object)}</li>
* 否则返回{@code null} * <li>如果对象实现了{@link Cloneable}接口调用其{@code Cloneable#clone()}方法</li>
* <li>如果对象实现了{@link Serializable}接口执行深度克隆</li>
* <li>不符合上述任意情况则返回{@code null}</li>
* </ol>
* *
* @param <T> 对象类型 * @param <T> 对象类型
* @param obj 被克隆对象 * @param obj 被克隆对象
* @return 克隆后的对象 * @return 克隆后的对象
* @see ArrayUtil#clone(Object)
* @see Object#clone()
* @see #cloneByStream(Object)
*/ */
public static <T> T clone(final T obj) { public static <T> T clone(final T obj) {
T result = ArrayUtil.clone(obj); T result = ArrayUtil.clone(obj);
@ -360,6 +361,7 @@ public class ObjUtil {
* @param <T> 对象类型 * @param <T> 对象类型
* @param obj 对象 * @param obj 对象
* @return 克隆后或原对象 * @return 克隆后或原对象
* @see #clone(Object)
*/ */
public static <T> T cloneIfPossible(final T obj) { public static <T> T cloneIfPossible(final T obj) {
T clone = null; T clone = null;
@ -373,12 +375,13 @@ public class ObjUtil {
/** /**
* 序列化后拷贝流的方式克隆<br> * 序列化后拷贝流的方式克隆<br>
* 对象必须实现Serializable接口 * 若对象未实现{@link Serializable}接口则默认返回{@code null}
* *
* @param <T> 对象类型 * @param <T> 对象类型
* @param obj 被克隆对象 * @param obj 被克隆对象
* @return 克隆后的对象 * @return 克隆后的对象
* @throws UtilException IO异常和ClassNotFoundException封装 * @throws UtilException IO异常和ClassNotFoundException封装
* @see SerializeUtil#clone(Object)
*/ */
public static <T> T cloneByStream(final T obj) { public static <T> T cloneByStream(final T obj) {
return SerializeUtil.clone(obj); return SerializeUtil.clone(obj);
@ -399,12 +402,15 @@ public class ObjUtil {
} }
/** /**
* 检查是否为有效的数字<br> * 检查是否为有效的数字若对象不为{@link Number}则直接返回{@code true}否则
* 检查Double和Float是否为无限大或者Not a Number<br> * <ul>
* 非数字类型和Null将返回true * <li>若对象类型为{@link Double}则检查{@link Double#isInfinite()}{@link Double#isNaN()}</li>
* <li>若对象类型为{@link Float}则检查{@link Float#isInfinite()}{@link Float#isNaN()}</li>
* </ul>
* *
* @param obj 被检查类型 * @param obj 被检查类型
* @return 检查结果非数字类型和Null将返回true * @return 检查结果非数字类型和Null将返回true
* @see NumberUtil#isValidNumber(Number)
*/ */
public static boolean isValidIfNumber(final Object obj) { public static boolean isValidIfNumber(final Object obj) {
if (obj instanceof Number) { if (obj instanceof Number) {
@ -454,7 +460,7 @@ public class ObjUtil {
} }
/** /**
* 获得给定类第一个泛型参数 * 获得给定类指定下标的泛型参数
* *
* @param obj 被检查的对象 * @param obj 被检查的对象
* @param index 泛型类型的索引号即第几个泛型类型 * @param index 泛型类型的索引号即第几个泛型类型
@ -466,16 +472,17 @@ public class ObjUtil {
} }
/** /**
* 将Object转为String<br> * <p>将对象转为字符串
* 策略为 * <ul>
* <pre> * <li>若对象为{@code null}则返回null</li>
* 1null转为"null" * <li>若对象为{@link Map}则返回{@code Map#toString()}</li>
* 2调用Convert.toStr(Object)转换 * <li>若对象为其他类型则调用{@link Convert#toStr(Object)}进行转换</li>
* </pre> * </ul>
* *
* @param obj Bean对象 * @param obj Bean对象
* @return Bean所有字段转为Map后的字符串 * @return 转换后的字符串
* @since 3.2.0 * @since 3.2.0
* @see Convert#toStr(Object)
*/ */
public static String toString(final Object obj) { public static String toString(final Object obj) {
if (null == obj) { if (null == obj) {
@ -484,7 +491,6 @@ public class ObjUtil {
if (obj instanceof Map) { if (obj instanceof Map) {
return obj.toString(); return obj.toString();
} }
return Convert.toStr(obj); return Convert.toStr(obj);
} }
} }

View File

@ -13,6 +13,7 @@ import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Stack; import java.util.Stack;
import java.util.concurrent.ThreadPoolExecutor;
/** /**
* 系统运行时工具类用于执行系统命令的工具 * 系统运行时工具类用于执行系统命令的工具
@ -234,11 +235,21 @@ public class RuntimeUtil {
/** /**
* 获得JVM可用的处理器数量一般为CPU核心数 * 获得JVM可用的处理器数量一般为CPU核心数
* *
* <p>
* 这里做一个特殊的处理,在特殊的CPU上面会有获取不到CPU数量的情况所以这里做一个保护;
* 默认给一个7真实的CPU基本都是偶数方便区分
* 如果不做处理会出现创建线程池时{@link ThreadPoolExecutor}抛出异常{@link IllegalArgumentException}
*</p>
*
* @return 可用的处理器数量 * @return 可用的处理器数量
* @since 5.3.0 * @since 5.3.0
*/ */
public static int getProcessorCount() { public static int getProcessorCount() {
return Runtime.getRuntime().availableProcessors(); int cpu = Runtime.getRuntime().availableProcessors();
if (cpu <= 0) {
cpu = 7;
}
return cpu;
} }
/** /**

View File

@ -0,0 +1,50 @@
package cn.hutool.core.collection.iter;
import org.junit.Assert;
import org.junit.Test;
/**
* test for {@link ArrayIter}
*/
public class ArrayIterTest {
@Test
public void testHasNext() {
Integer[] arr = new Integer[]{ 1, 2, 3 };
ArrayIter<Integer> iter = new ArrayIter<>(arr);
Assert.assertTrue(iter.hasNext());
}
@Test
public void testNext() {
Integer[] arr = new Integer[]{ 1, 2, 3 };
ArrayIter<Integer> iter = new ArrayIter<>(arr);
Assert.assertEquals((Integer)1, iter.next());
Assert.assertEquals((Integer)2, iter.next());
Assert.assertEquals((Integer)3, iter.next());
}
@Test
public void testRemove() {
Integer[] arr = new Integer[]{ 1, 2, 3 };
ArrayIter<Integer> iter = new ArrayIter<>(arr);
Assert.assertThrows(UnsupportedOperationException.class, iter::remove);
}
@Test
public void testGetArray() {
Integer[] arr = new Integer[]{ 1, 2, 3 };
ArrayIter<Integer> iter = new ArrayIter<>(arr);
Assert.assertEquals(arr, iter.getArray());
}
@Test
public void testReset() {
Integer[] arr = new Integer[]{ 1, 2, 3 };
ArrayIter<Integer> iter = new ArrayIter<>(arr);
Assert.assertEquals((Integer)1, iter.next());
iter.reset();
Assert.assertEquals((Integer)1, iter.next());
}
}

View File

@ -0,0 +1,47 @@
package cn.hutool.core.collection.iter;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* test for {@link CopiedIter}
*/
public class CopiedIterTest {
@Test
public void copyOf() {
List<Integer> list = Arrays.asList(1, 2, 3);
Iterator<Integer> iter = list.iterator();
Assert.assertEquals((Integer)1, iter.next());
Assert.assertEquals((Integer)2, CopiedIter.copyOf(iter).next());
}
@Test
public void hasNext() {
Assert.assertTrue(CopiedIter.copyOf(Arrays.asList(1, 2, 3).iterator()).hasNext());
Assert.assertFalse(CopiedIter.copyOf(Collections.emptyIterator()).hasNext());
}
@Test
public void next() {
List<Integer> list = Arrays.asList(1, 2, 3);
Iterator<Integer> iter = CopiedIter.copyOf(list.iterator());
Assert.assertEquals((Integer)1, iter.next());
Assert.assertEquals((Integer)2, iter.next());
Assert.assertEquals((Integer)3, iter.next());
}
@Test
public void remove() {
List<Integer> list = Arrays.asList(1, 2, 3);
Iterator<Integer> iter = CopiedIter.copyOf(list.iterator());
Assert.assertThrows(UnsupportedOperationException.class, iter::remove);
}
}

View File

@ -0,0 +1,46 @@
package cn.hutool.core.collection.iter;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
/**
* @author huangchengxing
*/
public class EnumerationIterTest {
@Test
public void testHasNext() {
Enumeration<Integer> enumeration = new IteratorEnumeration<>(Arrays.asList(1, 2, 3).iterator());
EnumerationIter<Integer> iter = new EnumerationIter<>(enumeration);
Assert.assertTrue(iter.hasNext());
Assert.assertFalse(new EnumerationIter<>(new IteratorEnumeration<>(Collections.emptyIterator())).hasNext());
}
@Test
public void testNext() {
Enumeration<Integer> enumeration = new IteratorEnumeration<>(Arrays.asList(1, 2, 3).iterator());
EnumerationIter<Integer> iter = new EnumerationIter<>(enumeration);
Assert.assertEquals((Integer)1, iter.next());
Assert.assertEquals((Integer)2, iter.next());
Assert.assertEquals((Integer)3, iter.next());
}
@Test
public void testRemove() {
Enumeration<Integer> enumeration = new IteratorEnumeration<>(Arrays.asList(1, 2, 3).iterator());
EnumerationIter<Integer> iter = new EnumerationIter<>(enumeration);
Assert.assertThrows(UnsupportedOperationException.class, iter::remove);
}
@Test
public void testIterator() {
Enumeration<Integer> enumeration = new IteratorEnumeration<>(Arrays.asList(1, 2, 3).iterator());
EnumerationIter<Integer> iter = new EnumerationIter<>(enumeration);
Assert.assertSame(iter, iter.iterator());
}
}

View File

@ -4,7 +4,10 @@ import cn.hutool.core.collection.ListUtil;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.function.Predicate;
public class FilterIterTest { public class FilterIterTest {
@ -20,4 +23,40 @@ public class FilterIterTest {
} }
Assert.assertEquals(2, count); Assert.assertEquals(2, count);
} }
@Test
public void hasNext() {
Iterator<Integer> iter = new FilterIter<>(Arrays.asList(1, 2, 3).iterator(), i -> true);
Assert.assertTrue(iter.hasNext());
iter = new FilterIter<>(Collections.emptyIterator(), i -> true);
Assert.assertFalse(iter.hasNext());
}
@Test
public void next() {
// 只保留奇数
Iterator<Integer> iter = new FilterIter<>(Arrays.asList(1, 2, 3).iterator(), i -> (i & 1) == 1);
Assert.assertEquals((Integer)1, iter.next());
Assert.assertEquals((Integer)3, iter.next());
}
@Test
public void remove() {
Iterator<Integer> iter = new FilterIter<>(Collections.emptyIterator(), i -> true);
Assert.assertThrows(IllegalStateException.class, iter::remove);
}
@Test
public void getIterator() {
FilterIter<Integer> iter = new FilterIter<>(Collections.emptyIterator(), i -> true);
Assert.assertSame(Collections.emptyIterator(), iter.getIterator());
}
@Test
public void getFilter() {
Predicate<Integer> predicate = i -> true;
FilterIter<Integer> iter = new FilterIter<>(Collections.emptyIterator(), predicate);
Assert.assertSame(predicate, iter.getFilter());
}
} }

View File

@ -0,0 +1,69 @@
package cn.hutool.core.collection.iter;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
/**
* test for {@link IterChain}
*/
public class IterChainTest {
@Test
public void testAddChain() {
Iterator<Integer> iter1 = Arrays.asList(1, 2).iterator();
Iterator<Integer> iter2 = Arrays.asList(3, 4).iterator();
IterChain<Integer> iterChain = new IterChain<>();
Assert.assertSame(iterChain, iterChain.addChain(iter1));
Assert.assertSame(iterChain, iterChain.addChain(iter2));
Assert.assertEquals(2, iterChain.allIterators.size());
iterChain = new IterChain<>(iter1, iter2);
Assert.assertEquals(2, iterChain.allIterators.size());
}
@Test
public void testHasNext() {
IterChain<Integer> iterChain = new IterChain<>();
Assert.assertFalse(iterChain.hasNext());
Assert.assertFalse(iterChain.addChain(Collections.emptyIterator()).hasNext());
Assert.assertTrue(iterChain.addChain(Arrays.asList(3, 4).iterator()).hasNext());
}
@Test
public void testNext() {
Iterator<Integer> iter1 = Arrays.asList(1, 2).iterator();
Iterator<Integer> iter2 = Arrays.asList(3, 4).iterator();
IterChain<Integer> iterChain = new IterChain<>();
Assert.assertSame(iterChain, iterChain.addChain(iter1));
Assert.assertSame(iterChain, iterChain.addChain(iter2));
Assert.assertEquals((Integer)1, iterChain.next());
Assert.assertEquals((Integer)2, iterChain.next());
Assert.assertEquals((Integer)3, iterChain.next());
Assert.assertEquals((Integer)4, iterChain.next());
}
@Test
public void testRemove() {
IterChain<Integer> iterChain = new IterChain<>();
iterChain.addChain(Arrays.asList(1, 2).iterator());
Assert.assertThrows(IllegalStateException.class, iterChain::remove);
}
@Test
public void testIterator() {
Iterator<Integer> iter1 = Arrays.asList(1, 2).iterator();
Iterator<Integer> iter2 = Arrays.asList(3, 4).iterator();
IterChain<Integer> iterChain = new IterChain<>();
Assert.assertSame(iterChain, iterChain.addChain(iter1));
Assert.assertSame(iterChain, iterChain.addChain(iter2));
Iterator<Iterator<Integer>> iterators = iterChain.iterator();
Assert.assertSame(iter1, iterators.next());
Assert.assertSame(iter2, iterators.next());
}
}

View File

@ -0,0 +1,306 @@
package cn.hutool.core.collection.iter;
import lombok.RequiredArgsConstructor;
import org.junit.Assert;
import org.junit.Test;
import org.w3c.dom.NodeList;
import java.util.*;
import java.util.function.Function;
/**
* test for {@link IterUtil}
*/
public class IterUtilTest {
@Test
public void testGetIter() {
Assert.assertNull(IterUtil.getIter(null));
Assert.assertEquals(Collections.emptyIterator(), IterUtil.getIter(Collections.emptyList()));
Assert.assertNull(IterUtil.getIter((Object)null));
Assert.assertNotNull(IterUtil.getIter(Collections.emptyIterator()));
Assert.assertNotNull(IterUtil.getIter((Object)Collections.emptyList()));
Assert.assertNotNull(IterUtil.getIter(new Integer[0]));
Assert.assertNotNull(IterUtil.getIter(Collections.emptyMap()));
Assert.assertNull(IterUtil.getIter((NodeList)null));
}
@Test
public void testIsEmpty() {
Assert.assertTrue(IterUtil.isEmpty(Collections.emptyIterator()));
Assert.assertFalse(IterUtil.isEmpty(Arrays.asList(1, 2).iterator()));
Assert.assertTrue(IterUtil.isEmpty(Collections.emptyList()));
Assert.assertFalse(IterUtil.isEmpty(Arrays.asList(1, 2)));
}
@Test
public void testIsNotEmpty() {
Assert.assertFalse(IterUtil.isNotEmpty(Collections.emptyIterator()));
Assert.assertTrue(IterUtil.isNotEmpty(Arrays.asList(1, 2).iterator()));
Assert.assertFalse(IterUtil.isNotEmpty(Collections.emptyList()));
Assert.assertTrue(IterUtil.isNotEmpty(Arrays.asList(1, 2)));
}
@Test
public void testHasNull() {
Assert.assertFalse(IterUtil.hasNull(Arrays.asList(1, 3, 2).iterator()));
Assert.assertTrue(IterUtil.hasNull(Arrays.asList(1, null, 2).iterator()));
Assert.assertFalse(IterUtil.hasNull(Collections.emptyIterator()));
Assert.assertTrue(IterUtil.hasNull(null));
}
@Test
public void testIsAllNull() {
Assert.assertTrue(IterUtil.isAllNull(Arrays.asList(null, null)));
Assert.assertFalse(IterUtil.isAllNull(Arrays.asList(1, null)));
Assert.assertTrue(IterUtil.isAllNull((Iterable<?>)null));
Assert.assertTrue(IterUtil.isAllNull(Arrays.asList(null, null).iterator()));
Assert.assertFalse(IterUtil.isAllNull(Arrays.asList(1, null).iterator()));
Assert.assertTrue(IterUtil.isAllNull((Iterator<?>)null));
}
@Test
public void testCountMap() {
Object o1 = new Object();
Object o2 = new Object();
Map<Object, Integer> countMap = IterUtil.countMap(Arrays.asList(o1, o2, o1, o1).iterator());
Assert.assertEquals((Integer)3, countMap.get(o1));
Assert.assertEquals((Integer)1, countMap.get(o2));
}
@Test
public void testFieldValueMap() {
Bean bean1 = new Bean(1, "A");
Bean bean2 = new Bean(2, "B");
Map<Integer, Bean> map = IterUtil.fieldValueMap(Arrays.asList(bean1, bean2).iterator(), "id");
Assert.assertEquals(bean1, map.get(1));
Assert.assertEquals(bean2, map.get(2));
}
@Test
public void testFieldValueAsMap() {
Bean bean1 = new Bean(1, "A");
Bean bean2 = new Bean(2, "B");
Map<Integer, String> map = IterUtil.fieldValueAsMap(
Arrays.asList(bean1, bean2).iterator(), "id", "name"
);
Assert.assertEquals("A", map.get(1));
Assert.assertEquals("B", map.get(2));
}
@Test
public void testFieldValueList() {
Bean bean1 = new Bean(1, "A");
Bean bean2 = new Bean(2, "B");
Assert.assertEquals(Arrays.asList(1, 2), IterUtil.fieldValueList(Arrays.asList(bean1, bean2), "id"));
Assert.assertEquals(
Arrays.asList(1, 2),
IterUtil.fieldValueList(Arrays.asList(bean1, bean2).iterator(), "id")
);
}
@Test
public void testJoin() {
List<String> stringList = Arrays.asList("1", "2", "3");
Assert.assertEquals("123", IterUtil.join(stringList.iterator(), ""));
Assert.assertEquals("-1--2--3-", IterUtil.join(stringList.iterator(), "", "-", "-"));
Assert.assertEquals("123", IterUtil.join(stringList.iterator(), "", Function.identity()));
}
@Test
public void testToMap() {
List<Integer> keys = Arrays.asList(1, 2, 3);
Map<Integer, Integer> map = IterUtil.toMap(keys, keys);
Assert.assertEquals(keys, new ArrayList<>(map.keySet()));
Assert.assertEquals(keys, new ArrayList<>(map.values()));
map = IterUtil.toMap(keys.iterator(), keys.iterator());
Assert.assertEquals(keys, new ArrayList<>(map.keySet()));
Assert.assertEquals(keys, new ArrayList<>(map.values()));
map = IterUtil.toMap(keys.iterator(), keys.iterator(), true);
Assert.assertEquals(keys, new ArrayList<>(map.keySet()));
Assert.assertEquals(keys, new ArrayList<>(map.values()));
map = IterUtil.toMap(keys, keys, true);
Assert.assertEquals(keys, new ArrayList<>(map.keySet()));
Assert.assertEquals(keys, new ArrayList<>(map.values()));
map = IterUtil.toMap(keys, Function.identity());
Assert.assertEquals(keys, new ArrayList<>(map.keySet()));
Assert.assertEquals(keys, new ArrayList<>(map.values()));
map = IterUtil.toMap(keys, Function.identity(), Function.identity());
Assert.assertEquals(keys, new ArrayList<>(map.keySet()));
Assert.assertEquals(keys, new ArrayList<>(map.values()));
}
@Test
public void testToListMap() {
List<Integer> keys = Arrays.asList(1, 2, 3, 4);
Map<Boolean, List<Integer>> map = IterUtil.toListMap(keys, i -> (i & 1) == 0, Function.identity());
Assert.assertEquals(Arrays.asList(2, 4), map.get(true));
Assert.assertEquals(Arrays.asList(1, 3), map.get(false));
map = IterUtil.toListMap(keys, i -> (i & 1) == 0);
Assert.assertEquals(Arrays.asList(2, 4), map.get(true));
Assert.assertEquals(Arrays.asList(1, 3), map.get(false));
map = new LinkedHashMap<>();
Map<Boolean, List<Integer>> rawMap = IterUtil.toListMap(map, keys, i -> (i & 1) == 0, Function.identity());
Assert.assertSame(rawMap, map);
Assert.assertEquals(Arrays.asList(2, 4), rawMap.get(true));
Assert.assertEquals(Arrays.asList(1, 3), rawMap.get(false));
}
@Test
public void testAsIterable() {
Iterator<Integer> iter = Arrays.asList(1, 2, 3).iterator();
Assert.assertEquals(iter, IterUtil.asIterable(iter).iterator());
Assert.assertNull(IterUtil.asIterable(null).iterator());
Enumeration<Integer> enumeration = new IteratorEnumeration<>(iter);
Iterator<Integer> iter2 = IterUtil.asIterator(enumeration);
Assert.assertEquals((Integer)1, iter2.next());
Assert.assertEquals((Integer)2, iter2.next());
Assert.assertEquals((Integer)3, iter2.next());
}
@Test
public void testGet() {
Iterator<Integer> iter = Arrays.asList(1, 2, 3, 4).iterator();
Assert.assertEquals((Integer)3, IterUtil.get(iter, 2));
Assert.assertThrows(IllegalArgumentException.class, () -> IterUtil.get(iter, -1));
}
@Test
public void testGetFirst() {
Iterator<Integer> iter = Arrays.asList(1, 2, 3, 4).iterator();
Assert.assertEquals((Integer)1, IterUtil.getFirst(iter));
Assert.assertNull(IterUtil.getFirst(null));
Assert.assertNull(IterUtil.getFirst(Collections.emptyIterator()));
Assert.assertEquals((Integer)2, IterUtil.getFirst(iter, t -> (t & 1) == 0));
Assert.assertNull(IterUtil.getFirst((Iterator<Integer>)null, t -> (t & 1) == 0));
Assert.assertNull(IterUtil.getFirst(Collections.emptyIterator(), Objects::nonNull));
}
@Test
public void testGetFirstNoneNull() {
Iterator<Integer> iter = Arrays.asList(null, 2, null, 4).iterator();
Assert.assertEquals((Integer)2, IterUtil.getFirstNoneNull(iter));
Assert.assertNull(IterUtil.getFirstNoneNull(null));
Assert.assertNull(IterUtil.getFirstNoneNull(Collections.emptyIterator()));
}
@Test
public void testGetElementType() {
List<Object> list = Arrays.asList(null, "str", null);
Assert.assertEquals(String.class, IterUtil.getElementType(list));
Assert.assertNull(IterUtil.getElementType((Iterable<?>)null));
Assert.assertNull(IterUtil.getElementType(Collections.emptyList()));
Assert.assertEquals(String.class, IterUtil.getElementType(list.iterator()));
Assert.assertNull(IterUtil.getElementType((Iterator<?>)null));
Assert.assertNull(IterUtil.getElementType(Collections.emptyIterator()));
}
@Test
public void testEdit() {
Assert.assertEquals(
Collections.singletonList("str"),
IterUtil.edit(Arrays.asList(null, "str", null).iterator(), t -> t)
);
Assert.assertEquals(
Collections.singletonList("str"),
IterUtil.edit(Arrays.asList(null, "str", null).iterator(), null)
);
Assert.assertEquals(Collections.emptyList(), IterUtil.edit(null, t -> t));
}
@Test
public void testRemove() {
List<Integer> list = new ArrayList<>(Arrays.asList(1, null, null, 3));
IterUtil.remove(list.iterator(), Objects::isNull);
Assert.assertEquals(Arrays.asList(1, 3), list);
}
@Test
public void testFilterToList() {
List<Integer> list1 = new ArrayList<>(Arrays.asList(1, null, null, 3));
List<Integer> list2 = IterUtil.filterToList(list1.iterator(), Objects::nonNull);
Assert.assertSame(list1, list1);
Assert.assertEquals(Arrays.asList(1, 3), list2);
}
@Test
public void testFiltered() {
Assert.assertNotNull(IterUtil.filtered(Collections.emptyIterator(), t -> true));
}
@Test
public void testEmpty() {
Assert.assertSame(Collections.emptyIterator(), IterUtil.empty());
}
@Test
public void testTrans() {
Assert.assertNotNull(IterUtil.trans(Collections.emptyIterator(), t -> true));
}
@Test
public void testSize() {
Assert.assertEquals(0, IterUtil.size((Iterator<?>)null));
Assert.assertEquals(0, IterUtil.size(Collections.emptyIterator()));
Assert.assertEquals(3, IterUtil.size(Arrays.asList(1, 2, 3).iterator()));
Assert.assertEquals(0, IterUtil.size((Iterable<?>)null));
Assert.assertEquals(0, IterUtil.size(Collections.emptyList()));
Assert.assertEquals(3, IterUtil.size(Arrays.asList(1, 2, 3)));
}
@Test
public void testIsEqualList() {
Assert.assertFalse(IterUtil.isEqualList(null, Collections.emptyList()));
Assert.assertFalse(IterUtil.isEqualList(Arrays.asList(1, 2, 3), Collections.emptyList()));
Assert.assertFalse(IterUtil.isEqualList(Arrays.asList(1, 2, 3), Arrays.asList(1, 2)));
Assert.assertTrue(IterUtil.isEqualList(Arrays.asList(1, 2, 3), Arrays.asList(1, 2, 3)));
Assert.assertTrue(IterUtil.isEqualList(null, null));
Assert.assertTrue(IterUtil.isEqualList(Collections.emptyList(), Collections.emptyList()));
}
@Test
public void testClear() {
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
IterUtil.clear(list.iterator());
Assert.assertTrue(list.isEmpty());
Assert.assertThrows(UnsupportedOperationException.class, () -> IterUtil.clear(Arrays.asList(1, 2).iterator()));
}
@Test
public void testToStr() {
List<Integer> list = Arrays.asList(1, 2, 3);
Assert.assertEquals("[1, 2, 3]", IterUtil.toStr(list.iterator()));
Assert.assertEquals("[1, 2, 3]", IterUtil.toStr(list.iterator(), Objects::toString));
Assert.assertEquals("{1:2:3}", IterUtil.toStr(list.iterator(), Objects::toString, ":", "{", "}"));
}
@Test
public void testForEach() {
List<Integer> list = new ArrayList<>();
IterUtil.forEach(Arrays.asList(1, 2, 3, 4).iterator(), list::add);
Assert.assertEquals(Arrays.asList(1, 2, 3, 4), list);
}
@RequiredArgsConstructor
private static class Bean {
private final Integer id;
private final String name;
}
}

View File

@ -0,0 +1,32 @@
package cn.hutool.core.collection.iter;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* test for {@link IteratorEnumeration}
*/
public class IteratorEnumerationTest {
@Test
public void testHasMoreElements() {
List<Integer> list = Arrays.asList(1, 2, 3);
IteratorEnumeration<Integer> enumeration = new IteratorEnumeration<>(list.iterator());
Assert.assertTrue(enumeration.hasMoreElements());
Assert.assertFalse(new IteratorEnumeration<>(Collections.emptyIterator()).hasMoreElements());
}
@Test
public void testNextElement() {
List<Integer> list = Arrays.asList(1, 2, 3);
IteratorEnumeration<Integer> enumeration = new IteratorEnumeration<>(list.iterator());
Assert.assertEquals((Integer)1, enumeration.nextElement());
Assert.assertEquals((Integer)2, enumeration.nextElement());
Assert.assertEquals((Integer)3, enumeration.nextElement());
}
}

View File

@ -0,0 +1,68 @@
package cn.hutool.core.collection.iter;
import org.junit.Assert;
import org.junit.Test;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.NoSuchElementException;
/**
* test for {@link LineIter}
*/
public class LineIterTest {
@Test
public void testHasNext() {
LineIter iter = getItrFromClasspathFile();
Assert.assertTrue(iter.hasNext());
}
@Test
public void testNext() {
LineIter iter = getItrFromClasspathFile();
Assert.assertEquals("is first line", iter.next());
Assert.assertEquals("is second line", iter.next());
Assert.assertEquals("is third line", iter.next());
}
@Test
public void testRemove() {
LineIter iter = getItrFromClasspathFile();
iter.next();
Assert.assertThrows(UnsupportedOperationException.class, iter::remove);
}
@Test
public void testFinish() {
LineIter iter = getItrFromClasspathFile();
iter.finish();
Assert.assertThrows(NoSuchElementException.class, iter::next);
}
@Test
public void testClose() throws IOException {
URL url = LineIterTest.class.getClassLoader().getResource("text.txt");
Assert.assertNotNull(url);
FileInputStream inputStream = new FileInputStream(url.getFile());
LineIter iter = new LineIter(inputStream, StandardCharsets.UTF_8);
iter.close();
Assert.assertThrows(NoSuchElementException.class, iter::next);
Assert.assertThrows(IOException.class, inputStream::read);
}
private static LineIter getItrFromClasspathFile() {
URL url = LineIterTest.class.getClassLoader().getResource("text.txt");
Assert.assertNotNull(url);
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(url.getFile());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
return new LineIter(bufferedReader);
}
}

View File

@ -0,0 +1,31 @@
package cn.hutool.core.collection.iter;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
/**
* test for {@link PartitionIter}
*/
public class PartitionIterTest {
@Test
public void testHasNext() {
Iterator<Integer> iter = Arrays.asList(1, 2, 3, 4).iterator();
PartitionIter<Integer> partitionIter = new PartitionIter<>(iter, 2);
Assert.assertTrue(partitionIter.hasNext());
Assert.assertFalse(new PartitionIter<>(Collections.emptyIterator(), 1).hasNext());
}
@Test
public void testNext() {
Iterator<Integer> iter = Arrays.asList(1, 2, 3, 4).iterator();
PartitionIter<Integer> partitionIter = new PartitionIter<>(iter, 2);
Assert.assertEquals(Arrays.asList(1, 2), partitionIter.next());
Assert.assertEquals(Arrays.asList(3, 4), partitionIter.next());
}
}

View File

@ -0,0 +1,44 @@
package cn.hutool.core.collection.iter;
import cn.hutool.core.collection.ListUtil;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
/**
* @author huangchengxing
*/
public class TransIterTest {
@Test
public void testHasNext() {
TransIter<Integer, String> iter = new TransIter<>(Arrays.asList(1, 2, 3).iterator(), String::valueOf);
Assert.assertTrue(iter.hasNext());
Assert.assertFalse(new TransIter<>(Collections.emptyIterator(), Function.identity()).hasNext());
}
@Test
public void testNext() {
TransIter<Integer, String> iter = new TransIter<>(Arrays.asList(1, 2, 3).iterator(), String::valueOf);
Assert.assertEquals("1", iter.next());
Assert.assertEquals("2", iter.next());
Assert.assertEquals("3", iter.next());
}
@Test
public void testRemove() {
List<Integer> list = ListUtil.of(1, 2, 3);
TransIter<Integer, String> iter = new TransIter<>(list.iterator(), String::valueOf);
iter.next();
iter.remove();
iter.next();
iter.remove();
iter.next();
iter.remove();
Assert.assertTrue(list.isEmpty());
}
}

View File

@ -10,7 +10,6 @@ import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
import java.util.Objects; import java.util.Objects;
public class TimeUtilTest { public class TimeUtilTest {
@ -234,7 +233,49 @@ public class TimeUtilTest {
@Test @Test
public void ofTest2(){ public void ofTest2(){
final Instant instant = Objects.requireNonNull(DateUtil.parse("2022-02-22")).toInstant(); final Instant instant = Objects.requireNonNull(DateUtil.parse("2022-02-22")).toInstant();
final LocalDateTime of = TimeUtil.of((TemporalAccessor) instant); final LocalDateTime of = TimeUtil.of(instant);
Console.log(of); Console.log(of);
} }
@SuppressWarnings("ConstantConditions")
@Test
public void isInTest() {
// 时间范围 8点-9点
final LocalDateTime begin = LocalDateTime.parse("2019-02-02T08:00:00");
final LocalDateTime end = LocalDateTime.parse("2019-02-02T09:00:00");
// 不在时间范围内 用例
Assert.assertFalse(TimeUtil.isIn(LocalDateTime.parse("2019-02-02T06:00:00"), begin, end));
Assert.assertFalse(TimeUtil.isIn(LocalDateTime.parse("2019-02-02T13:00:00"), begin, end));
Assert.assertFalse(TimeUtil.isIn(LocalDateTime.parse("2019-02-01T08:00:00"), begin, end));
Assert.assertFalse(TimeUtil.isIn(LocalDateTime.parse("2019-02-03T09:00:00"), begin, end));
// 在时间范围内 用例
Assert.assertTrue(TimeUtil.isIn(LocalDateTime.parse("2019-02-02T08:00:00"), begin, end));
Assert.assertTrue(TimeUtil.isIn(LocalDateTime.parse("2019-02-02T08:00:01"), begin, end));
Assert.assertTrue(TimeUtil.isIn(LocalDateTime.parse("2019-02-02T08:11:00"), begin, end));
Assert.assertTrue(TimeUtil.isIn(LocalDateTime.parse("2019-02-02T08:22:00"), begin, end));
Assert.assertTrue(TimeUtil.isIn(LocalDateTime.parse("2019-02-02T08:59:59"), begin, end));
Assert.assertTrue(TimeUtil.isIn(LocalDateTime.parse("2019-02-02T09:00:00"), begin, end));
// 测试边界条件
Assert.assertTrue(TimeUtil.isIn(begin, begin, end, true, false));
Assert.assertFalse(TimeUtil.isIn(begin, begin, end, false, false));
Assert.assertTrue(TimeUtil.isIn(end, begin, end, false, true));
Assert.assertFalse(TimeUtil.isIn(end, begin, end, false, false));
// beginend互换
Assert.assertTrue(TimeUtil.isIn(begin, end, begin, true, true));
// 比较当前时间范围
final LocalDateTime now = LocalDateTime.now();
Assert.assertTrue(TimeUtil.isIn(now, now.minusHours(1L), now.plusHours(1L)));
Assert.assertFalse(TimeUtil.isIn(now, now.minusHours(1L), now.minusHours(2L)));
Assert.assertFalse(TimeUtil.isIn(now, now.plusHours(1L), now.plusHours(2L)));
// 异常入参
Assert.assertThrows(IllegalArgumentException.class, () -> TimeUtil.isIn(null, begin, end, false, false));
Assert.assertThrows(IllegalArgumentException.class, () -> TimeUtil.isIn(begin, null, end, false, false));
Assert.assertThrows(IllegalArgumentException.class, () -> TimeUtil.isIn(begin, begin, null, false, false));
}
} }

View File

@ -47,14 +47,14 @@ public class CollectorUtilTest {
@Test @Test
public void testToEasyStream() { public void testToEasyStream() {
Stream<Integer> stream =Stream.of(1, 2, 3, 4) final Stream<Integer> stream =Stream.of(1, 2, 3, 4)
.collect(CollectorUtil.toEasyStream()); .collect(CollectorUtil.toEasyStream());
Assert.assertEquals(EasyStream.class, stream.getClass()); Assert.assertEquals(EasyStream.class, stream.getClass());
} }
@Test @Test
public void testToEntryStream() { public void testToEntryStream() {
Map<String, Integer> map = Stream.of(1, 2, 3, 4, 5) final Map<String, Integer> map = Stream.of(1, 2, 3, 4, 5)
// 转为EntryStream // 转为EntryStream
.collect(CollectorUtil.toEntryStream(Function.identity(), String::valueOf)) .collect(CollectorUtil.toEntryStream(Function.identity(), String::valueOf))
// 过滤偶数 // 过滤偶数

View File

@ -218,7 +218,7 @@ public class EasyStreamTest {
} }
@Test @Test
public void testPeek(){ public void testPeek() {
EasyStream.of("one", "two", "three", "four") EasyStream.of("one", "two", "three", "four")
.filter(e -> e.length() == 4) .filter(e -> e.length() == 4)
.peek(e -> Assert.assertEquals("four", e)) .peek(e -> Assert.assertEquals("four", e))
@ -228,12 +228,12 @@ public class EasyStreamTest {
} }
@Test @Test
public void testPeekIdx(){ public void testPeekIdx() {
EasyStream.of("one", "two", "three", "four") EasyStream.of("one", "two", "three", "four")
.filter(e -> e.length() == 4) .filter(e -> e.length() == 4)
.peekIdx((e,i) -> Assert.assertEquals("four:0", e + ":" + i)) .peekIdx((e, i) -> Assert.assertEquals("four:0", e + ":" + i))
.map(String::toUpperCase) .map(String::toUpperCase)
.peekIdx((e,i) -> Assert.assertEquals("FOUR:0", e + ":" + i)) .peekIdx((e, i) -> Assert.assertEquals("FOUR:0", e + ":" + i))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@ -431,7 +431,7 @@ public class EasyStreamTest {
@Test @Test
public void testToTree() { public void testToTree() {
Consumer<Object> test = o -> { Consumer<Object> test = o -> {
List<Student> studentTree = EasyStream final List<Student> studentTree = EasyStream
.of( .of(
Student.builder().id(1L).name("dromara").build(), Student.builder().id(1L).name("dromara").build(),
Student.builder().id(2L).name("baomidou").build(), Student.builder().id(2L).name("baomidou").build(),
@ -464,7 +464,7 @@ public class EasyStreamTest {
), studentTree); ), studentTree);
}; };
test = test.andThen(o -> { test = test.andThen(o -> {
List<Student> studentTree = EasyStream final List<Student> studentTree = EasyStream
.of( .of(
Student.builder().id(1L).name("dromara").matchParent(true).build(), Student.builder().id(1L).name("dromara").matchParent(true).build(),
Student.builder().id(2L).name("baomidou").matchParent(true).build(), Student.builder().id(2L).name("baomidou").matchParent(true).build(),
@ -501,7 +501,7 @@ public class EasyStreamTest {
@Test @Test
public void testFlatTree() { public void testFlatTree() {
List<Student> studentTree = asList( final List<Student> studentTree = asList(
Student.builder().id(1L).name("dromara") Student.builder().id(1L).name("dromara")
.children(asList(Student.builder().id(3L).name("hutool").parentId(1L) .children(asList(Student.builder().id(3L).name("hutool").parentId(1L)
.children(singletonList(Student.builder().id(6L).name("looly").parentId(3L).build())) .children(singletonList(Student.builder().id(6L).name("looly").parentId(3L).build()))

View File

@ -1,17 +1,23 @@
package cn.hutool.core.util; package cn.hutool.core.util;
import cn.hutool.core.collection.ListUtil; import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.exceptions.CloneRuntimeException; import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
/**
* test for {@link ObjUtil}
*/
public class ObjUtilTest { public class ObjUtilTest {
@Test @Test
@ -56,43 +62,49 @@ public class ObjUtilTest {
final Iterable<Integer> list = ListUtil.of(1, 2, 3); final Iterable<Integer> list = ListUtil.of(1, 2, 3);
Assert.assertEquals(3, ObjUtil.length(list)); Assert.assertEquals(3, ObjUtil.length(list));
Assert.assertEquals(3, ObjUtil.length(Arrays.asList(1, 2, 3).iterator()));
} }
@Test @Test
public void containsTest(){ public void containsTest(){
final int[] array = new int[]{1,2,3,4,5}; Assert.assertTrue(ObjUtil.contains(new int[]{1,2,3,4,5}, 1));
Assert.assertFalse(ObjUtil.contains(null, 1));
final boolean contains = ObjUtil.contains(array, 1); Assert.assertTrue(ObjUtil.contains("123", "3"));
Assert.assertTrue(contains); Map<Integer, Integer> map = new HashMap<>();
map.put(1, 1);
map.put(2, 2);
Assert.assertTrue(ObjUtil.contains(map, 1));
Assert.assertTrue(ObjUtil.contains(Arrays.asList(1, 2, 3).iterator(), 2));
} }
@Test @Test
public void cloneTest() { public void isNullTest() {
final Obj obj = new Obj(); Assert.assertTrue(ObjUtil.isNull(null));
final Obj obj2 = ObjUtil.clone(obj);
Assert.assertEquals("OK", obj2.doSomeThing());
}
static class Obj implements Cloneable {
public String doSomeThing() {
return "OK";
}
@Override
public Obj clone() {
try {
return (Obj) super.clone();
} catch (final CloneNotSupportedException e) {
throw new CloneRuntimeException(e);
}
}
} }
@Test @Test
public void toStringTest() { public void isNotNullTest() {
final ArrayList<String> strings = ListUtil.of("1", "2"); Assert.assertFalse(ObjUtil.isNotNull(null));
final String result = ObjUtil.toString(strings); }
Assert.assertEquals("[1, 2]", result);
@Test
public void isEmptyTest() {
Assert.assertTrue(ObjUtil.isEmpty(null));
Assert.assertTrue(ObjUtil.isEmpty(new int[0]));
Assert.assertTrue(ObjUtil.isEmpty(""));
Assert.assertTrue(ObjUtil.isEmpty(Collections.emptyList()));
Assert.assertTrue(ObjUtil.isEmpty(Collections.emptyMap()));
Assert.assertTrue(ObjUtil.isEmpty(Collections.emptyIterator()));
}
@Test
public void isNotEmptyTest() {
Assert.assertFalse(ObjUtil.isNotEmpty(null));
Assert.assertFalse(ObjUtil.isNotEmpty(new int[0]));
Assert.assertFalse(ObjUtil.isNotEmpty(""));
Assert.assertFalse(ObjUtil.isNotEmpty(Collections.emptyList()));
Assert.assertFalse(ObjUtil.isNotEmpty(Collections.emptyMap()));
Assert.assertFalse(ObjUtil.isNotEmpty(Collections.emptyIterator()));
} }
@Test @Test
@ -113,6 +125,48 @@ public class ObjUtilTest {
Assert.assertSame(val2, ObjUtil.defaultIfNull(null, Function.identity(), val2)); Assert.assertSame(val2, ObjUtil.defaultIfNull(null, Function.identity(), val2));
} }
@Test
public void cloneTest() {
Assert.assertNull(ObjUtil.clone(null));
final CloneableBean cloneableBean1 = new CloneableBean(1);
final CloneableBean cloneableBean2 = ObjUtil.clone(cloneableBean1);
Assert.assertEquals(cloneableBean1, cloneableBean2);
final SerializableBean serializableBean1 = new SerializableBean(2);
final SerializableBean serializableBean2 = ObjUtil.clone(serializableBean1);
Assert.assertEquals(serializableBean1, serializableBean2);
final Bean bean1 = new Bean(3);
Assert.assertNull(ObjUtil.clone(bean1));
}
@Test
public void cloneIfPossibleTest() {
Assert.assertNull(ObjUtil.clone(null));
final CloneableBean cloneableBean1 = new CloneableBean(1);
Assert.assertEquals(cloneableBean1, ObjUtil.cloneIfPossible(cloneableBean1));
final SerializableBean serializableBean1 = new SerializableBean(2);
Assert.assertEquals(serializableBean1, ObjUtil.cloneIfPossible(serializableBean1));
final Bean bean1 = new Bean(3);
Assert.assertSame(bean1, ObjUtil.cloneIfPossible(bean1));
final ExceptionCloneableBean exceptionBean1 = new ExceptionCloneableBean(3);
Assert.assertSame(exceptionBean1, ObjUtil.cloneIfPossible(exceptionBean1));
}
@Test
public void cloneByStreamTest() {
Assert.assertNull(ObjUtil.cloneByStream(null));
Assert.assertNull(ObjUtil.cloneByStream(new CloneableBean(1)));
final SerializableBean serializableBean1 = new SerializableBean(2);
Assert.assertEquals(serializableBean1, ObjUtil.cloneByStream(serializableBean1));
Assert.assertNull(ObjUtil.cloneByStream(new Bean(1)));
}
@Test @Test
public void isBasicTypeTest(){ public void isBasicTypeTest(){
final int a = 1; final int a = 1;
@ -121,9 +175,72 @@ public class ObjUtilTest {
} }
@Test @Test
public void cloneIfPossibleTest() { public void isValidIfNumberTest() {
final String a = "a"; Assert.assertTrue(ObjUtil.isValidIfNumber(null));
final String a2 = ObjUtil.cloneIfPossible(a); Assert.assertFalse(ObjUtil.isValidIfNumber(Double.NEGATIVE_INFINITY));
Assert.assertNotSame(a, a2); Assert.assertFalse(ObjUtil.isValidIfNumber(Double.NaN));
Assert.assertTrue(ObjUtil.isValidIfNumber(Double.MIN_VALUE));
Assert.assertFalse(ObjUtil.isValidIfNumber(Float.NEGATIVE_INFINITY));
Assert.assertFalse(ObjUtil.isValidIfNumber(Float.NaN));
Assert.assertTrue(ObjUtil.isValidIfNumber(Float.MIN_VALUE));
} }
@Test
public void compareTest() {
Assert.assertEquals(0, ObjUtil.compare(1, 1));
Assert.assertEquals(1, ObjUtil.compare(1, null));
Assert.assertEquals(-1, ObjUtil.compare(null, 1));
Assert.assertEquals(-1, ObjUtil.compare(1, null, true));
Assert.assertEquals(1, ObjUtil.compare(null, 1, true));
}
@Test
public void getTypeArgumentTest() {
final Bean bean = new Bean(1);
Assert.assertEquals(Integer.class, ObjUtil.getTypeArgument(bean));
Assert.assertEquals(String.class, ObjUtil.getTypeArgument(bean, 1));
}
@Test
public void toStringTest() {
Assert.assertEquals("null", ObjUtil.toString(null));
Assert.assertEquals(Collections.emptyMap().toString(), ObjUtil.toString(Collections.emptyMap()));
Assert.assertEquals("[1, 2]", Arrays.asList("1", "2").toString());
}
@RequiredArgsConstructor
@EqualsAndHashCode
private static class ExceptionCloneableBean implements Cloneable {
private final Integer id;
@Override
protected Object clone() throws CloneNotSupportedException {
throw new RuntimeException("can not clone this object");
}
}
@RequiredArgsConstructor
@EqualsAndHashCode
private static class CloneableBean implements Cloneable {
private final Integer id;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
@RequiredArgsConstructor
@EqualsAndHashCode
private static class SerializableBean implements Serializable {
private final Integer id;
}
@RequiredArgsConstructor
@EqualsAndHashCode
private static class Bean implements TypeArgument<Integer, String> {
private final Integer id;
}
private interface TypeArgument<A, B> {};
} }

View File

@ -43,4 +43,11 @@ public class RuntimeUtilTest {
final int pid = RuntimeUtil.getPid(); final int pid = RuntimeUtil.getPid();
Assert.assertTrue(pid > 0); Assert.assertTrue(pid > 0);
} }
@Test
public void getProcessorCountTest(){
int cpu = RuntimeUtil.getProcessorCount();
Console.log("cpu个数{}", cpu);
Assert.assertTrue(cpu > 0);
}
} }

View File

@ -0,0 +1,3 @@
is first line
is second line
is third line

View File

@ -2,8 +2,9 @@ package cn.hutool.extra.ftp;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.CharsetUtil;
import java.io.Closeable; import java.io.Closeable;
import java.io.File; import java.io.File;
@ -73,7 +74,12 @@ public abstract class AbstractFtp implements Closeable {
* @since 5.7.5 * @since 5.7.5
*/ */
public boolean isDir(final String dir) { public boolean isDir(final String dir) {
final String workDir = pwd();
try {
return cd(dir); return cd(dir);
} finally {
cd(workDir);
}
} }
/** /**
@ -85,14 +91,35 @@ public abstract class AbstractFtp implements Closeable {
public abstract boolean mkdir(String dir); public abstract boolean mkdir(String dir);
/** /**
* 文件或目录是否存在 * 文件或目录是否存在<br>
* <ul>
* <li>提供路径为空则返回{@code false}</li>
* <li>提供路径非目录但是以'/''\'结尾返回{@code false}</li>
* <li>文件名是'.'或者'..'返回{@code false}</li>
* </ul>
* *
* @param path 目录 * @param path 目录
* @return 是否存在 * @return 是否存在
*/ */
public boolean exist(final String path) { public boolean exist(final String path) {
if (StrUtil.isBlank(path)) {
return false;
}
// 目录验证
if (isDir(path)) {
return true;
}
if (CharUtil.isFileSeparator(path.charAt(path.length() - 1))) {
return false;
}
final String fileName = FileUtil.getName(path); final String fileName = FileUtil.getName(path);
final String dir = StrUtil.removeSuffix(path, fileName); if (".".equals(fileName) || "..".equals(fileName)) {
return false;
}
// 文件验证
final String dir = StrUtil.defaultIfEmpty(StrUtil.removeSuffix(path, fileName), ".");
final List<String> names; final List<String> names;
try { try {
names = ls(dir); names = ls(dir);
@ -180,7 +207,7 @@ public abstract class AbstractFtp implements Closeable {
/** /**
* 下载文件-避免未完成的文件<br> * 下载文件-避免未完成的文件<br>
* 来自https://gitee.com/dromara/hutool/pulls/407<br> * 来自<a href="https://gitee.com/dromara/hutool/pulls/407">https://gitee.com/dromara/hutool/pulls/407</a><br>
* 此方法原理是先在目标文件同级目录下创建临时文件下载之等下载完毕后重命名避免因下载错误导致的文件不完整 * 此方法原理是先在目标文件同级目录下创建临时文件下载之等下载完毕后重命名避免因下载错误导致的文件不完整
* *
* @param path 文件路径 * @param path 文件路径

View File

@ -89,5 +89,66 @@ public class FtpTest {
name, name,
FileUtil.file("d:/test/download/" + name)); FileUtil.file("d:/test/download/" + name));
} }
IoUtil.close(ftp);
}
@Test
@Ignore
public void isDirTest() throws Exception {
try (final Ftp ftp = new Ftp("127.0.0.1", 21)) {
Console.log(ftp.pwd());
ftp.isDir("/test");
Console.log(ftp.pwd());
}
}
@Test
@Ignore
public void existSftpTest() throws Exception {
try (final Sftp ftp = new Sftp("127.0.0.1", 22, "test", "test")) {
Console.log(ftp.pwd());
Console.log(ftp.exist(null));
Console.log(ftp.exist(""));
Console.log(ftp.exist("."));
Console.log(ftp.exist(".."));
Console.log(ftp.exist("/"));
Console.log(ftp.exist("a"));
Console.log(ftp.exist("/home/test"));
Console.log(ftp.exist("/home/test/"));
Console.log(ftp.exist("/home/test//////"));
Console.log(ftp.exist("/home/test/file1"));
Console.log(ftp.exist("/home/test/file1/"));
Console.log(ftp.exist("///////////"));
Console.log(ftp.exist("./"));
Console.log(ftp.exist("./file1"));
Console.log(ftp.pwd());
}
}
@Test
@Ignore
public void existFtpTest() throws Exception {
try (final Ftp ftp = new Ftp("127.0.0.1", 21)) {
Console.log(ftp.pwd());
Console.log(ftp.exist(null));
Console.log(ftp.exist(""));
Console.log(ftp.exist("."));
Console.log(ftp.exist(".."));
Console.log(ftp.exist("/"));
Console.log(ftp.exist("a"));
Console.log(ftp.exist("/test"));
Console.log(ftp.exist("/test/"));
Console.log(ftp.exist("/test//////"));
Console.log(ftp.exist("/test/.."));
Console.log(ftp.exist("/test/."));
Console.log(ftp.exist("/file1"));
Console.log(ftp.exist("/file1/"));
Console.log(ftp.exist("///////////"));
Console.log(ftp.exist("./"));
Console.log(ftp.exist("./file1"));
Console.log(ftp.exist("./2/3/4/.."));
Console.log(ftp.pwd());
}
} }
} }

View File

@ -180,7 +180,7 @@ public enum GlobalHeaders {
for (final Entry<String, List<String>> entry : headers.entrySet()) { for (final Entry<String, List<String>> entry : headers.entrySet()) {
name = entry.getKey(); name = entry.getKey();
for (final String value : entry.getValue()) { for (final String value : entry.getValue()) {
this.header(name, StrUtil.nullToEmpty(value), false); this.header(name, StrUtil.emptyIfNull(value), false);
} }
} }
return this; return this;

View File

@ -174,7 +174,7 @@ public abstract class HttpBase<T> {
} }
for (final Entry<String, String> entry : headers.entrySet()) { for (final Entry<String, String> entry : headers.entrySet()) {
this.header(entry.getKey(), StrUtil.nullToEmpty(entry.getValue()), isOverride); this.header(entry.getKey(), StrUtil.emptyIfNull(entry.getValue()), isOverride);
} }
return (T) this; return (T) this;
} }
@ -207,7 +207,7 @@ public abstract class HttpBase<T> {
for (final Entry<String, List<String>> entry : headers.entrySet()) { for (final Entry<String, List<String>> entry : headers.entrySet()) {
name = entry.getKey(); name = entry.getKey();
for (final String value : entry.getValue()) { for (final String value : entry.getValue()) {
this.header(name, StrUtil.nullToEmpty(value), isOverride); this.header(name, StrUtil.emptyIfNull(value), isOverride);
} }
} }
return (T) this; return (T) this;
@ -227,7 +227,7 @@ public abstract class HttpBase<T> {
} }
for (final Entry<String, String> entry : headers.entrySet()) { for (final Entry<String, String> entry : headers.entrySet()) {
this.header(entry.getKey(), StrUtil.nullToEmpty(entry.getValue()), false); this.header(entry.getKey(), StrUtil.emptyIfNull(entry.getValue()), false);
} }
return (T) this; return (T) this;
} }

View File

@ -213,7 +213,7 @@ public class HttpConnection {
for (final Entry<String, List<String>> entry : headerMap.entrySet()) { for (final Entry<String, List<String>> entry : headerMap.entrySet()) {
name = entry.getKey(); name = entry.getKey();
for (final String value : entry.getValue()) { for (final String value : entry.getValue()) {
this.header(name, StrUtil.nullToEmpty(value), isOverride); this.header(name, StrUtil.emptyIfNull(value), isOverride);
} }
} }
} }

View File

@ -13,7 +13,6 @@ import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.convert.JSONConverterOld;
import cn.hutool.json.serialize.JSONString; import cn.hutool.json.serialize.JSONString;
import java.io.IOException; import java.io.IOException;
@ -207,9 +206,8 @@ public final class InternalJSONUtil {
* @param key * @param key
* @param value * @param value
* @param predicate 属性过滤器{@link Predicate#test(Object)}{@code true}保留 * @param predicate 属性过滤器{@link Predicate#test(Object)}{@code true}保留
* @return JSONObject
*/ */
public static JSONObject propertyPut(final JSONObject jsonObject, final Object key, final Object value, final Predicate<MutableEntry<String, Object>> predicate) { public static void propertyPut(final JSONObject jsonObject, final Object key, final Object value, final Predicate<MutableEntry<String, Object>> predicate) {
final String[] path = StrUtil.splitToArray(Convert.toStr(key), CharUtil.DOT); final String[] path = StrUtil.splitToArray(Convert.toStr(key), CharUtil.DOT);
final int last = path.length - 1; final int last = path.length - 1;
JSONObject target = jsonObject; JSONObject target = jsonObject;
@ -223,7 +221,6 @@ public final class InternalJSONUtil {
target = nextTarget; target = nextTarget;
} }
target.set(path[last], value, predicate); target.set(path[last], value, predicate);
return jsonObject;
} }
/** /**
@ -259,8 +256,7 @@ public final class InternalJSONUtil {
.setIgnoreNullValue(config.isIgnoreNullValue()) .setIgnoreNullValue(config.isIgnoreNullValue())
.setTransientSupport(config.isTransientSupport()) .setTransientSupport(config.isTransientSupport())
// 使用JSON转换器 // 使用JSON转换器
.setConverter((type, value) -> .setConverter(config.getConverter());
JSONConverterOld.convertWithCheck(type, value, null, config.isIgnoreError()));
} }
/** /**
@ -296,11 +292,10 @@ public final class InternalJSONUtil {
* *
* @param str 字符串 * @param str 字符串
* @param writer Writer * @param writer Writer
* @return Writer
* @throws IORuntimeException IO异常 * @throws IORuntimeException IO异常
*/ */
public static Writer quote(final String str, final Writer writer) throws IORuntimeException { public static void quote(final String str, final Writer writer) throws IORuntimeException {
return quote(str, writer, true); quote(str, writer, true);
} }
/** /**

View File

@ -2,7 +2,6 @@ package cn.hutool.json;
import cn.hutool.core.bean.BeanPath; import cn.hutool.core.bean.BeanPath;
import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.lang.mutable.MutableEntry;
import cn.hutool.json.convert.JSONConverterOld;
import java.io.Serializable; import java.io.Serializable;
import java.io.StringWriter; import java.io.StringWriter;
@ -107,7 +106,10 @@ public interface JSON extends Cloneable, Serializable {
* @see BeanPath#get(Object) * @see BeanPath#get(Object)
* @since 4.0.6 * @since 4.0.6
*/ */
<T> T getByPath(String expression, Class<T> resultType); @SuppressWarnings("unchecked")
default <T> T getByPath(final String expression, final Class<T> resultType){
return (T) getConfig().getConverter().convert(resultType, getByPath(expression));
}
/** /**
* 格式化打印JSON缩进为4个空格 * 格式化打印JSON缩进为4个空格
@ -159,17 +161,6 @@ public interface JSON extends Cloneable, Serializable {
*/ */
Writer write(Writer writer, int indentFactor, int indent, final Predicate<MutableEntry<Object, Object>> predicate) throws JSONException; Writer write(Writer writer, int indentFactor, int indent, final Predicate<MutableEntry<Object, Object>> predicate) throws JSONException;
/**
* 转为实体类对象转换异常将被抛出
*
* @param <T> Bean类型
* @param clazz 实体类
* @return 实体类对象
*/
default <T> T toBean(final Class<T> clazz) {
return toBean((Type) clazz);
}
/** /**
* 转为实体类对象 * 转为实体类对象
* *
@ -178,7 +169,8 @@ public interface JSON extends Cloneable, Serializable {
* @return 实体类对象 * @return 实体类对象
* @since 4.3.2 * @since 4.3.2
*/ */
@SuppressWarnings("unchecked")
default <T> T toBean(final Type type) { default <T> T toBean(final Type type) {
return JSONConverterOld.jsonConvert(type, this, getConfig()); return (T) getConfig().getConverter().convert(type, this);
} }
} }

View File

@ -8,7 +8,6 @@ import cn.hutool.core.lang.mutable.MutableEntry;
import cn.hutool.core.lang.mutable.MutableObj; import cn.hutool.core.lang.mutable.MutableObj;
import cn.hutool.core.text.StrJoiner; import cn.hutool.core.text.StrJoiner;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.convert.JSONConverterOld;
import cn.hutool.json.mapper.ArrayMapper; import cn.hutool.json.mapper.ArrayMapper;
import cn.hutool.json.serialize.JSONWriter; import cn.hutool.json.serialize.JSONWriter;
@ -193,11 +192,6 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
return (index < 0 || index >= this.size()) ? defaultValue : this.rawList.get(index); return (index < 0 || index >= this.size()) ? defaultValue : this.rawList.get(index);
} }
@Override
public <T> T getByPath(final String expression, final Class<T> resultType) {
return JSONConverterOld.jsonConvert(resultType, getByPath(expression), getConfig());
}
/** /**
* Append an object value. This increases the array's length by one. <br> * Append an object value. This increases the array's length by one. <br>
* 加入元素数组长度+1等同于 {@link JSONArray#add(Object)} * 加入元素数组长度+1等同于 {@link JSONArray#add(Object)}

View File

@ -1,6 +1,7 @@
package cn.hutool.json; package cn.hutool.json;
import cn.hutool.core.comparator.CompareUtil; import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.convert.Converter;
import java.io.Serializable; import java.io.Serializable;
import java.util.Comparator; import java.util.Comparator;
@ -38,7 +39,6 @@ public class JSONConfig implements Serializable {
* 是否支持transient关键字修饰和@Transient注解如果支持被修饰的字段或方法对应的字段将被忽略 * 是否支持transient关键字修饰和@Transient注解如果支持被修饰的字段或方法对应的字段将被忽略
*/ */
private boolean transientSupport = true; private boolean transientSupport = true;
/** /**
* 是否去除末尾多余0例如如果为true,5.0返回5 * 是否去除末尾多余0例如如果为true,5.0返回5
*/ */
@ -47,6 +47,10 @@ public class JSONConfig implements Serializable {
* 是否检查重复key * 是否检查重复key
*/ */
private boolean checkDuplicate; private boolean checkDuplicate;
/**
* 自定义的类型转换器用于在序列化反序列化操作中实现对象类型转换
*/
private Converter converter;
/** /**
* 创建默认的配置项 * 创建默认的配置项
@ -237,4 +241,20 @@ public class JSONConfig implements Serializable {
this.checkDuplicate = checkDuplicate; this.checkDuplicate = checkDuplicate;
return this; return this;
} }
/**
* 获取自定义的类型转换器用于在序列化反序列化操作中实现对象类型转换
* @return 转换器
*/
public Converter getConverter() {
return converter;
}
/**
* 设置自定义的类型转换器用于在序列化反序列化操作中实现对象类型转换
* @param converter 转换器
*/
public void setConverter(final Converter converter) {
this.converter = converter;
}
} }

View File

@ -3,7 +3,6 @@ package cn.hutool.json;
import cn.hutool.core.convert.ConvertException; import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.lang.getter.OptNullBasicTypeFromObjectGetter; import cn.hutool.core.lang.getter.OptNullBasicTypeFromObjectGetter;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.convert.JSONConverterOld;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Date; import java.util.Date;
@ -163,12 +162,13 @@ public interface JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K> {
* @throws ConvertException 转换异常 * @throws ConvertException 转换异常
* @since 3.0.8 * @since 3.0.8
*/ */
@SuppressWarnings("unchecked")
default <T> T get(final K key, final Class<T> type) throws ConvertException { default <T> T get(final K key, final Class<T> type) throws ConvertException {
final Object value = this.getObj(key); final Object value = this.getObj(key);
if (ObjUtil.isNull(value)) { if (ObjUtil.isNull(value)) {
return null; return null;
} }
return JSONConverterOld.jsonConvert(type, value, getConfig()); return (T) getConfig().getConverter().convert(type, value);
} }
} }

View File

@ -5,7 +5,6 @@ import cn.hutool.core.lang.mutable.MutableEntry;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.MapWrapper; import cn.hutool.core.map.MapWrapper;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.convert.JSONConverterOld;
import cn.hutool.json.mapper.ObjectMapper; import cn.hutool.json.mapper.ObjectMapper;
import cn.hutool.json.serialize.JSONWriter; import cn.hutool.json.serialize.JSONWriter;
@ -183,11 +182,6 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
return this.getOrDefault(key, defaultValue); return this.getOrDefault(key, defaultValue);
} }
@Override
public <T> T getByPath(final String expression, final Class<T> resultType) {
return JSONConverterOld.jsonConvert(resultType, getByPath(expression), getConfig());
}
/** /**
* PUT 键值对到JSONObject中在忽略null模式下如果值为{@code null}将此键移除 * PUT 键值对到JSONObject中在忽略null模式下如果值为{@code null}将此键移除
* *

View File

@ -1,7 +1,6 @@
package cn.hutool.json; package cn.hutool.json;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.convert.JSONConverterOld;
import cn.hutool.json.serialize.JSONDeserializer; import cn.hutool.json.serialize.JSONDeserializer;
import cn.hutool.json.serialize.JSONString; import cn.hutool.json.serialize.JSONString;
@ -29,8 +28,8 @@ public class JSONSupport implements JSONString, JSONDeserializer<Object> {
*/ */
@Override @Override
public Object deserialize(final JSON json) { public Object deserialize(final JSON json) {
final JSONSupport support = JSONConverterOld.jsonToBean(getClass(), json, false); // TODO 经过两次转换效率差待优化
BeanUtil.copyProperties(support, this); BeanUtil.copyProperties(json.toBean(getClass()), this);
return this; return this;
} }

View File

@ -0,0 +1,16 @@
package cn.hutool.json.convert;
import cn.hutool.core.convert.CompositeConverter;
import cn.hutool.core.convert.ConvertException;
import java.lang.reflect.Type;
public class JSONCompositeConverter extends CompositeConverter {
public static final JSONCompositeConverter INSTANCE = new JSONCompositeConverter();
@Override
public <T> T convert(final Type type, final Object value, final T defaultValue, final boolean isCustomFirst) throws ConvertException {
return super.convert(type, value, defaultValue, isCustomFirst);
}
}

View File

@ -0,0 +1,53 @@
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.json.serialize.JSONDeserializer;
import cn.hutool.json.serialize.JSONObjectSerializer;
import lombok.Data;
import org.junit.Assert;
import org.junit.Test;
public class Issue2555Test {
@Test
public void serAndDeserTest(){
JSONUtil.putSerializer(MyType.class, new MySerializer());
JSONUtil.putDeserializer(MyType.class, new MyDeserializer());
final SimpleObj simpleObj = new SimpleObj();
final MyType child = new MyType();
child.setAddress("addrValue1");
simpleObj.setMyType(child);
final String json = JSONUtil.toJsonStr(simpleObj);
Assert.assertEquals("{\"myType\":{\"addr\":\"addrValue1\"}}", json);
//MyDeserializer不会被调用
final SimpleObj simpleObj2 = JSONUtil.toBean(json, SimpleObj.class);
Assert.assertEquals("addrValue1", simpleObj2.getMyType().getAddress());
}
@Data
public static class MyType {
private String address;
}
@Data
public static class SimpleObj {
private MyType myType;
}
public static class MySerializer implements JSONObjectSerializer<MyType> {
@Override
public void serialize(JSONObject json, MyType bean) {
json.set("addr", bean.getAddress());
}
}
public static class MyDeserializer implements JSONDeserializer<MyType> {
@Override
public MyType deserialize(JSON json) {
final MyType myType = new MyType();
myType.setAddress(((JSONObject)json).getStr("addr"));
return myType;
}
}
}

View File

@ -3,12 +3,15 @@ package cn.hutool.json.jwt;
import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.json.jwt.signers.AlgorithmUtil;
import cn.hutool.json.jwt.signers.JWTSigner;
import cn.hutool.json.jwt.signers.JWTSignerUtil; import cn.hutool.json.jwt.signers.JWTSignerUtil;
import lombok.Data; import lombok.Data;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import java.util.Arrays; import java.util.Arrays;
import java.util.Base64;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -159,4 +162,14 @@ public class JWTTest {
final Date date = JWT.of(token).getPayload().getClaimsJson().getDate(JWTPayload.ISSUED_AT); final Date date = JWT.of(token).getPayload().getClaimsJson().getDate(JWTPayload.ISSUED_AT);
Assert.assertEquals("2022-02-02", DateUtil.format(date, DatePattern.NORM_DATE_PATTERN)); Assert.assertEquals("2022-02-02", DateUtil.format(date, DatePattern.NORM_DATE_PATTERN));
} }
@Test
public void issue2581Test(){
final Map<String, Object> map = new HashMap<>();
map.put("test2", 22222222222222L);
final JWTSigner jwtSigner = JWTSignerUtil.createSigner(AlgorithmUtil.getAlgorithm("HS256"), Base64.getDecoder().decode("abcdefghijklmn"));
final String sign = JWT.of().addPayloads(map).sign(jwtSigner);
final Object test2 = JWT.of(sign).getPayload().getClaim("test2");
Assert.assertEquals(Long.class, test2.getClass());
}
} }

View File

@ -63,8 +63,8 @@ public class StyleSet implements Serializable {
// 默认数字格式 // 默认数字格式
cellStyleForNumber = StyleUtil.cloneCellStyle(workbook, this.cellStyle); cellStyleForNumber = StyleUtil.cloneCellStyle(workbook, this.cellStyle);
// 2表示0.00 // 0表示General
cellStyleForNumber.setDataFormat((short) 2); cellStyleForNumber.setDataFormat((short) 0);
// 默认日期格式 // 默认日期格式
this.cellStyleForDate = StyleUtil.cloneCellStyle(workbook, this.cellStyle); this.cellStyleForDate = StyleUtil.cloneCellStyle(workbook, this.cellStyle);

View File

@ -449,7 +449,7 @@ public class CellUtil {
} }
final Comment comment = drawing.createCellComment(anchor); final Comment comment = drawing.createCellComment(anchor);
comment.setString(factory.createRichTextString(commentText)); comment.setString(factory.createRichTextString(commentText));
comment.setAuthor(StrUtil.nullToEmpty(commentAuthor)); comment.setAuthor(StrUtil.emptyIfNull(commentAuthor));
cell.setCellComment(comment); cell.setCellComment(comment);
} }

View File

@ -820,6 +820,19 @@ public class ExcelWriteTest {
writer.close(); writer.close();
} }
@Test
//@Ignore
public void writeDoubleTest(){
// https://gitee.com/dromara/hutool/issues/I5PI5C
final String path = "d:/test/doubleTest.xlsx";
FileUtil.del(path);
final ExcelWriter writer = ExcelUtil.getWriter(path);
writer.disableDefaultStyle();
writer.writeRow(ListUtil.view(0.427d));
writer.close();
}
@Test @Test
@Ignore @Ignore
public void issueI466ZZTest(){ public void issueI466ZZTest(){

View File

@ -4,11 +4,14 @@ import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Console; import cn.hutool.core.lang.Console;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import java.awt.Font; import java.awt.Font;
import java.io.File; import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
@ -94,4 +97,28 @@ public class WordWriterTest {
word07Writer.addTable(list); word07Writer.addTable(list);
word07Writer.close(); word07Writer.close();
} }
@Test
@Ignore
public void writeBeanAsTableTest(){
final List<Vo> of = ListUtil.of(
new Vo("测试1", new BigDecimal(12), new BigDecimal(2)),
new Vo("测试2", new BigDecimal(13), new BigDecimal(2)),
new Vo("测试3", new BigDecimal(15), new BigDecimal(3)),
new Vo("测试4", new BigDecimal(112), new BigDecimal(5))
);
WordUtil.getWriter()
.addTable(of)
.flush(FileUtil.file("d:/test/beanValueTest.docx"))
.close();
}
@Data
@AllArgsConstructor
private static class Vo{
private String name;
private BigDecimal amount;
private BigDecimal onYear;
}
} }

View File

@ -38,7 +38,7 @@ public class GroupedMap extends LinkedHashMap<String, LinkedHashMap<String, Stri
public String get(final String group, final String key) { public String get(final String group, final String key) {
readLock.lock(); readLock.lock();
try { try {
final LinkedHashMap<String, String> map = this.get(StrUtil.nullToEmpty(group)); final LinkedHashMap<String, String> map = this.get(StrUtil.emptyIfNull(group));
if (MapUtil.isNotEmpty(map)) { if (MapUtil.isNotEmpty(map)) {
return map.get(key); return map.get(key);
} }
@ -88,7 +88,7 @@ public class GroupedMap extends LinkedHashMap<String, LinkedHashMap<String, Stri
* @return 此key之前存在的值如果没有返回null * @return 此key之前存在的值如果没有返回null
*/ */
public String put(String group, final String key, final String value) { public String put(String group, final String key, final String value) {
group = StrUtil.nullToEmpty(group).trim(); group = StrUtil.emptyIfNull(group).trim();
writeLock.lock(); writeLock.lock();
try { try {
final LinkedHashMap<String, String> valueMap = this.computeIfAbsent(group, k -> new LinkedHashMap<>()); final LinkedHashMap<String, String> valueMap = this.computeIfAbsent(group, k -> new LinkedHashMap<>());
@ -121,7 +121,7 @@ public class GroupedMap extends LinkedHashMap<String, LinkedHashMap<String, Stri
* @return 被删除的值如果值不存在返回null * @return 被删除的值如果值不存在返回null
*/ */
public String remove(String group, final String key) { public String remove(String group, final String key) {
group = StrUtil.nullToEmpty(group).trim(); group = StrUtil.emptyIfNull(group).trim();
writeLock.lock(); writeLock.lock();
try { try {
final LinkedHashMap<String, String> valueMap = this.get(group); final LinkedHashMap<String, String> valueMap = this.get(group);
@ -141,7 +141,7 @@ public class GroupedMap extends LinkedHashMap<String, LinkedHashMap<String, Stri
* @return 是否为空 * @return 是否为空
*/ */
public boolean isEmpty(String group) { public boolean isEmpty(String group) {
group = StrUtil.nullToEmpty(group).trim(); group = StrUtil.emptyIfNull(group).trim();
readLock.lock(); readLock.lock();
try { try {
final LinkedHashMap<String, String> valueMap = this.get(group); final LinkedHashMap<String, String> valueMap = this.get(group);
@ -172,7 +172,7 @@ public class GroupedMap extends LinkedHashMap<String, LinkedHashMap<String, Stri
* @return 是否包含key * @return 是否包含key
*/ */
public boolean containsKey(String group, final String key) { public boolean containsKey(String group, final String key) {
group = StrUtil.nullToEmpty(group).trim(); group = StrUtil.emptyIfNull(group).trim();
readLock.lock(); readLock.lock();
try { try {
final LinkedHashMap<String, String> valueMap = this.get(group); final LinkedHashMap<String, String> valueMap = this.get(group);
@ -193,7 +193,7 @@ public class GroupedMap extends LinkedHashMap<String, LinkedHashMap<String, Stri
* @return 是否包含值 * @return 是否包含值
*/ */
public boolean containsValue(String group, final String value) { public boolean containsValue(String group, final String value) {
group = StrUtil.nullToEmpty(group).trim(); group = StrUtil.emptyIfNull(group).trim();
readLock.lock(); readLock.lock();
try { try {
final LinkedHashMap<String, String> valueMap = this.get(group); final LinkedHashMap<String, String> valueMap = this.get(group);
@ -213,7 +213,7 @@ public class GroupedMap extends LinkedHashMap<String, LinkedHashMap<String, Stri
* @return this * @return this
*/ */
public GroupedMap clear(String group) { public GroupedMap clear(String group) {
group = StrUtil.nullToEmpty(group).trim(); group = StrUtil.emptyIfNull(group).trim();
writeLock.lock(); writeLock.lock();
try { try {
final LinkedHashMap<String, String> valueMap = this.get(group); final LinkedHashMap<String, String> valueMap = this.get(group);
@ -243,7 +243,7 @@ public class GroupedMap extends LinkedHashMap<String, LinkedHashMap<String, Stri
* @return 键Set * @return 键Set
*/ */
public Set<String> keySet(String group) { public Set<String> keySet(String group) {
group = StrUtil.nullToEmpty(group).trim(); group = StrUtil.emptyIfNull(group).trim();
readLock.lock(); readLock.lock();
try { try {
final LinkedHashMap<String, String> valueMap = this.get(group); final LinkedHashMap<String, String> valueMap = this.get(group);
@ -263,7 +263,7 @@ public class GroupedMap extends LinkedHashMap<String, LinkedHashMap<String, Stri
* @return * @return
*/ */
public Collection<String> values(String group) { public Collection<String> values(String group) {
group = StrUtil.nullToEmpty(group).trim(); group = StrUtil.emptyIfNull(group).trim();
readLock.lock(); readLock.lock();
try { try {
final LinkedHashMap<String, String> valueMap = this.get(group); final LinkedHashMap<String, String> valueMap = this.get(group);
@ -293,7 +293,7 @@ public class GroupedMap extends LinkedHashMap<String, LinkedHashMap<String, Stri
* @return 键值对 * @return 键值对
*/ */
public Set<Entry<String, String>> entrySet(String group) { public Set<Entry<String, String>> entrySet(String group) {
group = StrUtil.nullToEmpty(group).trim(); group = StrUtil.emptyIfNull(group).trim();
readLock.lock(); readLock.lock();
try { try {
final LinkedHashMap<String, String> valueMap = this.get(group); final LinkedHashMap<String, String> valueMap = this.get(group);

View File

@ -572,7 +572,7 @@ public final class Props extends Properties implements BasicTypeGetter<String>,
* @since 4.6.3 * @since 4.6.3
*/ */
public <T> T fillBean(final T bean, String prefix) { public <T> T fillBean(final T bean, String prefix) {
prefix = StrUtil.nullToEmpty(StrUtil.addSuffixIfNot(prefix, StrUtil.DOT)); prefix = StrUtil.emptyIfNull(StrUtil.addSuffixIfNot(prefix, StrUtil.DOT));
String key; String key;
for (final java.util.Map.Entry<Object, Object> entry : this.entrySet()) { for (final java.util.Map.Entry<Object, Object> entry : this.entrySet()) {

View File

@ -137,7 +137,7 @@ public class Profile implements Serializable {
*/ */
private String fixNameForProfile(final String name) { private String fixNameForProfile(final String name) {
Assert.notBlank(name, "Setting name must be not blank !"); Assert.notBlank(name, "Setting name must be not blank !");
final String actralProfile = StrUtil.nullToEmpty(this.profile); final String actralProfile = StrUtil.emptyIfNull(this.profile);
if (false == name.contains(StrUtil.DOT)) { if (false == name.contains(StrUtil.DOT)) {
return StrUtil.format("{}/{}.setting", actralProfile, name); return StrUtil.format("{}/{}.setting", actralProfile, name);
} }

View File

@ -450,12 +450,13 @@ public class ImgUtil {
* *
* @param srcImageFile 源图像文件 * @param srcImageFile 源图像文件
* @param destDir 切片目标文件夹 * @param destDir 切片目标文件夹
* @param formatName 格式名称即图片格式后缀
* @param rows 目标切片行数默认2必须是范围 [1, 20] 之内 * @param rows 目标切片行数默认2必须是范围 [1, 20] 之内
* @param cols 目标切片列数默认2必须是范围 [1, 20] 之内 * @param cols 目标切片列数默认2必须是范围 [1, 20] 之内
*/ */
public static void sliceByRowsAndCols(final File srcImageFile, final File destDir, final int rows, final int cols) { public static void sliceByRowsAndCols(final File srcImageFile, final File destDir, final String formatName, final int rows, final int cols) {
try { try {
sliceByRowsAndCols(ImageIO.read(srcImageFile), destDir, rows, cols); sliceByRowsAndCols(ImageIO.read(srcImageFile), destDir, formatName, rows, cols);
} catch (final IOException e) { } catch (final IOException e) {
throw new IORuntimeException(e); throw new IORuntimeException(e);
} }
@ -466,10 +467,11 @@ public class ImgUtil {
* *
* @param srcImage 源图像如果非{@link BufferedImage}则默认使用RGB模式 * @param srcImage 源图像如果非{@link BufferedImage}则默认使用RGB模式
* @param destDir 切片目标文件夹 * @param destDir 切片目标文件夹
* @param formatName 格式名称即图片格式后缀
* @param rows 目标切片行数默认2必须是范围 [1, 20] 之内 * @param rows 目标切片行数默认2必须是范围 [1, 20] 之内
* @param cols 目标切片列数默认2必须是范围 [1, 20] 之内 * @param cols 目标切片列数默认2必须是范围 [1, 20] 之内
*/ */
public static void sliceByRowsAndCols(final Image srcImage, final File destDir, int rows, int cols) { public static void sliceByRowsAndCols(final Image srcImage, final File destDir, final String formatName, int rows, int cols) {
if (false == destDir.exists()) { if (false == destDir.exists()) {
FileUtil.mkdir(destDir); FileUtil.mkdir(destDir);
} else if (false == destDir.isDirectory()) { } else if (false == destDir.isDirectory()) {
@ -497,7 +499,7 @@ public class ImgUtil {
for (int j = 0; j < cols; j++) { for (int j = 0; j < cols; j++) {
tag = cut(bi, new Rectangle(j * destWidth, i * destHeight, destWidth, destHeight)); tag = cut(bi, new Rectangle(j * destWidth, i * destHeight, destWidth, destHeight));
// 输出为文件 // 输出为文件
ImageIO.write(toRenderedImage(tag), IMAGE_TYPE_JPEG, new File(destDir, "_r" + i + "_c" + j + ".jpg")); ImageIO.write(toRenderedImage(tag), formatName, new File(destDir, "_r" + i + "_c" + j + ".jpg"));
} }
} }
} catch (final IOException e) { } catch (final IOException e) {
@ -2072,7 +2074,7 @@ public class ImgUtil {
r = (pixel & 0xff0000) >> 16; r = (pixel & 0xff0000) >> 16;
g = (pixel & 0xff00) >> 8; g = (pixel & 0xff00) >> 8;
b = (pixel & 0xff); b = (pixel & 0xff);
if(matchFilters(r, g, b, rgbFilters)){ if (matchFilters(r, g, b, rgbFilters)) {
continue; continue;
} }
countMap.merge(r + "-" + g + "-" + b, 1L, Long::sum); countMap.merge(r + "-" + g + "-" + b, 1L, Long::sum);
@ -2100,13 +2102,14 @@ public class ImgUtil {
/** /**
* 给定RGB是否匹配过滤器中任何一个RGB颜色 * 给定RGB是否匹配过滤器中任何一个RGB颜色
*
* @param r R * @param r R
* @param g G * @param g G
* @param b B * @param b B
* @param rgbFilters 颜色过滤器 * @param rgbFilters 颜色过滤器
* @return 是否匹配 * @return 是否匹配
*/ */
private static boolean matchFilters(final int r, final int g, final int b, final int[]... rgbFilters){ private static boolean matchFilters(final int r, final int g, final int b, final int[]... rgbFilters) {
if (rgbFilters != null && rgbFilters.length > 0) { if (rgbFilters != null && rgbFilters.length > 0) {
for (final int[] rgbFilter : rgbFilters) { for (final int[] rgbFilter : rgbFilters) {
if (r == rgbFilter[0] && g == rgbFilter[1] && b == rgbFilter[2]) { if (r == rgbFilter[0] && g == rgbFilter[1] && b == rgbFilter[2]) {

View File

@ -89,7 +89,7 @@ public class ImgUtilTest {
@Test @Test
@Ignore @Ignore
public void sliceByRowsAndColsTest() { public void sliceByRowsAndColsTest() {
ImgUtil.sliceByRowsAndCols(FileUtil.file("d:/test/logo.jpg"), FileUtil.file("d:/test/dest"), 1, 5); ImgUtil.sliceByRowsAndCols(FileUtil.file("d:/test/logo.jpg"), FileUtil.file("d:/test/dest"), ImgUtil.IMAGE_TYPE_JPEG, 1, 5);
} }
@Test @Test