diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/lang/mutable/Mutable.java b/hutool-core/src/main/java/org/dromara/hutool/core/lang/mutable/Mutable.java index b6ef0d702..e67c8b357 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/lang/mutable/Mutable.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/lang/mutable/Mutable.java @@ -12,14 +12,110 @@ package org.dromara.hutool.core.lang.mutable; +import org.dromara.hutool.core.lang.Opt; + +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; + /** - * 提供可变值类型接口 + *

提供可变值类型接口
+ * + * 相较于{@link Opt}或{@link java.util.Optional},该所有实现类中的方法都不区分值是否为{@code null}, + * 因此在使用前需要自行判断值是否为{@code null}, + * 确保不会因为{@code null}值而抛出{@link NullPointerException}的情况。 * * @param 值得类型 * @since 3.0.1 */ public interface Mutable { + // ==================== factory methods ==================== + + /** + * 创建一个{@link MutableBool}对象 + * + * @param value 值 + * @return {@link MutableBool} + */ + static MutableBool of(final boolean value) { + return new MutableBool(value); + } + + /** + * 创建一个{@link MutableByte}对象 + * + * @param value 值 + * @return {@link MutableByte} + */ + static MutableByte of(final byte value) { + return new MutableByte(value); + } + + /** + * 创建一个{@link MutableFloat}对象 + * + * @param value 值 + * @return {@link MutableFloat} + */ + static MutableFloat of(final float value) { + return new MutableFloat(value); + } + + /** + * 创建一个{@link MutableInt}对象 + * + * @param value 值 + * @return {@link MutableInt} + */ + static MutableInt of(final int value) { + return new MutableInt(value); + } + + /** + * 创建一个{@link MutableLong}对象 + * + * @param value 值 + * @return {@link MutableLong} + */ + static MutableLong of(final long value) { + return new MutableLong(value); + } + + /** + * 创建一个{@link MutableDouble}对象 + * + * @param value 值 + * @return {@link MutableDouble} + */ + static MutableDouble of(final double value) { + return new MutableDouble(value); + } + + /** + * 创建一个{@link MutableShort}对象 + * + * @param value 值 + * @return {@link MutableShort} + */ + static MutableShort of(final short value) { + return new MutableShort(value); + } + + /** + * 创建一个{@link MutableObj}对象 + * + * @param value 值 + * @return {@link MutableObj} + */ + static MutableObj of(final T value) { + return new MutableObj<>(value); + } + + // ==================== base methods ==================== + /** * 获得原始值 * @return 原始值 @@ -32,4 +128,57 @@ public interface Mutable { */ void set(T value); + /** + * 根据操作修改值 + * + * @param operator 操作 + * @return 值 + */ + default Mutable map(final UnaryOperator operator) { + set(operator.apply(get())); + return this; + } + + /** + * 检查并操作值 + * + * @param consumer 操作 + * @return 当前对象 + */ + default Mutable peek(final Consumer consumer) { + consumer.accept(get()); + return this; + } + + /** + * 检查值是否满足条件 + * + * @param predicate 条件 + * @return 是否满足条件 + */ + default boolean test(final Predicate predicate) { + return predicate.test(get()); + } + + /** + * 获取值,并将值转换为{@link Opt} + * + * @return {@link Opt} + */ + default Opt toOpt() { + return to(Opt::ofNullable); + } + + /** + * 获取值,并将值转换为指定类型。
+ * 注意,值为null时,转换函数依然会被调用。 + * + * @param function 转换函数 + * @param 转换后的类型 + * @return 转换后的值 + */ + default R to(final Function function) { + Objects.requireNonNull(function); + return function.apply(get()); + } } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/lang/mutable/MutableObj.java b/hutool-core/src/main/java/org/dromara/hutool/core/lang/mutable/MutableObj.java index 2a87e8a02..d6e871447 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/lang/mutable/MutableObj.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/lang/mutable/MutableObj.java @@ -15,6 +15,7 @@ package org.dromara.hutool.core.lang.mutable; import org.dromara.hutool.core.util.ObjUtil; import java.io.Serializable; +import java.util.Objects; /** * 可变{@code Object} @@ -82,7 +83,7 @@ public class MutableObj implements Mutable, Serializable{ @Override public int hashCode() { - return value == null ? 0 : value.hashCode(); + return Objects.hashCode(value); } // ----------------------------------------------------------------------- diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/BaseMutableTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/BaseMutableTest.java new file mode 100644 index 000000000..8826a5c04 --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/BaseMutableTest.java @@ -0,0 +1,129 @@ +package org.dromara.hutool.core.lang.mutable; + +import org.dromara.hutool.core.text.StrValidator; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Objects; + +/** + * base test for {@link Mutable} implementations. + * + * @author huangchengxing + */ +abstract class BaseMutableTest> { + + /** + * 创建一个值,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + abstract V getValue1(); + + /** + * 创建一个值,与{@link #getValue1()}不同,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + abstract V getValue2(); + + /** + * 创建一个{@link Mutable} + * + * @param value 值 + * @return 值 + */ + abstract M getMutable(V value); + + @Test + void testOf() { + Assertions.assertInstanceOf(MutableBool.class, Mutable.of(true)); + Assertions.assertInstanceOf(MutableByte.class, Mutable.of((byte) 1)); + Assertions.assertInstanceOf(MutableDouble.class, Mutable.of(1.0D)); + Assertions.assertInstanceOf(MutableFloat.class, Mutable.of(1.0F)); + Assertions.assertInstanceOf(MutableInt.class, Mutable.of(1)); + Assertions.assertInstanceOf(MutableLong.class, Mutable.of(1L)); + Assertions.assertInstanceOf(MutableObj.class, Mutable.of(new Object())); + Assertions.assertInstanceOf(MutableShort.class, Mutable.of((short) 1)); + } + + @Test + void testGet() { + Mutable mutableObj = getMutable(getValue1()); + V value = mutableObj.get(); + Assertions.assertEquals(getValue1(), value); + } + + @Test + void testSet() { + Mutable mutableObj = getMutable(getValue2()); + mutableObj.set(getValue2()); + V value = mutableObj.get(); + Assertions.assertEquals(getValue2(), value); + } + + @Test + void testTo() { + Mutable mutableObj = getMutable(getValue1()); + String value = mutableObj.to(String::valueOf); + Assertions.assertEquals(String.valueOf(getValue1()), value); + } + + @Test + void testToOpt() { + Mutable mutableObj = getMutable(getValue1()); + V value = mutableObj.toOpt().get(); + Assertions.assertEquals(getValue1(), value); + } + + @Test + void testMap() { + Mutable mutableObj = getMutable(getValue1()); + V value = mutableObj.map(v -> getValue2()).get(); + Assertions.assertEquals(getValue2(), value); + } + + @Test + void testTest() { + Mutable mutableObj = getMutable(getValue1()); + Assertions.assertTrue(mutableObj.test(Objects::nonNull)); + } + + @Test + void testPeek() { + Mutable m1 = getMutable(getValue1()); + Mutable m2 = getMutable(getValue2()); + m1.peek(m2::set); + Assertions.assertEquals(getValue1(), m2.get()); + } + + @Test + void testHashCode() { + V value = getValue1(); + Mutable mutableObj = new MutableObj<>(value); + Assertions.assertEquals(value.hashCode(), mutableObj.hashCode()); + mutableObj.set(null); + Assertions.assertEquals(0, mutableObj.hashCode()); + } + + @Test + void testEquals() { + V value = getValue1(); + Mutable mutableObj = new MutableObj<>(value); + Assertions.assertNotEquals(value, mutableObj); + Assertions.assertEquals(mutableObj, mutableObj); + Assertions.assertEquals(mutableObj, new MutableObj<>(value)); + Assertions.assertNotEquals(mutableObj, new MutableObj<>(null)); + Assertions.assertNotEquals(mutableObj, null); + Assertions.assertNotEquals(mutableObj, value); + } + + @Test + void testToString() { + V value = getValue1(); + Mutable mutableObj = new MutableObj<>(value); + Assertions.assertEquals(value.toString(), mutableObj.toString()); + mutableObj.set(null); + Assertions.assertEquals(StrValidator.NULL, mutableObj.toString()); + } +} diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableBoolTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableBoolTest.java new file mode 100644 index 000000000..879a23c28 --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableBoolTest.java @@ -0,0 +1,40 @@ +package org.dromara.hutool.core.lang.mutable; + +/** + * test for {@link MutableBool} + * + * @author huangchengxing + */ +public class MutableBoolTest extends BaseMutableTest { + + /** + * 创建一个值 + * + * @return 值 + */ + @Override + Boolean getValue1() { + return Boolean.TRUE; + } + + /** + * 创建一个值 + * + * @return 值 + */ + @Override + Boolean getValue2() { + return Boolean.FALSE; + } + + /** + * 创建一个{@link Mutable} + * + * @param value 值 + * @return 值 + */ + @Override + MutableBool getMutable(Boolean value) { + return new MutableBool(value); + } +} diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableByteTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableByteTest.java new file mode 100644 index 000000000..2e30f5d72 --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableByteTest.java @@ -0,0 +1,38 @@ +package org.dromara.hutool.core.lang.mutable; + +/** + * @author huangchengxing + */ +public class MutableByteTest extends BaseMutableTest { + + /** + * 创建一个值,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + Number getValue1() { + return Byte.MAX_VALUE; + } + + /** + * 创建一个值,与{@link #getValue1()}不同,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + Number getValue2() { + return Byte.MIN_VALUE; + } + + /** + * 创建一个{@link Mutable} + * + * @param value 值 + * @return 值 + */ + @Override + MutableByte getMutable(Number value) { + return new MutableByte(value); + } +} diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableDoubleTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableDoubleTest.java new file mode 100644 index 000000000..2491dad6d --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableDoubleTest.java @@ -0,0 +1,38 @@ +package org.dromara.hutool.core.lang.mutable; + +/** + * @author huangchengxing + */ +public class MutableDoubleTest extends BaseMutableTest { + + /** + * 创建一个值,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + Number getValue1() { + return Double.MAX_VALUE; + } + + /** + * 创建一个值,与{@link #getValue1()}不同,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + Number getValue2() { + return Double.MAX_VALUE; + } + + /** + * 创建一个{@link Mutable} + * + * @param value 值 + * @return 值 + */ + @Override + MutableDouble getMutable(Number value) { + return new MutableDouble(value); + } +} diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableEntryTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableEntryTest.java new file mode 100644 index 000000000..14ae5e848 --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableEntryTest.java @@ -0,0 +1,45 @@ +package org.dromara.hutool.core.lang.mutable; + +import org.dromara.hutool.core.map.MapUtil; + +import java.util.Map; + +/** + * @author huangchengxing + */ +public class MutableEntryTest extends BaseMutableTest, MutableEntry> { + + private static final Map.Entry ENTRY1 = MapUtil.entry("key1", "value1"); + private static final Map.Entry ENTRY2 = MapUtil.entry("key2", "value2"); + + /** + * 创建一个值,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + Map.Entry getValue1() { + return ENTRY1; + } + + /** + * 创建一个值,与{@link #getValue1()}不同,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + Map.Entry getValue2() { + return ENTRY2; + } + + /** + * 创建一个{@link Mutable} + * + * @param value 值 + * @return 值 + */ + @Override + MutableEntry getMutable(Map.Entry value) { + return new MutableEntry<>(value.getKey(), value.getValue()); + } +} diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableFloatTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableFloatTest.java new file mode 100644 index 000000000..6f43a8538 --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableFloatTest.java @@ -0,0 +1,37 @@ +package org.dromara.hutool.core.lang.mutable; + +/** + * @author huangchengxing + */ +public class MutableFloatTest extends BaseMutableTest { + /** + * 创建一个值,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + Number getValue1() { + return Float.MAX_VALUE; + } + + /** + * 创建一个值,与{@link #getValue1()}不同,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + Number getValue2() { + return Float.MIN_VALUE; + } + + /** + * 创建一个{@link Mutable} + * + * @param value 值 + * @return 值 + */ + @Override + MutableFloat getMutable(Number value) { + return new MutableFloat(value); + } +} diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableIntTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableIntTest.java new file mode 100644 index 000000000..01ffe1750 --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableIntTest.java @@ -0,0 +1,37 @@ +package org.dromara.hutool.core.lang.mutable; + +/** + * @author huangchengxing + */ +public class MutableIntTest extends BaseMutableTest { + /** + * 创建一个值,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + Number getValue1() { + return Integer.MAX_VALUE; + } + + /** + * 创建一个值,与{@link #getValue1()}不同,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + Number getValue2() { + return Integer.MIN_VALUE; + } + + /** + * 创建一个{@link Mutable} + * + * @param value 值 + * @return 值 + */ + @Override + MutableInt getMutable(Number value) { + return new MutableInt(value); + } +} diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableLongTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableLongTest.java new file mode 100644 index 000000000..3d46f281f --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableLongTest.java @@ -0,0 +1,37 @@ +package org.dromara.hutool.core.lang.mutable; + +/** + * @author huangchengxing + */ +public class MutableLongTest extends BaseMutableTest { + /** + * 创建一个值,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + Number getValue1() { + return Long.MAX_VALUE; + } + + /** + * 创建一个值,与{@link #getValue1()}不同,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + Number getValue2() { + return Long.MIN_VALUE; + } + + /** + * 创建一个{@link Mutable} + * + * @param value 值 + * @return 值 + */ + @Override + MutableLong getMutable(Number value) { + return new MutableLong(value); + } +} diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableObjTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableObjTest.java new file mode 100644 index 000000000..af71a2eee --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableObjTest.java @@ -0,0 +1,40 @@ +package org.dromara.hutool.core.lang.mutable; + +/** + * test for {@link MutableObj} + * + * @author huangchengxing + */ +class MutableObjTest extends BaseMutableTest> { + + /** + * 创建一个值 + * + * @return 值 + */ + @Override + String getValue1() { + return "test1"; + } + + /** + * 创建一个值 + * + * @return 值 + */ + @Override + String getValue2() { + return "test2"; + } + + /** + * 创建一个{@link Mutable} + * + * @param value 值 + * @return 值 + */ + @Override + MutableObj getMutable(String value) { + return new MutableObj<>(value); + } +} diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableShortTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableShortTest.java new file mode 100644 index 000000000..a918098e8 --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableShortTest.java @@ -0,0 +1,37 @@ +package org.dromara.hutool.core.lang.mutable; + +/** + * @author huangchengxing + */ +public class MutableShortTest extends BaseMutableTest { + /** + * 创建一个值,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + Number getValue1() { + return Short.MAX_VALUE; + } + + /** + * 创建一个值,与{@link #getValue1()}不同,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + Number getValue2() { + return Short.MIN_VALUE; + } + + /** + * 创建一个{@link Mutable} + * + * @param value 值 + * @return 值 + */ + @Override + MutableShort getMutable(Number value) { + return new MutableShort(value); + } +} diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableTripleTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableTripleTest.java new file mode 100644 index 000000000..457411c68 --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/mutable/MutableTripleTest.java @@ -0,0 +1,41 @@ +package org.dromara.hutool.core.lang.mutable; + +/** + * @author huangchengxing + */ +public class MutableTripleTest extends BaseMutableTest, MutableTriple> { + + private static final MutableTriple VALUE1 = new MutableTriple<>("1", "2", "3"); + private static final MutableTriple VALUE2 = new MutableTriple<>("4", "5", "6"); + + /** + * 创建一个值,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + MutableTriple getValue1() { + return VALUE1; + } + + /** + * 创建一个值,与{@link #getValue1()}不同,且反复调用应该返回完全相同的值 + * + * @return 值 + */ + @Override + MutableTriple getValue2() { + return VALUE2; + } + + /** + * 创建一个{@link Mutable} + * + * @param value 值 + * @return 值 + */ + @Override + MutableTriple getMutable(MutableTriple value) { + return new MutableTriple<>(value.getLeft(), value.getMiddle(), value.getRight()); + } +}