diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/iter/ArrayIter.java b/hutool-core/src/main/java/cn/hutool/core/collection/iter/ArrayIter.java index d11bce6c0..8f2e31420 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/iter/ArrayIter.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/iter/ArrayIter.java @@ -3,6 +3,7 @@ package cn.hutool.core.collection.iter; import java.io.Serializable; import java.lang.reflect.Array; import java.util.NoSuchElementException; +import java.util.Objects; /** * 数组Iterator对象 @@ -75,7 +76,7 @@ public class ArrayIter implements IterableIter, ResettableIter, Seriali * @throws NullPointerException array对象为null */ 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) { this.endIndex = endIndex; } diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/iter/CopiedIter.java b/hutool-core/src/main/java/cn/hutool/core/collection/iter/CopiedIter.java index 389a2fff3..1720d26d5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/iter/CopiedIter.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/iter/CopiedIter.java @@ -1,8 +1,10 @@ package cn.hutool.core.collection.iter; import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.ObjUtil; import java.io.Serializable; +import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -39,12 +41,12 @@ public class CopiedIter implements IterableIter, Serializable { } /** - * 构造 + * 构造,当{@code iterator}为空时,默认复制一个空迭代器 * * @param iterator 被复制的Iterator */ public CopiedIter(final Iterator iterator) { - final List eleList = ListUtil.of(iterator); + final List eleList = ListUtil.of(ObjUtil.defaultIfNull(iterator, Collections.emptyIterator())); this.listIterator = eleList.iterator(); } diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/iter/EnumerationIter.java b/hutool-core/src/main/java/cn/hutool/core/collection/iter/EnumerationIter.java index 883ac31fa..174450a0e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/iter/EnumerationIter.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/iter/EnumerationIter.java @@ -1,7 +1,5 @@ package cn.hutool.core.collection.iter; -import cn.hutool.core.collection.iter.IterableIter; - import java.io.Serializable; import java.util.Enumeration; import java.util.Iterator; diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/iter/FilterIter.java b/hutool-core/src/main/java/cn/hutool/core/collection/iter/FilterIter.java index ca7e81c12..29776d13f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/iter/FilterIter.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/iter/FilterIter.java @@ -32,6 +32,7 @@ public class FilterIter implements Iterator { * * @param iterator 被包装的{@link Iterator} * @param filter 过滤函数,{@code null}表示不过滤 + * @throws NullPointerException {@code iterator}为{@code null}时抛出 */ public FilterIter(final Iterator iterator, final Predicate filter) { this.iterator = Assert.notNull(iterator); diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/iter/IterChain.java b/hutool-core/src/main/java/cn/hutool/core/collection/iter/IterChain.java index b281ffd9b..7a8145c4c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/iter/IterChain.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/iter/IterChain.java @@ -1,11 +1,9 @@ package cn.hutool.core.collection.iter; import cn.hutool.core.lang.Chain; +import cn.hutool.core.util.ArrayUtil; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; +import java.util.*; /** * 组合{@link Iterator},将多个{@link Iterator}组合在一起,便于集中遍历。
@@ -28,16 +26,27 @@ public class IterChain implements Iterator, Chain, IterChain... iterators) { - for (final Iterator iterator : iterators) { - addChain(iterator); + if (ArrayUtil.isNotEmpty(iterators)) { + for (final Iterator iterator : iterators) { + addChain(iterator); + } } } + /** + * 添加迭代器 + * + * @param iterator 迭代器 + * @return 当前实例 + * @throws IllegalArgumentException 当迭代器被重复添加,或待添加的迭代器为{@code null}时抛出 + */ @Override public IterChain addChain(final Iterator iterator) { + Objects.requireNonNull(iterator); if (allIterators.contains(iterator)) { throw new IllegalArgumentException("Duplicate iterator"); } diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/iter/IterUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/iter/IterUtil.java index ce70b40fe..16d91c494 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/iter/IterUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/iter/IterUtil.java @@ -11,16 +11,7 @@ import cn.hutool.core.util.ObjUtil; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import java.util.ArrayList; -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.*; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -192,32 +183,35 @@ public class IterUtil { /** * 获取指定Bean列表中某个字段,生成新的列表 * + * @param 返回元素类型 * @param 对象类型 * @param iterable 对象列表 * @param fieldName 字段名(会通过反射获取其值) * @return 某个字段值与对象对应Map * @since 4.6.2 */ - public static List fieldValueList(final Iterable iterable, final String fieldName) { + public static List fieldValueList(final Iterable iterable, final String fieldName) { return fieldValueList(getIter(iterable), fieldName); } /** * 获取指定Bean列表中某个字段,生成新的列表 * + * @param 返回元素类型 * @param 对象类型 * @param iter 对象列表 * @param fieldName 字段名(会通过反射获取其值) * @return 某个字段值与对象对应Map * @since 4.0.10 */ - public static List fieldValueList(final Iterator iter, final String fieldName) { - final List result = new ArrayList<>(); + @SuppressWarnings("unchecked") + public static List fieldValueList(final Iterator iter, final String fieldName) { + final List result = new ArrayList<>(); if (null != iter) { V value; while (iter.hasNext()) { value = iter.next(); - result.add(FieldUtil.getFieldValue(value, fieldName)); + result.add((R)FieldUtil.getFieldValue(value, fieldName)); } } return result; @@ -378,7 +372,7 @@ public class IterUtil { } /** - * 将列表转成值为List的HashMap + * 将列表转成值为List的Map集合 * * @param resultMap 结果Map,可自定义结果Map类型 * @param iterable 值列表 @@ -702,38 +696,40 @@ public class IterUtil { } /** - * 判断两个{@link Iterable} 是否元素和顺序相同,返回{@code true}的条件是: + *

判断两个{@link Iterable}中的元素与其顺序是否相同
+ * 当满足下列情况时返回{@code true}: *

    - *
  • 两个{@link Iterable}必须长度相同
  • - *
  • 两个{@link Iterable}元素相同index的对象必须equals,满足{@link Objects#equals(Object, Object)}
  • + *
  • 两个{@link Iterable}都为{@code null};
  • + *
  • 两个{@link Iterable}满足{@code iterable1 == iterable2};
  • + *
  • 两个{@link Iterable}所有具有相同下标的元素皆满足{@link Objects#equals(Object, Object)};
  • *
* 此方法来自Apache-Commons-Collections4。 * - * @param list1 列表1 - * @param list2 列表2 + * @param iterable1 列表1 + * @param iterable2 列表2 * @return 是否相同 * @since 5.6.0 */ - public static boolean isEqualList(final Iterable list1, final Iterable list2) { - if (list1 == list2) { + public static boolean isEqualList(final Iterable iterable1, final Iterable iterable2) { + if (iterable1 == iterable2) { return true; } - - final Iterator it1 = list1.iterator(); - final Iterator it2 = list2.iterator(); + if (iterable1 == null || iterable2 == null) { + return false; + } + final Iterator iter1 = iterable1.iterator(); + final Iterator iter2 = iterable2.iterator(); Object obj1; Object obj2; - while (it1.hasNext() && it2.hasNext()) { - obj1 = it1.next(); - obj2 = it2.next(); - + while (iter1.hasNext() && iter2.hasNext()) { + obj1 = iter1.next(); + obj2 = iter2.next(); if (false == Objects.equals(obj1, obj2)) { return false; } } - // 当两个Iterable长度不一致时返回false - return false == (it1.hasNext() || it2.hasNext()); + return false == (iter1.hasNext() || iter2.hasNext()); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/iter/IterableIter.java b/hutool-core/src/main/java/cn/hutool/core/collection/iter/IterableIter.java index d09f337a1..379e8741e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/iter/IterableIter.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/iter/IterableIter.java @@ -15,4 +15,5 @@ public interface IterableIter extends Iterable, Iterator { default Iterator iterator() { return this; } + } diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/iter/IteratorEnumeration.java b/hutool-core/src/main/java/cn/hutool/core/collection/iter/IteratorEnumeration.java index 5ccd3b2e9..2511145d9 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/iter/IteratorEnumeration.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/iter/IteratorEnumeration.java @@ -16,6 +16,8 @@ public class IteratorEnumeration implements Enumeration, Serializable{ private final Iterator iterator; + + /** * 构造 * @param iterator {@link Iterator}对象 diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/iter/PartitionIter.java b/hutool-core/src/main/java/cn/hutool/core/collection/iter/PartitionIter.java index 69d049104..8ca37b3b0 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/iter/PartitionIter.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/iter/PartitionIter.java @@ -1,11 +1,12 @@ 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.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Objects; /** * 分批迭代工具,可以分批处理数据 @@ -36,9 +37,11 @@ public class PartitionIter implements IterableIter>, Serializable { * * @param iterator 迭代器 * @param partitionSize 每批大小,最后一批不满一批算一批 + * @throws IllegalArgumentException 当{@code partitionSize}小于等于0,或{@code iterator}为{@code null}时抛出 */ public PartitionIter(final Iterator 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; } diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/partition/AvgPartition.java b/hutool-core/src/main/java/cn/hutool/core/collection/partition/AvgPartition.java index ec6bf0de3..8998e6e94 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/partition/AvgPartition.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/partition/AvgPartition.java @@ -1,6 +1,5 @@ package cn.hutool.core.collection.partition; -import cn.hutool.core.collection.partition.Partition; import cn.hutool.core.lang.Assert; import java.util.List; diff --git a/hutool-core/src/main/java/cn/hutool/core/compress/ZipWriter.java b/hutool-core/src/main/java/cn/hutool/core/compress/ZipWriter.java index 9b7851d38..3bb70e92d 100755 --- a/hutool-core/src/main/java/cn/hutool/core/compress/ZipWriter.java +++ b/hutool-core/src/main/java/cn/hutool/core/compress/ZipWriter.java @@ -164,7 +164,7 @@ public class ZipWriter implements Closeable { * @throws IORuntimeException IO异常 */ public ZipWriter add(String path, final InputStream in) throws IORuntimeException { - path = StrUtil.nullToEmpty(path); + path = StrUtil.emptyIfNull(path); if (null == in) { // 空目录需要检查路径规范性,目录以"/"结尾 path = StrUtil.addSuffixIfNot(path, StrUtil.SLASH); diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java b/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java index 9178b4a34..25bfeae79 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java @@ -783,11 +783,7 @@ public class DateTime extends Date { * @since 3.0.8 */ public boolean isIn(final Date beginDate, final Date endDate) { - final long beginMills = beginDate.getTime(); - final long endMills = endDate.getTime(); - final long thisMills = this.getTime(); - - return thisMills >= Math.min(beginMills, endMills) && thisMills <= Math.max(beginMills, endMills); + return DateUtil.isIn(this, beginDate, endDate); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java index 3ad82fea7..917fc4a40 100755 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java @@ -1381,11 +1381,49 @@ public class DateUtil extends CalendarUtil { * @since 3.0.8 */ public static boolean isIn(final Date date, final Date beginDate, final Date endDate) { - if (date instanceof DateTime) { - return ((DateTime) date).isIn(beginDate, endDate); - } else { - return new DateTime(date).isIn(beginDate, endDate); + return isIn(date, beginDate, endDate, true, true); + } + + /** + * 当前日期是否在日期指定范围内
+ * 起始日期和结束日期可以互换
+ * 通过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; } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/date/TemporalAccessorUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/TemporalAccessorUtil.java index 2471f1d7d..c737af574 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/TemporalAccessorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/TemporalAccessorUtil.java @@ -181,11 +181,49 @@ public class TemporalAccessorUtil extends TemporalUtil{ * @param endDate 结束日期(包含) * @return 是否在范围内 */ - public static boolean isIn(TemporalAccessor date, TemporalAccessor beginDate, TemporalAccessor endDate){ - final long thisMills = TemporalAccessorUtil.toEpochMilli(date); - final long beginMills = TemporalAccessorUtil.toEpochMilli(beginDate); - final long endMills = TemporalAccessorUtil.toEpochMilli(endDate); + public static boolean isIn(final TemporalAccessor date, final TemporalAccessor beginDate, final TemporalAccessor endDate){ + return isIn(date, beginDate, endDate, true, true); + } - return thisMills >= Math.min(beginMills, endMills) && thisMills <= Math.max(beginMills, endMills); + /** + * 当前日期是否在日期指定范围内
+ * 起始日期和结束日期可以互换
+ * 通过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; } } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java index 34fbca434..124f35f0e 100755 --- a/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java @@ -190,7 +190,7 @@ public class ResourceUtil { * @return {@link URL} */ 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); } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/ClassScanner.java b/hutool-core/src/main/java/cn/hutool/core/lang/ClassScanner.java index 89d8973fa..64085972a 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/ClassScanner.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/ClassScanner.java @@ -209,7 +209,7 @@ public class ClassScanner implements Serializable { * @param charset 编码 */ public ClassScanner(String packageName, final Predicate> classPredicate, final Charset charset) { - packageName = StrUtil.nullToEmpty(packageName); + packageName = StrUtil.emptyIfNull(packageName); this.packageName = packageName; this.packageNameWithDot = StrUtil.addSuffixIfNot(packageName, StrUtil.DOT); this.packageDirName = packageName.replace(CharUtil.DOT, File.separatorChar); diff --git a/hutool-core/src/main/java/cn/hutool/core/map/MapGetUtil.java b/hutool-core/src/main/java/cn/hutool/core/map/MapGetUtil.java new file mode 100755 index 000000000..d28ca5a63 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/map/MapGetUtil.java @@ -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 目标值类型 + * @param map Map + * @param key 键 + * @param type 值类型 + * @return 值 + * @since 4.0.6 + */ + public static T get(final Map map, final Object key, final Class type) { + return get(map, key, type, null); + } + + /** + * 获取Map指定key的值,并转换为指定类型 + * + * @param 目标值类型 + * @param map Map + * @param key 键 + * @param type 值类型 + * @param defaultValue 默认值 + * @return 值 + * @since 5.3.11 + */ + public static T get(final Map map, final Object key, final Class type, final T defaultValue) { + return null == map ? defaultValue : Convert.convert(type, map.get(key), defaultValue); + } + + /** + * 获取Map指定key的值,并转换为指定类型,此方法在转换失败后不抛异常,返回null。 + * + * @param 目标值类型 + * @param map Map + * @param key 键 + * @param type 值类型 + * @param defaultValue 默认值 + * @return 值 + * @since 5.5.3 + */ + public static T getQuietly(final Map map, final Object key, final Class type, final T defaultValue) { + return null == map ? defaultValue : Convert.convertQuietly(type, map.get(key), defaultValue); + } + + /** + * 获取Map指定key的值,并转换为指定类型 + * + * @param 目标值类型 + * @param map Map + * @param key 键 + * @param type 值类型 + * @return 值 + * @since 4.5.12 + */ + public static T get(final Map map, final Object key, final TypeReference type) { + return get(map, key, type, null); + } + + /** + * 获取Map指定key的值,并转换为指定类型 + * + * @param 目标值类型 + * @param map Map + * @param key 键 + * @param type 值类型 + * @param defaultValue 默认值 + * @return 值 + * @since 5.3.11 + */ + public static T get(final Map map, final Object key, final TypeReference type, final T defaultValue) { + return null == map ? defaultValue : Convert.convert(type, map.get(key), defaultValue); + } + + /** + * 获取Map指定key的值,并转换为指定类型,转换失败后返回null,不抛异常 + * + * @param 目标值类型 + * @param map Map + * @param key 键 + * @param type 值类型 + * @param defaultValue 默认值 + * @return 值 + * @since 5.5.3 + */ + public static T getQuietly(final Map map, final Object key, final TypeReference type, final T defaultValue) { + return null == map ? defaultValue : Convert.convertQuietly(type, map.get(key), defaultValue); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java b/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java index b0582b2a6..18e643b76 100755 --- a/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java @@ -7,7 +7,6 @@ import cn.hutool.core.collection.iter.IterUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.reflect.ConstructorUtil; -import cn.hutool.core.reflect.TypeReference; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; @@ -16,7 +15,6 @@ import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.Date; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Iterator; @@ -25,7 +23,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NavigableMap; -import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; @@ -41,7 +38,7 @@ import java.util.stream.Collectors; * @author Looly * @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)) { return new HashMap<>(); } else { - try{ + try { return (Map) ConstructorUtil.newInstance(mapType); - }catch (UtilException e){ + } catch (final UtilException e) { // 不支持的map类型,返回默认的HashMap return new HashMap<>(); } @@ -483,14 +480,14 @@ public class MapUtil { } final List> resultList = new ArrayList<>(); - for (Entry> entry : listMap.entrySet()) { + for (final Entry> entry : listMap.entrySet()) { final Iterator iterator = IterUtil.getIter(entry.getValue()); if (IterUtil.isEmpty(iterator)) { continue; } final K key = entry.getKey(); // 对已经存在的map添加元素 - for (Map map : resultList) { + for (final Map map : resultList) { // 还可以继续添加元素 if (iterator.hasNext()) { map.put(key, iterator.next()); @@ -966,319 +963,6 @@ public class MapUtil { 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 目标值类型 - * @param map Map - * @param key 键 - * @param type 值类型 - * @return 值 - * @since 4.0.6 - */ - public static T get(final Map map, final Object key, final Class type) { - return get(map, key, type, null); - } - - /** - * 获取Map指定key的值,并转换为指定类型 - * - * @param 目标值类型 - * @param map Map - * @param key 键 - * @param type 值类型 - * @param defaultValue 默认值 - * @return 值 - * @since 5.3.11 - */ - public static T get(final Map map, final Object key, final Class type, final T defaultValue) { - return null == map ? defaultValue : Convert.convert(type, map.get(key), defaultValue); - } - - /** - * 获取Map指定key的值,并转换为指定类型,此方法在转换失败后不抛异常,返回null。 - * - * @param 目标值类型 - * @param map Map - * @param key 键 - * @param type 值类型 - * @param defaultValue 默认值 - * @return 值 - * @since 5.5.3 - */ - public static T getQuietly(final Map map, final Object key, final Class type, final T defaultValue) { - return null == map ? defaultValue : Convert.convertQuietly(type, map.get(key), defaultValue); - } - - /** - * 获取Map指定key的值,并转换为指定类型 - * - * @param 目标值类型 - * @param map Map - * @param key 键 - * @param type 值类型 - * @return 值 - * @since 4.5.12 - */ - public static T get(final Map map, final Object key, final TypeReference type) { - return get(map, key, type, null); - } - - /** - * 获取Map指定key的值,并转换为指定类型 - * - * @param 目标值类型 - * @param map Map - * @param key 键 - * @param type 值类型 - * @param defaultValue 默认值 - * @return 值 - * @since 5.3.11 - */ - public static T get(final Map map, final Object key, final TypeReference type, final T defaultValue) { - return null == map ? defaultValue : Convert.convert(type, map.get(key), defaultValue); - } - - /** - * 获取Map指定key的值,并转换为指定类型,转换失败后返回null,不抛异常 - * - * @param 目标值类型 - * @param map Map - * @param key 键 - * @param type 值类型 - * @param defaultValue 默认值 - * @return 值 - * @since 5.5.3 - */ - public static T getQuietly(final Map map, final Object key, final TypeReference type, final T defaultValue) { - return null == map ? defaultValue : Convert.convertQuietly(type, map.get(key), defaultValue); - } - /** * 重命名键
* 实现方式为一处然后重新put,当旧的key不存在直接返回
@@ -1557,4 +1241,32 @@ public class MapUtil { } return resultMap; } + + /** + * 根据给定的entry列表,根据entry的key进行分组; + * + * @param 键类型 + * @param 值类型 + * @param entries entry列表 + * @return entries + * @since 5.8.6 + */ + public static Map> grouping(final Iterable> entries) { + if (CollUtil.isEmpty(entries)) { + return zero(); + } + + final Map> map = new HashMap<>(); + for (final Map.Entry pair : entries) { + final List 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; + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/net/URLUtil.java b/hutool-core/src/main/java/cn/hutool/core/net/URLUtil.java index 6b754e34b..8b21a6387 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/URLUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/URLUtil.java @@ -579,7 +579,7 @@ public class URLUtil { if (isEncodePath) { 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); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java index 48f842c5d..c5f8bd951 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java @@ -406,7 +406,7 @@ public class UrlQuery { private void addParam(final String key, final String value, final Charset charset) { if (null != key) { 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) { // name为空,value作为name,value赋值null this.query.put(URLDecoder.decode(value, charset, isFormUrlEncoded), null); diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 9b9cf5c18..7ec8c70c2 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -26,7 +26,7 @@ public class CollectorUtil { * 说明已包含IDENTITY_FINISH特征 为 Characteristics.IDENTITY_FINISH 的缩写 */ public static final Set CH_ID - = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH)); + = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH)); /** * 说明不包含IDENTITY_FINISH特征 */ @@ -52,7 +52,7 @@ public class CollectorUtil { * @return {@link Collector} */ public static Collector joining(final CharSequence delimiter, - final Function toStringFunc) { + final Function toStringFunc) { return joining(delimiter, StrUtil.EMPTY, StrUtil.EMPTY, toStringFunc); } @@ -67,15 +67,15 @@ public class CollectorUtil { * @return {@link Collector} */ public static Collector joining(final CharSequence delimiter, - final CharSequence prefix, - final CharSequence suffix, - final Function toStringFunc) { + final CharSequence prefix, + final CharSequence suffix, + final Function toStringFunc) { return new SimpleCollector<>( - () -> new StringJoiner(delimiter, prefix, suffix), - (joiner, ele) -> joiner.add(toStringFunc.apply(ele)), - StringJoiner::merge, - StringJoiner::toString, - Collections.emptySet() + () -> new StringJoiner(delimiter, prefix, suffix), + (joiner, ele) -> joiner.add(toStringFunc.apply(ele)), + StringJoiner::merge, + StringJoiner::toString, + Collections.emptySet() ); } @@ -94,8 +94,8 @@ public class CollectorUtil { * @return {@link Collector} */ public static > Collector groupingBy(final Function classifier, - final Supplier mapFactory, - final Collector downstream) { + final Supplier mapFactory, + final Collector downstream) { final Supplier downstreamSupplier = downstream.supplier(); final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer, T> accumulator = (m, t) -> { @@ -133,9 +133,8 @@ public class CollectorUtil { * @param 下游操作在进行中间操作时对应类型 * @return {@link Collector} */ - public static - Collector> groupingBy(final Function classifier, - final Collector downstream) { + public static Collector> groupingBy(final Function classifier, + final Collector downstream) { return groupingBy(classifier, HashMap::new, downstream); } @@ -147,8 +146,7 @@ public class CollectorUtil { * @param 实体中的分组依据对应类型,也是Map中key的类型 * @return {@link Collector} */ - public static Collector>> - groupingBy(final Function classifier) { + public static Collector>> groupingBy(final Function classifier) { return groupingBy(classifier, Collectors.toList()); } @@ -163,10 +161,9 @@ public class CollectorUtil { * @param map中value的类型 * @return 对null友好的 toMap 操作的 {@link Collector}实现 */ - public static - Collector> toMap(final Function keyMapper, - final Function valueMapper, - final BinaryOperator mergeFunction) { + public static Collector> toMap(final Function keyMapper, + final Function valueMapper, + final BinaryOperator mergeFunction) { return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); } @@ -185,11 +182,11 @@ public class CollectorUtil { */ public static > Collector toMap(final Function keyMapper, - final Function valueMapper, - final BinaryOperator mergeFunction, - final Supplier mapSupplier) { + final Function valueMapper, + final BinaryOperator mergeFunction, + final Supplier mapSupplier) { final BiConsumer accumulator - = (map, element) -> map.put(Opt.ofNullable(element).map(keyMapper).get(), Opt.ofNullable(element).map(valueMapper).get()); + = (map, element) -> map.put(Opt.ofNullable(element).map(keyMapper).get(), Opt.ofNullable(element).map(valueMapper).get()); return new SimpleCollector<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID); } @@ -235,13 +232,13 @@ public class CollectorUtil { */ public static >> Collector, ?, R> reduceListMap(final Supplier mapSupplier) { return Collectors.reducing(mapSupplier.get(), value -> { - R result = mapSupplier.get(); - value.forEach((k, v) -> result.computeIfAbsent(k, i -> new ArrayList<>()).add(v)); - return result; - }, (l, r) -> { - r.forEach((k, v) -> l.computeIfAbsent(k, i -> new ArrayList<>()).addAll(v)); - return l; - } + final R result = mapSupplier.get(); + value.forEach((k, v) -> result.computeIfAbsent(k, i -> new ArrayList<>()).add(v)); + return result; + }, (l, r) -> { + r.forEach((k, v) -> l.computeIfAbsent(k, i -> new ArrayList<>()).addAll(v)); + return l; + } ); } @@ -271,7 +268,7 @@ public class CollectorUtil { * @since 6.0.0 */ public static Collector, EntryStream> toEntryStream( - Function keyMapper, Function valueMapper) { + final Function keyMapper, final Function valueMapper) { Objects.requireNonNull(keyMapper); Objects.requireNonNull(valueMapper); return transform(ArrayList::new, list -> EntryStream.of(list, keyMapper, valueMapper)); @@ -306,11 +303,14 @@ public class CollectorUtil { * @since 6.0.0 */ public static > Collector transform( - Supplier collFactory, Function mapper) { + final Supplier collFactory, final Function mapper) { Objects.requireNonNull(collFactory); Objects.requireNonNull(mapper); 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 收集器 * @since 6.0.0 */ - public static Collector, R> transform(Function, R> mapper) { + public static Collector, R> transform(final Function, R> mapper) { return transform(ArrayList::new, mapper); } diff --git a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java index 39ec1c03d..e745820f5 100755 --- a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java @@ -50,7 +50,7 @@ public class CharSequenceUtil extends StrChecker { * @param str 被转换的字符串 * @return 转换后的字符串 */ - public static String nullToEmpty(final CharSequence str) { + public static String emptyIfNull(final CharSequence str) { return ObjUtil.defaultIfNull(str, EMPTY).toString(); } @@ -61,7 +61,7 @@ public class CharSequenceUtil extends StrChecker { * @param str 被转换的字符串 * @return 转换后的字符串 */ - public static T emptyToNull(final T str) { + public static T nullIfEmpty(final T str) { return isEmpty(str) ? null : str; } @@ -809,10 +809,10 @@ public class CharSequenceUtil extends StrChecker { /** * 指定范围内查找指定字符 * - * @param text 字符串 - * @param matcher 被查找的字符匹配器 - * @param start 起始位置,如果小于0,从0开始查找 - * @param end 终止位置,如果超过str.length()则默认查找到字符串末尾 + * @param text 字符串 + * @param matcher 被查找的字符匹配器 + * @param start 起始位置,如果小于0,从0开始查找 + * @param end 终止位置,如果超过str.length()则默认查找到字符串末尾 * @return 位置 * @since 6.0.0 */ @@ -2521,7 +2521,7 @@ public class CharSequenceUtil extends StrChecker { * @return 包装后的字符串 */ 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) { final StringBuilder sb = new StringBuilder(); for (final CharSequence str : strs) { - sb.append(isNullToEmpty ? nullToEmpty(str) : str); + sb.append(isNullToEmpty ? emptyIfNull(str) : str); } return sb.toString(); } diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java b/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java index 04777884e..c41fe4617 100644 --- a/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java @@ -1,5 +1,7 @@ package cn.hutool.core.thread; +import cn.hutool.core.util.RuntimeUtil; + import java.lang.Thread.UncaughtExceptionHandler; import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; @@ -129,7 +131,7 @@ public class ThreadUtil { } // 最佳的线程数 = 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(); } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ObjUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ObjUtil.java index 3d88ceb10..b2f0ee03a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ObjUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ObjUtil.java @@ -1,5 +1,6 @@ package cn.hutool.core.util; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.iter.IterUtil; import cn.hutool.core.comparator.CompareUtil; 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.reflect.ClassUtil; import cn.hutool.core.reflect.MethodUtil; +import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.text.StrUtil; +import java.io.Serializable; import java.lang.reflect.Array; import java.math.BigDecimal; -import java.util.Collection; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.function.Function; import java.util.function.Supplier; @@ -29,13 +28,12 @@ import java.util.function.Supplier; public class ObjUtil { /** - * 比较两个对象是否相等。 - * 相同的条件有两个,满足其一即可:
- *
    - *
  1. obj1 == null && obj2 == null
  2. - *
  3. obj1.equals(obj2)
  4. - *
  5. 如果是BigDecimal比较,0 == obj1.compareTo(obj2)
  6. - *
+ *

比较两个对象是否相等,满足下述任意条件即返回{@code true}: + *

    + *
  • 若两对象皆为{@link BigDecimal},且满足{@code 0 == obj1.compareTo(obj2)}
  • + *
  • {@code obj1 == null && obj2 == null}
  • + *
  • {@code obj1.equals(obj2)}
  • + *
* * @param obj1 对象1 * @param obj2 对象2 @@ -50,27 +48,27 @@ public class ObjUtil { } /** - * 比较两个对象是否不相等。
+ * 比较两个对象是否不相等 * * @param obj1 对象1 * @param obj2 对象2 * @return 是否不等 * @since 3.0.7 + * @see #equals(Object, Object) */ public static boolean notEquals(final Object obj1, final Object obj2) { return false == equals(obj1, obj2); } /** - * 计算对象长度,如果是字符串调用其length函数,集合类调用其size函数,数组调用其length属性,其他可遍历对象遍历计算长度
- * 支持的类型包括: + *

计算对象长度,支持类型包括: *

    - *
  • CharSequence
  • - *
  • Map
  • - *
  • Iterator
  • - *
  • Iterable
  • - *
  • Enumeration
  • - *
  • Array
  • + *
  • {@code null}:默认返回{@code 0};
  • + *
  • 数组:返回数组长度;
  • + *
  • {@link CharSequence}:返回{@link CharSequence#length()};
  • + *
  • {@link Collection}:返回{@link Collection#size()};
  • + *
  • {@link Iterator}或{@link Iterable}:可迭代的元素数量;
  • + *
  • {@link Enumeration}:返回可迭代的元素数量;
  • *
* * @param obj 被计算长度的对象 @@ -100,6 +98,9 @@ public class ObjUtil { } return count; } + if (obj.getClass().isArray()) { + return Array.getLength(obj); + } if (obj instanceof Enumeration) { final Enumeration enumeration = (Enumeration) obj; count = 0; @@ -109,23 +110,21 @@ public class ObjUtil { } return count; } - if (obj.getClass().isArray()) { - return Array.getLength(obj); - } return -1; } /** - * 对象中是否包含元素
- * 支持的对象类型包括: + *

检查{@code obj}中是否包含{@code element},若{@code obj}为{@code null},则直接返回{@code false}。
+ * 支持类型包括: *

    - *
  • String
  • - *
  • Collection
  • - *
  • Map
  • - *
  • Iterator
  • - *
  • Iterable
  • - *
  • Enumeration
  • - *
  • Array
  • + *
  • {@code null}:默认返回{@code false};
  • + *
  • {@link String}:等同{@link String#contains(CharSequence)};
  • + *
  • {@link Collection}:等同{@link Collection#contains(Object)};
  • + *
  • {@link Map}:等同{@link Map#containsValue(Object)};
  • + *
  • + * {@link Iterator}、{@link Iterable}、{@link Enumeration}或数组: + * 等同于遍历后对其元素调用{@link #equals(Object, Object)}方法; + *
  • *
* * @param obj 对象 @@ -182,12 +181,7 @@ public class ObjUtil { } /** - * 检查对象是否为null
- * 判断标准为: - * - *
-	 * 1. == null
-	 * 
+ * 检查对象是否为{@code null} * * @param obj 对象 * @return 是否为null @@ -197,7 +191,7 @@ public class ObjUtil { } /** - * 检查对象是否不为null + * 检查对象是否不为{@code null} * * @param obj 对象 * @return 是否为null @@ -207,19 +201,26 @@ public class ObjUtil { } /** - * 判断指定对象是否为空,支持: - * - *
-	 * 1. CharSequence
-	 * 2. Map
-	 * 3. Iterable
-	 * 4. Iterator
-	 * 5. Array
-	 * 
+ * 判断指定对象是否为空,支持类型包括: + *
    + *
  • {@code null}:默认返回{@code true};
  • + *
  • 数组:等同于{@link ArrayUtil#isEmpty(Object)};
  • + *
  • {@link CharSequence}:等同于{@link CharSequenceUtil#isEmpty(CharSequence)};
  • + *
  • {@link Collection}:等同于{@link CollUtil#isEmpty(Collection)};
  • + *
  • {@link Map}:等同于{@link MapUtil#isEmpty(Map)};
  • + *
  • + * {@link Iterator}或{@link Iterable}:等同于{@link IterUtil#isEmpty(Iterator)}、 + * {@link IterUtil#isEmpty(Iterable)}; + *
  • + *
* * @param obj 被判断的对象 * @return 是否为空,如果类型不支持,返回false * @since 4.5.7 + * @see StrUtil#isEmpty(CharSequence) + * @see MapUtil#isEmpty(Map) + * @see IterUtil#isEmpty(Iterable) + * @see IterUtil#isEmpty(Iterator) */ @SuppressWarnings("rawtypes") public static boolean isEmpty(final Object obj) { @@ -229,7 +230,9 @@ public class ObjUtil { if (obj instanceof CharSequence) { 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); } else if (obj instanceof Iterable) { return IterUtil.isEmpty((Iterable) obj); @@ -243,34 +246,26 @@ public class ObjUtil { } /** - * 判断指定对象是否为非空,支持: - * - *
-	 * 1. CharSequence
-	 * 2. Map
-	 * 3. Iterable
-	 * 4. Iterator
-	 * 5. Array
-	 * 
+ * 判断指定对象是否为非空 * * @param obj 被判断的对象 * @return 是否为空,如果类型不支持,返回true * @since 4.5.7 + * @see #isEmpty(Object) */ public static boolean isNotEmpty(final Object obj) { return false == isEmpty(obj); } /** - * 如果给定对象为{@code null}返回默认值 - * - *
-	 * ObjectUtil.defaultIfNull(null, null)      = null
-	 * ObjectUtil.defaultIfNull(null, "")        = ""
-	 * ObjectUtil.defaultIfNull(null, "zz")      = "zz"
-	 * ObjectUtil.defaultIfNull("abc", *)        = "abc"
-	 * ObjectUtil.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE
-	 * 
+ *

如果给定对象为{@code null}返回默认值 + *

{@code
+	 * ObjectUtil.defaultIfNull(null, null);      // = null
+	 * ObjectUtil.defaultIfNull(null, "");        // = ""
+	 * ObjectUtil.defaultIfNull(null, "zz");      // = "zz"
+	 * ObjectUtil.defaultIfNull("abc", *);        // = "abc"
+	 * ObjectUtil.defaultIfNull(Boolean.TRUE, *); // = Boolean.TRUE
+	 * }
* * @param 对象类型 * @param object 被检查对象,可能为{@code null} @@ -333,14 +328,20 @@ public class ObjUtil { } /** - * 克隆对象
- * 如果对象实现Cloneable接口,调用其clone方法
- * 如果实现Serializable接口,执行深度克隆
- * 否则返回{@code null} + *

克隆对象 + *

    + *
  1. 如果对象是数组,则等同于{@link ArrayUtil#clone(Object)};
  2. + *
  3. 如果对象实现了{@link Cloneable}接口,调用其{@code Cloneable#clone()}方法;
  4. + *
  5. 如果对象实现了{@link Serializable}接口,执行深度克隆;
  6. + *
  7. 不符合上述任意情况则返回{@code null};
  8. + *
* * @param 对象类型 * @param obj 被克隆对象 * @return 克隆后的对象 + * @see ArrayUtil#clone(Object) + * @see Object#clone() + * @see #cloneByStream(Object) */ public static T clone(final T obj) { T result = ArrayUtil.clone(obj); @@ -360,6 +361,7 @@ public class ObjUtil { * @param 对象类型 * @param obj 对象 * @return 克隆后或原对象 + * @see #clone(Object) */ public static T cloneIfPossible(final T obj) { T clone = null; @@ -373,12 +375,13 @@ public class ObjUtil { /** * 序列化后拷贝流的方式克隆
- * 对象必须实现Serializable接口 + * 若对象未实现{@link Serializable}接口则默认返回{@code null} * * @param 对象类型 * @param obj 被克隆对象 * @return 克隆后的对象 * @throws UtilException IO异常和ClassNotFoundException封装 + * @see SerializeUtil#clone(Object) */ public static T cloneByStream(final T obj) { return SerializeUtil.clone(obj); @@ -399,12 +402,15 @@ public class ObjUtil { } /** - * 检查是否为有效的数字
- * 检查Double和Float是否为无限大,或者Not a Number
- * 非数字类型和Null将返回true + * 检查是否为有效的数字,若对象不为{@link Number},则直接返回{@code true},否则: + *
    + *
  • 若对象类型为{@link Double},则检查{@link Double#isInfinite()}或{@link Double#isNaN()};
  • + *
  • 若对象类型为{@link Float},则检查{@link Float#isInfinite()}或{@link Float#isNaN()};
  • + *
* * @param obj 被检查类型 * @return 检查结果,非数字类型和Null将返回true + * @see NumberUtil#isValidNumber(Number) */ public static boolean isValidIfNumber(final Object obj) { if (obj instanceof Number) { @@ -454,7 +460,7 @@ public class ObjUtil { } /** - * 获得给定类的第一个泛型参数 + * 获得给定类指定下标的泛型参数 * * @param obj 被检查的对象 * @param index 泛型类型的索引号,即第几个泛型类型 @@ -466,16 +472,17 @@ public class ObjUtil { } /** - * 将Object转为String
- * 策略为: - *
-	 *  1、null转为"null"
-	 *  2、调用Convert.toStr(Object)转换
-	 * 
+ *

将对象转为字符串 + *

    + *
  • 若对象为{@code null},则返回“null”;
  • + *
  • 若对象为{@link Map},则返回{@code Map#toString()};
  • + *
  • 若对象为其他类型,则调用{@link Convert#toStr(Object)}进行转换;
  • + *
* * @param obj Bean对象 - * @return Bean所有字段转为Map后的字符串 + * @return 转换后的字符串 * @since 3.2.0 + * @see Convert#toStr(Object) */ public static String toString(final Object obj) { if (null == obj) { @@ -484,7 +491,6 @@ public class ObjUtil { if (obj instanceof Map) { return obj.toString(); } - return Convert.toStr(obj); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/RuntimeUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/RuntimeUtil.java index 1989565f0..90533cb95 100755 --- a/hutool-core/src/main/java/cn/hutool/core/util/RuntimeUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/RuntimeUtil.java @@ -13,6 +13,7 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Stack; +import java.util.concurrent.ThreadPoolExecutor; /** * 系统运行时工具类,用于执行系统命令的工具 @@ -234,11 +235,21 @@ public class RuntimeUtil { /** * 获得JVM可用的处理器数量(一般为CPU核心数) * + *

+ * 这里做一个特殊的处理,在特殊的CPU上面,会有获取不到CPU数量的情况,所以这里做一个保护; + * 默认给一个7,真实的CPU基本都是偶数,方便区分。 + * 如果不做处理,会出现创建线程池时{@link ThreadPoolExecutor},抛出异常:{@link IllegalArgumentException} + *

+ * * @return 可用的处理器数量 * @since 5.3.0 */ public static int getProcessorCount() { - return Runtime.getRuntime().availableProcessors(); + int cpu = Runtime.getRuntime().availableProcessors(); + if (cpu <= 0) { + cpu = 7; + } + return cpu; } /** diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/iter/ArrayIterTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/iter/ArrayIterTest.java new file mode 100644 index 000000000..48aef57a1 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/collection/iter/ArrayIterTest.java @@ -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 iter = new ArrayIter<>(arr); + Assert.assertTrue(iter.hasNext()); + } + + @Test + public void testNext() { + Integer[] arr = new Integer[]{ 1, 2, 3 }; + ArrayIter 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 iter = new ArrayIter<>(arr); + Assert.assertThrows(UnsupportedOperationException.class, iter::remove); + } + + @Test + public void testGetArray() { + Integer[] arr = new Integer[]{ 1, 2, 3 }; + ArrayIter iter = new ArrayIter<>(arr); + Assert.assertEquals(arr, iter.getArray()); + } + + @Test + public void testReset() { + Integer[] arr = new Integer[]{ 1, 2, 3 }; + ArrayIter iter = new ArrayIter<>(arr); + Assert.assertEquals((Integer)1, iter.next()); + iter.reset(); + Assert.assertEquals((Integer)1, iter.next()); + } + +} diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/iter/CopiedIterTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/iter/CopiedIterTest.java new file mode 100644 index 000000000..76e86a7c2 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/collection/iter/CopiedIterTest.java @@ -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 list = Arrays.asList(1, 2, 3); + Iterator 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 list = Arrays.asList(1, 2, 3); + Iterator 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 list = Arrays.asList(1, 2, 3); + Iterator iter = CopiedIter.copyOf(list.iterator()); + Assert.assertThrows(UnsupportedOperationException.class, iter::remove); + } + +} diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/iter/EnumerationIterTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/iter/EnumerationIterTest.java new file mode 100644 index 000000000..8c2b6b0c3 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/collection/iter/EnumerationIterTest.java @@ -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 enumeration = new IteratorEnumeration<>(Arrays.asList(1, 2, 3).iterator()); + EnumerationIter iter = new EnumerationIter<>(enumeration); + Assert.assertTrue(iter.hasNext()); + Assert.assertFalse(new EnumerationIter<>(new IteratorEnumeration<>(Collections.emptyIterator())).hasNext()); + } + + @Test + public void testNext() { + Enumeration enumeration = new IteratorEnumeration<>(Arrays.asList(1, 2, 3).iterator()); + EnumerationIter 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 enumeration = new IteratorEnumeration<>(Arrays.asList(1, 2, 3).iterator()); + EnumerationIter iter = new EnumerationIter<>(enumeration); + Assert.assertThrows(UnsupportedOperationException.class, iter::remove); + } + + @Test + public void testIterator() { + Enumeration enumeration = new IteratorEnumeration<>(Arrays.asList(1, 2, 3).iterator()); + EnumerationIter iter = new EnumerationIter<>(enumeration); + Assert.assertSame(iter, iter.iterator()); + } + +} diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/iter/FilterIterTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/iter/FilterIterTest.java index 79cacae3c..4778a320d 100755 --- a/hutool-core/src/test/java/cn/hutool/core/collection/iter/FilterIterTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/collection/iter/FilterIterTest.java @@ -4,7 +4,10 @@ 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.Iterator; +import java.util.function.Predicate; public class FilterIterTest { @@ -20,4 +23,40 @@ public class FilterIterTest { } Assert.assertEquals(2, count); } + + @Test + public void hasNext() { + Iterator 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 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 iter = new FilterIter<>(Collections.emptyIterator(), i -> true); + Assert.assertThrows(IllegalStateException.class, iter::remove); + } + + @Test + public void getIterator() { + FilterIter iter = new FilterIter<>(Collections.emptyIterator(), i -> true); + Assert.assertSame(Collections.emptyIterator(), iter.getIterator()); + } + + @Test + public void getFilter() { + Predicate predicate = i -> true; + FilterIter iter = new FilterIter<>(Collections.emptyIterator(), predicate); + Assert.assertSame(predicate, iter.getFilter()); + } + } diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/iter/IterChainTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/iter/IterChainTest.java new file mode 100644 index 000000000..26676f85b --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/collection/iter/IterChainTest.java @@ -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 iter1 = Arrays.asList(1, 2).iterator(); + Iterator iter2 = Arrays.asList(3, 4).iterator(); + IterChain 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 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 iter1 = Arrays.asList(1, 2).iterator(); + Iterator iter2 = Arrays.asList(3, 4).iterator(); + IterChain 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 iterChain = new IterChain<>(); + iterChain.addChain(Arrays.asList(1, 2).iterator()); + Assert.assertThrows(IllegalStateException.class, iterChain::remove); + } + + @Test + public void testIterator() { + Iterator iter1 = Arrays.asList(1, 2).iterator(); + Iterator iter2 = Arrays.asList(3, 4).iterator(); + IterChain iterChain = new IterChain<>(); + Assert.assertSame(iterChain, iterChain.addChain(iter1)); + Assert.assertSame(iterChain, iterChain.addChain(iter2)); + + Iterator> iterators = iterChain.iterator(); + Assert.assertSame(iter1, iterators.next()); + Assert.assertSame(iter2, iterators.next()); + } + +} diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/iter/IterUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/iter/IterUtilTest.java new file mode 100644 index 000000000..be901e74d --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/collection/iter/IterUtilTest.java @@ -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 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 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 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 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 keys = Arrays.asList(1, 2, 3); + + Map 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 keys = Arrays.asList(1, 2, 3, 4); + + Map> 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> 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 iter = Arrays.asList(1, 2, 3).iterator(); + Assert.assertEquals(iter, IterUtil.asIterable(iter).iterator()); + Assert.assertNull(IterUtil.asIterable(null).iterator()); + + Enumeration enumeration = new IteratorEnumeration<>(iter); + Iterator 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 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 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)null, t -> (t & 1) == 0)); + Assert.assertNull(IterUtil.getFirst(Collections.emptyIterator(), Objects::nonNull)); + } + + @Test + public void testGetFirstNoneNull() { + Iterator 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 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 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 list1 = new ArrayList<>(Arrays.asList(1, null, null, 3)); + List 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 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 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 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; + } + +} diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/iter/IteratorEnumerationTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/iter/IteratorEnumerationTest.java new file mode 100644 index 000000000..273579188 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/collection/iter/IteratorEnumerationTest.java @@ -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 list = Arrays.asList(1, 2, 3); + IteratorEnumeration enumeration = new IteratorEnumeration<>(list.iterator()); + Assert.assertTrue(enumeration.hasMoreElements()); + Assert.assertFalse(new IteratorEnumeration<>(Collections.emptyIterator()).hasMoreElements()); + } + + @Test + public void testNextElement() { + List list = Arrays.asList(1, 2, 3); + IteratorEnumeration enumeration = new IteratorEnumeration<>(list.iterator()); + Assert.assertEquals((Integer)1, enumeration.nextElement()); + Assert.assertEquals((Integer)2, enumeration.nextElement()); + Assert.assertEquals((Integer)3, enumeration.nextElement()); + } + +} diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/iter/LineIterTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/iter/LineIterTest.java new file mode 100644 index 000000000..27c13d7cd --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/collection/iter/LineIterTest.java @@ -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); + } + +} diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/iter/PartitionIterTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/iter/PartitionIterTest.java new file mode 100644 index 000000000..cacc8f8ce --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/collection/iter/PartitionIterTest.java @@ -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 iter = Arrays.asList(1, 2, 3, 4).iterator(); + PartitionIter partitionIter = new PartitionIter<>(iter, 2); + Assert.assertTrue(partitionIter.hasNext()); + Assert.assertFalse(new PartitionIter<>(Collections.emptyIterator(), 1).hasNext()); + } + + @Test + public void testNext() { + Iterator iter = Arrays.asList(1, 2, 3, 4).iterator(); + PartitionIter partitionIter = new PartitionIter<>(iter, 2); + Assert.assertEquals(Arrays.asList(1, 2), partitionIter.next()); + Assert.assertEquals(Arrays.asList(3, 4), partitionIter.next()); + } + +} diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/iter/TransIterTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/iter/TransIterTest.java new file mode 100644 index 000000000..3651b59be --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/collection/iter/TransIterTest.java @@ -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 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 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 list = ListUtil.of(1, 2, 3); + TransIter iter = new TransIter<>(list.iterator(), String::valueOf); + iter.next(); + iter.remove(); + iter.next(); + iter.remove(); + iter.next(); + iter.remove(); + Assert.assertTrue(list.isEmpty()); + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/date/TimeUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/TimeUtilTest.java index f830c52c5..1879afb6f 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/TimeUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/TimeUtilTest.java @@ -10,7 +10,6 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; -import java.time.temporal.TemporalAccessor; import java.util.Objects; public class TimeUtilTest { @@ -234,7 +233,49 @@ public class TimeUtilTest { @Test public void ofTest2(){ 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); } + + @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)); + + // begin、end互换 + 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)); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java index 00670f8d2..a56eefd30 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java @@ -47,14 +47,14 @@ public class CollectorUtilTest { @Test public void testToEasyStream() { - Stream stream =Stream.of(1, 2, 3, 4) + final Stream stream =Stream.of(1, 2, 3, 4) .collect(CollectorUtil.toEasyStream()); Assert.assertEquals(EasyStream.class, stream.getClass()); } @Test public void testToEntryStream() { - Map map = Stream.of(1, 2, 3, 4, 5) + final Map map = Stream.of(1, 2, 3, 4, 5) // 转为EntryStream .collect(CollectorUtil.toEntryStream(Function.identity(), String::valueOf)) // 过滤偶数 diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java index b32481663..dfe056b1f 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java @@ -218,7 +218,7 @@ public class EasyStreamTest { } @Test - public void testPeek(){ + public void testPeek() { EasyStream.of("one", "two", "three", "four") .filter(e -> e.length() == 4) .peek(e -> Assert.assertEquals("four", e)) @@ -228,12 +228,12 @@ public class EasyStreamTest { } @Test - public void testPeekIdx(){ + public void testPeekIdx() { EasyStream.of("one", "two", "three", "four") .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) - .peekIdx((e,i) -> Assert.assertEquals("FOUR:0", e + ":" + i)) + .peekIdx((e, i) -> Assert.assertEquals("FOUR:0", e + ":" + i)) .collect(Collectors.toList()); } @@ -431,7 +431,7 @@ public class EasyStreamTest { @Test public void testToTree() { Consumer test = o -> { - List studentTree = EasyStream + final List studentTree = EasyStream .of( Student.builder().id(1L).name("dromara").build(), Student.builder().id(2L).name("baomidou").build(), @@ -464,7 +464,7 @@ public class EasyStreamTest { ), studentTree); }; test = test.andThen(o -> { - List studentTree = EasyStream + final List studentTree = EasyStream .of( Student.builder().id(1L).name("dromara").matchParent(true).build(), Student.builder().id(2L).name("baomidou").matchParent(true).build(), @@ -501,7 +501,7 @@ public class EasyStreamTest { @Test public void testFlatTree() { - List studentTree = asList( + final List studentTree = asList( Student.builder().id(1L).name("dromara") .children(asList(Student.builder().id(3L).name("hutool").parentId(1L) .children(singletonList(Student.builder().id(6L).name("looly").parentId(3L).build())) @@ -551,9 +551,9 @@ public class EasyStreamTest { @Test public void testTransform() { final boolean result = EasyStream.of(1, 2, 3) - .transform(EasyStream::toList) - .map(List::isEmpty) - .orElse(false); + .transform(EasyStream::toList) + .map(List::isEmpty) + .orElse(false); Assert.assertFalse(result); } diff --git a/hutool-core/src/test/java/cn/hutool/core/util/ObjUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/ObjUtilTest.java index dd920ee8b..b4c720f09 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/ObjUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/ObjUtilTest.java @@ -1,17 +1,23 @@ package cn.hutool.core.util; 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.Test; +import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; -import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.function.Function; +/** + * test for {@link ObjUtil} + */ public class ObjUtilTest { @Test @@ -56,43 +62,49 @@ public class ObjUtilTest { final Iterable list = ListUtil.of(1, 2, 3); Assert.assertEquals(3, ObjUtil.length(list)); + Assert.assertEquals(3, ObjUtil.length(Arrays.asList(1, 2, 3).iterator())); } @Test public void containsTest(){ - final int[] array = new int[]{1,2,3,4,5}; - - final boolean contains = ObjUtil.contains(array, 1); - Assert.assertTrue(contains); + Assert.assertTrue(ObjUtil.contains(new int[]{1,2,3,4,5}, 1)); + Assert.assertFalse(ObjUtil.contains(null, 1)); + Assert.assertTrue(ObjUtil.contains("123", "3")); + Map 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 - public void cloneTest() { - final Obj obj = new Obj(); - 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); - } - } + public void isNullTest() { + Assert.assertTrue(ObjUtil.isNull(null)); } @Test - public void toStringTest() { - final ArrayList strings = ListUtil.of("1", "2"); - final String result = ObjUtil.toString(strings); - Assert.assertEquals("[1, 2]", result); + public void isNotNullTest() { + Assert.assertFalse(ObjUtil.isNotNull(null)); + } + + @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 @@ -113,6 +125,48 @@ public class ObjUtilTest { 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 public void isBasicTypeTest(){ final int a = 1; @@ -121,9 +175,72 @@ public class ObjUtilTest { } @Test - public void cloneIfPossibleTest() { - final String a = "a"; - final String a2 = ObjUtil.cloneIfPossible(a); - Assert.assertNotSame(a, a2); + public void isValidIfNumberTest() { + Assert.assertTrue(ObjUtil.isValidIfNumber(null)); + Assert.assertFalse(ObjUtil.isValidIfNumber(Double.NEGATIVE_INFINITY)); + 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 { + private final Integer id; + } + + private interface TypeArgument {}; + } diff --git a/hutool-core/src/test/java/cn/hutool/core/util/RuntimeUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/RuntimeUtilTest.java index dd0ccbe80..d76d316e8 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/RuntimeUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/RuntimeUtilTest.java @@ -43,4 +43,11 @@ public class RuntimeUtilTest { final int pid = RuntimeUtil.getPid(); Assert.assertTrue(pid > 0); } + + @Test + public void getProcessorCountTest(){ + int cpu = RuntimeUtil.getProcessorCount(); + Console.log("cpu个数:{}", cpu); + Assert.assertTrue(cpu > 0); + } } diff --git a/hutool-core/src/test/resources/text.txt b/hutool-core/src/test/resources/text.txt new file mode 100644 index 000000000..810ae5ae8 --- /dev/null +++ b/hutool-core/src/test/resources/text.txt @@ -0,0 +1,3 @@ +is first line +is second line +is third line diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java b/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java index 616d8132f..245cf0955 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java @@ -2,8 +2,9 @@ package cn.hutool.extra.ftp; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.FileUtil; -import cn.hutool.core.util.CharsetUtil; 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.File; @@ -73,7 +74,12 @@ public abstract class AbstractFtp implements Closeable { * @since 5.7.5 */ public boolean isDir(final String dir) { - return cd(dir); + final String workDir = pwd(); + try { + return cd(dir); + } finally { + cd(workDir); + } } /** @@ -85,14 +91,35 @@ public abstract class AbstractFtp implements Closeable { public abstract boolean mkdir(String dir); /** - * 文件或目录是否存在 + * 文件或目录是否存在
+ *
    + *
  • 提供路径为空则返回{@code false}
  • + *
  • 提供路径非目录但是以'/'或'\'结尾返回{@code false}
  • + *
  • 文件名是'.'或者'..'返回{@code false}
  • + *
* * @param path 目录 * @return 是否存在 */ 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 dir = StrUtil.removeSuffix(path, fileName); + if (".".equals(fileName) || "..".equals(fileName)) { + return false; + } + + // 文件验证 + final String dir = StrUtil.defaultIfEmpty(StrUtil.removeSuffix(path, fileName), "."); final List names; try { names = ls(dir); @@ -180,7 +207,7 @@ public abstract class AbstractFtp implements Closeable { /** * 下载文件-避免未完成的文件
- * 来自:https://gitee.com/dromara/hutool/pulls/407
+ * 来自:https://gitee.com/dromara/hutool/pulls/407
* 此方法原理是先在目标文件同级目录下创建临时文件,下载之,等下载完毕后重命名,避免因下载错误导致的文件不完整。 * * @param path 文件路径 diff --git a/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java b/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java index bd7bebbcb..4e817b4ed 100644 --- a/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java @@ -89,5 +89,66 @@ public class FtpTest { 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()); + } } } diff --git a/hutool-http/src/main/java/cn/hutool/http/GlobalHeaders.java b/hutool-http/src/main/java/cn/hutool/http/GlobalHeaders.java index 00e694382..59f8590da 100644 --- a/hutool-http/src/main/java/cn/hutool/http/GlobalHeaders.java +++ b/hutool-http/src/main/java/cn/hutool/http/GlobalHeaders.java @@ -180,7 +180,7 @@ public enum GlobalHeaders { for (final Entry> entry : headers.entrySet()) { name = entry.getKey(); for (final String value : entry.getValue()) { - this.header(name, StrUtil.nullToEmpty(value), false); + this.header(name, StrUtil.emptyIfNull(value), false); } } return this; diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpBase.java b/hutool-http/src/main/java/cn/hutool/http/HttpBase.java index 1abe3cd07..13b56fb43 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpBase.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpBase.java @@ -174,7 +174,7 @@ public abstract class HttpBase { } for (final Entry entry : headers.entrySet()) { - this.header(entry.getKey(), StrUtil.nullToEmpty(entry.getValue()), isOverride); + this.header(entry.getKey(), StrUtil.emptyIfNull(entry.getValue()), isOverride); } return (T) this; } @@ -207,7 +207,7 @@ public abstract class HttpBase { for (final Entry> entry : headers.entrySet()) { name = entry.getKey(); for (final String value : entry.getValue()) { - this.header(name, StrUtil.nullToEmpty(value), isOverride); + this.header(name, StrUtil.emptyIfNull(value), isOverride); } } return (T) this; @@ -227,7 +227,7 @@ public abstract class HttpBase { } for (final Entry entry : headers.entrySet()) { - this.header(entry.getKey(), StrUtil.nullToEmpty(entry.getValue()), false); + this.header(entry.getKey(), StrUtil.emptyIfNull(entry.getValue()), false); } return (T) this; } diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java b/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java index 0e24960d5..73da28ea1 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java @@ -213,7 +213,7 @@ public class HttpConnection { for (final Entry> entry : headerMap.entrySet()) { name = entry.getKey(); for (final String value : entry.getValue()) { - this.header(name, StrUtil.nullToEmpty(value), isOverride); + this.header(name, StrUtil.emptyIfNull(value), isOverride); } } } diff --git a/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java b/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java index 52cf59582..b247e08df 100755 --- a/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java +++ b/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java @@ -13,7 +13,6 @@ import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.ObjUtil; -import cn.hutool.json.convert.JSONConverterOld; import cn.hutool.json.serialize.JSONString; import java.io.IOException; @@ -207,9 +206,8 @@ public final class InternalJSONUtil { * @param key 键 * @param value 值 * @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> predicate) { + public static void propertyPut(final JSONObject jsonObject, final Object key, final Object value, final Predicate> predicate) { final String[] path = StrUtil.splitToArray(Convert.toStr(key), CharUtil.DOT); final int last = path.length - 1; JSONObject target = jsonObject; @@ -223,7 +221,6 @@ public final class InternalJSONUtil { target = nextTarget; } target.set(path[last], value, predicate); - return jsonObject; } /** @@ -259,8 +256,7 @@ public final class InternalJSONUtil { .setIgnoreNullValue(config.isIgnoreNullValue()) .setTransientSupport(config.isTransientSupport()) // 使用JSON转换器 - .setConverter((type, value) -> - JSONConverterOld.convertWithCheck(type, value, null, config.isIgnoreError())); + .setConverter(config.getConverter()); } /** @@ -296,11 +292,10 @@ public final class InternalJSONUtil { * * @param str 字符串 * @param writer Writer - * @return Writer * @throws IORuntimeException IO异常 */ - public static Writer quote(final String str, final Writer writer) throws IORuntimeException { - return quote(str, writer, true); + public static void quote(final String str, final Writer writer) throws IORuntimeException { + quote(str, writer, true); } /** diff --git a/hutool-json/src/main/java/cn/hutool/json/JSON.java b/hutool-json/src/main/java/cn/hutool/json/JSON.java index f4561b9d3..c0c1f3a7c 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSON.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSON.java @@ -2,7 +2,6 @@ package cn.hutool.json; import cn.hutool.core.bean.BeanPath; import cn.hutool.core.lang.mutable.MutableEntry; -import cn.hutool.json.convert.JSONConverterOld; import java.io.Serializable; import java.io.StringWriter; @@ -107,7 +106,10 @@ public interface JSON extends Cloneable, Serializable { * @see BeanPath#get(Object) * @since 4.0.6 */ - T getByPath(String expression, Class resultType); + @SuppressWarnings("unchecked") + default T getByPath(final String expression, final Class resultType){ + return (T) getConfig().getConverter().convert(resultType, getByPath(expression)); + } /** * 格式化打印JSON,缩进为4个空格 @@ -159,17 +161,6 @@ public interface JSON extends Cloneable, Serializable { */ Writer write(Writer writer, int indentFactor, int indent, final Predicate> predicate) throws JSONException; - /** - * 转为实体类对象,转换异常将被抛出 - * - * @param Bean类型 - * @param clazz 实体类 - * @return 实体类对象 - */ - default T toBean(final Class clazz) { - return toBean((Type) clazz); - } - /** * 转为实体类对象 * @@ -178,7 +169,8 @@ public interface JSON extends Cloneable, Serializable { * @return 实体类对象 * @since 4.3.2 */ + @SuppressWarnings("unchecked") default T toBean(final Type type) { - return JSONConverterOld.jsonConvert(type, this, getConfig()); + return (T) getConfig().getConverter().convert(type, this); } } diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java index 8fbd73162..c8ca774b3 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java @@ -8,7 +8,6 @@ import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.lang.mutable.MutableObj; import cn.hutool.core.text.StrJoiner; import cn.hutool.core.util.ObjUtil; -import cn.hutool.json.convert.JSONConverterOld; import cn.hutool.json.mapper.ArrayMapper; import cn.hutool.json.serialize.JSONWriter; @@ -193,11 +192,6 @@ public class JSONArray implements JSON, JSONGetter, List, Rando return (index < 0 || index >= this.size()) ? defaultValue : this.rawList.get(index); } - @Override - public T getByPath(final String expression, final Class resultType) { - return JSONConverterOld.jsonConvert(resultType, getByPath(expression), getConfig()); - } - /** * Append an object value. This increases the array's length by one.
* 加入元素,数组长度+1,等同于 {@link JSONArray#add(Object)} diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java b/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java index b90a512c3..2e2526b82 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONConfig.java @@ -1,6 +1,7 @@ package cn.hutool.json; import cn.hutool.core.comparator.CompareUtil; +import cn.hutool.core.convert.Converter; import java.io.Serializable; import java.util.Comparator; @@ -38,7 +39,6 @@ public class JSONConfig implements Serializable { * 是否支持transient关键字修饰和@Transient注解,如果支持,被修饰的字段或方法对应的字段将被忽略。 */ private boolean transientSupport = true; - /** * 是否去除末尾多余0,例如如果为true,5.0返回5 */ @@ -47,6 +47,10 @@ public class JSONConfig implements Serializable { * 是否检查重复key */ private boolean checkDuplicate; + /** + * 自定义的类型转换器,用于在序列化、反序列化操作中实现对象类型转换 + */ + private Converter converter; /** * 创建默认的配置项 @@ -237,4 +241,20 @@ public class JSONConfig implements Serializable { this.checkDuplicate = checkDuplicate; return this; } + + /** + * 获取自定义的类型转换器,用于在序列化、反序列化操作中实现对象类型转换 + * @return 转换器 + */ + public Converter getConverter() { + return converter; + } + + /** + * 设置自定义的类型转换器,用于在序列化、反序列化操作中实现对象类型转换 + * @param converter 转换器 + */ + public void setConverter(final Converter converter) { + this.converter = converter; + } } diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONGetter.java b/hutool-json/src/main/java/cn/hutool/json/JSONGetter.java index 6114a2790..15b586f21 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONGetter.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONGetter.java @@ -3,7 +3,6 @@ package cn.hutool.json; import cn.hutool.core.convert.ConvertException; import cn.hutool.core.lang.getter.OptNullBasicTypeFromObjectGetter; import cn.hutool.core.util.ObjUtil; -import cn.hutool.json.convert.JSONConverterOld; import java.time.LocalDateTime; import java.util.Date; @@ -163,12 +162,13 @@ public interface JSONGetter extends OptNullBasicTypeFromObjectGetter { * @throws ConvertException 转换异常 * @since 3.0.8 */ + @SuppressWarnings("unchecked") default T get(final K key, final Class type) throws ConvertException { final Object value = this.getObj(key); if (ObjUtil.isNull(value)) { return null; } - return JSONConverterOld.jsonConvert(type, value, getConfig()); + return (T) getConfig().getConverter().convert(type, value); } } diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java index a56427eda..645a41d60 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java @@ -5,7 +5,6 @@ import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapWrapper; import cn.hutool.core.util.ObjUtil; -import cn.hutool.json.convert.JSONConverterOld; import cn.hutool.json.mapper.ObjectMapper; import cn.hutool.json.serialize.JSONWriter; @@ -183,11 +182,6 @@ public class JSONObject extends MapWrapper implements JSON, JSON return this.getOrDefault(key, defaultValue); } - @Override - public T getByPath(final String expression, final Class resultType) { - return JSONConverterOld.jsonConvert(resultType, getByPath(expression), getConfig()); - } - /** * PUT 键值对到JSONObject中,在忽略null模式下,如果值为{@code null},将此键移除 * diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONSupport.java b/hutool-json/src/main/java/cn/hutool/json/JSONSupport.java index 8660e849b..2e170d320 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONSupport.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONSupport.java @@ -1,7 +1,6 @@ package cn.hutool.json; import cn.hutool.core.bean.BeanUtil; -import cn.hutool.json.convert.JSONConverterOld; import cn.hutool.json.serialize.JSONDeserializer; import cn.hutool.json.serialize.JSONString; @@ -29,8 +28,8 @@ public class JSONSupport implements JSONString, JSONDeserializer { */ @Override public Object deserialize(final JSON json) { - final JSONSupport support = JSONConverterOld.jsonToBean(getClass(), json, false); - BeanUtil.copyProperties(support, this); + // TODO 经过两次转换,效率差,待优化 + BeanUtil.copyProperties(json.toBean(getClass()), this); return this; } diff --git a/hutool-json/src/main/java/cn/hutool/json/convert/JSONCompositeConverter.java b/hutool-json/src/main/java/cn/hutool/json/convert/JSONCompositeConverter.java new file mode 100755 index 000000000..709899b03 --- /dev/null +++ b/hutool-json/src/main/java/cn/hutool/json/convert/JSONCompositeConverter.java @@ -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 convert(final Type type, final Object value, final T defaultValue, final boolean isCustomFirst) throws ConvertException { + return super.convert(type, value, defaultValue, isCustomFirst); + } +} diff --git a/hutool-json/src/test/java/Issue2555Test.java b/hutool-json/src/test/java/Issue2555Test.java new file mode 100755 index 000000000..d62c63bb5 --- /dev/null +++ b/hutool-json/src/test/java/Issue2555Test.java @@ -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 { + @Override + public void serialize(JSONObject json, MyType bean) { + json.set("addr", bean.getAddress()); + } + } + + public static class MyDeserializer implements JSONDeserializer { + @Override + public MyType deserialize(JSON json) { + final MyType myType = new MyType(); + myType.setAddress(((JSONObject)json).getStr("addr")); + return myType; + } + } +} diff --git a/hutool-json/src/test/java/cn/hutool/json/jwt/JWTTest.java b/hutool-json/src/test/java/cn/hutool/json/jwt/JWTTest.java index 4dffd65ce..0d2808651 100755 --- a/hutool-json/src/test/java/cn/hutool/json/jwt/JWTTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/jwt/JWTTest.java @@ -3,12 +3,15 @@ package cn.hutool.json.jwt; import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateUtil; 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 lombok.Data; import org.junit.Assert; import org.junit.Test; import java.util.Arrays; +import java.util.Base64; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -159,4 +162,14 @@ public class JWTTest { final Date date = JWT.of(token).getPayload().getClaimsJson().getDate(JWTPayload.ISSUED_AT); Assert.assertEquals("2022-02-02", DateUtil.format(date, DatePattern.NORM_DATE_PATTERN)); } + + @Test + public void issue2581Test(){ + final Map 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()); + } } diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/StyleSet.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/StyleSet.java index e592ec0cc..9e5b24c23 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/StyleSet.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/StyleSet.java @@ -63,8 +63,8 @@ public class StyleSet implements Serializable { // 默认数字格式 cellStyleForNumber = StyleUtil.cloneCellStyle(workbook, this.cellStyle); - // 2表示:0.00 - cellStyleForNumber.setDataFormat((short) 2); + // 0表示:General + cellStyleForNumber.setDataFormat((short) 0); // 默认日期格式 this.cellStyleForDate = StyleUtil.cloneCellStyle(workbook, this.cellStyle); diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellUtil.java index ca8b8d056..5adfbdbd0 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellUtil.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellUtil.java @@ -449,7 +449,7 @@ public class CellUtil { } final Comment comment = drawing.createCellComment(anchor); comment.setString(factory.createRichTextString(commentText)); - comment.setAuthor(StrUtil.nullToEmpty(commentAuthor)); + comment.setAuthor(StrUtil.emptyIfNull(commentAuthor)); cell.setCellComment(comment); } diff --git a/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelWriteTest.java b/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelWriteTest.java index faa12dd0d..76a875b1d 100755 --- a/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelWriteTest.java +++ b/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelWriteTest.java @@ -820,6 +820,19 @@ public class ExcelWriteTest { 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 @Ignore public void issueI466ZZTest(){ diff --git a/hutool-poi/src/test/java/cn/hutool/poi/word/WordWriterTest.java b/hutool-poi/src/test/java/cn/hutool/poi/word/WordWriterTest.java index 4e7c6f0bc..0e0d32426 100644 --- a/hutool-poi/src/test/java/cn/hutool/poi/word/WordWriterTest.java +++ b/hutool-poi/src/test/java/cn/hutool/poi/word/WordWriterTest.java @@ -4,11 +4,14 @@ import cn.hutool.core.collection.ListUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.lang.Console; +import lombok.AllArgsConstructor; +import lombok.Data; import org.junit.Ignore; import org.junit.Test; import java.awt.Font; import java.io.File; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -94,4 +97,28 @@ public class WordWriterTest { word07Writer.addTable(list); word07Writer.close(); } + + @Test + @Ignore + public void writeBeanAsTableTest(){ + final List 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; + } } diff --git a/hutool-setting/src/main/java/cn/hutool/setting/GroupedMap.java b/hutool-setting/src/main/java/cn/hutool/setting/GroupedMap.java index d73a0e3a3..51da1f6fc 100644 --- a/hutool-setting/src/main/java/cn/hutool/setting/GroupedMap.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/GroupedMap.java @@ -38,7 +38,7 @@ public class GroupedMap extends LinkedHashMap map = this.get(StrUtil.nullToEmpty(group)); + final LinkedHashMap map = this.get(StrUtil.emptyIfNull(group)); if (MapUtil.isNotEmpty(map)) { return map.get(key); } @@ -88,7 +88,7 @@ public class GroupedMap extends LinkedHashMap valueMap = this.computeIfAbsent(group, k -> new LinkedHashMap<>()); @@ -121,7 +121,7 @@ public class GroupedMap extends LinkedHashMap valueMap = this.get(group); @@ -141,7 +141,7 @@ public class GroupedMap extends LinkedHashMap valueMap = this.get(group); @@ -172,7 +172,7 @@ public class GroupedMap extends LinkedHashMap valueMap = this.get(group); @@ -193,7 +193,7 @@ public class GroupedMap extends LinkedHashMap valueMap = this.get(group); @@ -213,7 +213,7 @@ public class GroupedMap extends LinkedHashMap valueMap = this.get(group); @@ -243,7 +243,7 @@ public class GroupedMap extends LinkedHashMap keySet(String group) { - group = StrUtil.nullToEmpty(group).trim(); + group = StrUtil.emptyIfNull(group).trim(); readLock.lock(); try { final LinkedHashMap valueMap = this.get(group); @@ -263,7 +263,7 @@ public class GroupedMap extends LinkedHashMap values(String group) { - group = StrUtil.nullToEmpty(group).trim(); + group = StrUtil.emptyIfNull(group).trim(); readLock.lock(); try { final LinkedHashMap valueMap = this.get(group); @@ -293,7 +293,7 @@ public class GroupedMap extends LinkedHashMap> entrySet(String group) { - group = StrUtil.nullToEmpty(group).trim(); + group = StrUtil.emptyIfNull(group).trim(); readLock.lock(); try { final LinkedHashMap valueMap = this.get(group); diff --git a/hutool-setting/src/main/java/cn/hutool/setting/dialect/Props.java b/hutool-setting/src/main/java/cn/hutool/setting/dialect/Props.java index c88802339..e198d5d4a 100644 --- a/hutool-setting/src/main/java/cn/hutool/setting/dialect/Props.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/dialect/Props.java @@ -572,7 +572,7 @@ public final class Props extends Properties implements BasicTypeGetter, * @since 4.6.3 */ public 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; for (final java.util.Map.Entry entry : this.entrySet()) { diff --git a/hutool-setting/src/main/java/cn/hutool/setting/profile/Profile.java b/hutool-setting/src/main/java/cn/hutool/setting/profile/Profile.java index debbbe5a4..73d680c47 100755 --- a/hutool-setting/src/main/java/cn/hutool/setting/profile/Profile.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/profile/Profile.java @@ -137,7 +137,7 @@ public class Profile implements Serializable { */ private String fixNameForProfile(final String name) { 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)) { return StrUtil.format("{}/{}.setting", actralProfile, name); } diff --git a/hutool-swing/src/main/java/cn/hutool/swing/img/ImgUtil.java b/hutool-swing/src/main/java/cn/hutool/swing/img/ImgUtil.java index 1e89906a4..08feaffb0 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/img/ImgUtil.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/img/ImgUtil.java @@ -450,12 +450,13 @@ public class ImgUtil { * * @param srcImageFile 源图像文件 * @param destDir 切片目标文件夹 + * @param formatName 格式名称,即图片格式后缀 * @param rows 目标切片行数。默认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 { - sliceByRowsAndCols(ImageIO.read(srcImageFile), destDir, rows, cols); + sliceByRowsAndCols(ImageIO.read(srcImageFile), destDir, formatName, rows, cols); } catch (final IOException e) { throw new IORuntimeException(e); } @@ -464,12 +465,13 @@ public class ImgUtil { /** * 图像切割(指定切片的行数和列数),默认RGB模式 * - * @param srcImage 源图像,如果非{@link BufferedImage},则默认使用RGB模式 - * @param destDir 切片目标文件夹 - * @param rows 目标切片行数。默认2,必须是范围 [1, 20] 之内 - * @param cols 目标切片列数。默认2,必须是范围 [1, 20] 之内 + * @param srcImage 源图像,如果非{@link BufferedImage},则默认使用RGB模式 + * @param destDir 切片目标文件夹 + * @param formatName 格式名称,即图片格式后缀 + * @param rows 目标切片行数。默认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()) { FileUtil.mkdir(destDir); } else if (false == destDir.isDirectory()) { @@ -497,7 +499,7 @@ public class ImgUtil { for (int j = 0; j < cols; j++) { 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) { @@ -1359,10 +1361,10 @@ public class ImgUtil { /** * 根据文字创建透明背景的PNG图片 * - * @param str 文字 - * @param font 字体{@link Font} - * @param fontColor 字体颜色,默认黑色 - * @param out 图片输出地 + * @param str 文字 + * @param font 字体{@link Font} + * @param fontColor 字体颜色,默认黑色 + * @param out 图片输出地 * @throws IORuntimeException IO异常 */ public static void createTransparentImage(String str, Font font, Color fontColor, ImageOutputStream out) throws IORuntimeException { @@ -2072,7 +2074,7 @@ public class ImgUtil { r = (pixel & 0xff0000) >> 16; g = (pixel & 0xff00) >> 8; b = (pixel & 0xff); - if(matchFilters(r, g, b, rgbFilters)){ + if (matchFilters(r, g, b, rgbFilters)) { continue; } countMap.merge(r + "-" + g + "-" + b, 1L, Long::sum); @@ -2100,13 +2102,14 @@ public class ImgUtil { /** * 给定RGB是否匹配过滤器中任何一个RGB颜色 - * @param r R - * @param g G - * @param b B + * + * @param r R + * @param g G + * @param b B * @param rgbFilters 颜色过滤器 * @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) { for (final int[] rgbFilter : rgbFilters) { if (r == rgbFilter[0] && g == rgbFilter[1] && b == rgbFilter[2]) { diff --git a/hutool-swing/src/test/java/cn/hutool/swing/img/ImgUtilTest.java b/hutool-swing/src/test/java/cn/hutool/swing/img/ImgUtilTest.java index 91763b9dd..832fee333 100755 --- a/hutool-swing/src/test/java/cn/hutool/swing/img/ImgUtilTest.java +++ b/hutool-swing/src/test/java/cn/hutool/swing/img/ImgUtilTest.java @@ -89,7 +89,7 @@ public class ImgUtilTest { @Test @Ignore 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