From 55fa1812a9b5d24337569f2c8fed30e27111d8c9 Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Wed, 31 Aug 2022 13:22:00 +0800 Subject: [PATCH] fix docs and test cases --- .../java/cn/hutool/core/util/ObjUtil.java | 176 +++++++++-------- .../java/cn/hutool/core/util/ObjUtilTest.java | 183 ++++++++++++++---- 2 files changed, 241 insertions(+), 118 deletions(-) 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..81a45da6b 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}: + *

* * @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属性,其他可遍历对象遍历计算长度
- * 支持的类型包括: + *

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

* * @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}。
+ * 支持类型包括: *

* * @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
-	 * 
+ * 判断指定对象是否为空,支持类型包括: + * * * @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}接口,调用其{@link 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},则返回{@link 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/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 {}; + }