diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/array/ArrayUtil.java b/hutool-core/src/main/java/cn/hutool/v7/core/array/ArrayUtil.java index 8662bf3418..3c24f92ea7 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/array/ArrayUtil.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/array/ArrayUtil.java @@ -587,6 +587,9 @@ public class ArrayUtil extends PrimitiveArrayUtil { * @since 3.2.2 */ public static Class getArrayType(final Class componentType) { + if(null == componentType) { + return null; + } return Array.newInstance(componentType, 0).getClass(); } diff --git a/hutool-core/src/test/java/cn/hutool/v7/core/array/ArrayUtilSubGenericTest.java b/hutool-core/src/test/java/cn/hutool/v7/core/array/ArrayUtilSubGenericTest.java new file mode 100644 index 0000000000..dcec6aa1bf --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/v7/core/array/ArrayUtilSubGenericTest.java @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2013-2025 Hutool Team and hutool.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hutool.v7.core.array; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * {@link ArrayUtil} sub方法泛型版本单元测试 + * 专门测试泛型版本的 sub 方法: + * - sub(A array, int beginInclude, int endExclude) + * - sub(A array, int beginInclude, int endExclude, int step) + */ +public class ArrayUtilSubGenericTest { + + // region === 测试 sub(A array, int beginInclude, int endExclude) === + + @Test + public void testSubGeneric_withStringArray() { + // 测试正常截取 + final String[] array = {"a", "b", "c", "d", "e"}; + final String[] result = ArrayUtil.sub(array, 1, 4); + assertArrayEquals(new String[]{"b", "c", "d"}, result); + + // 测试空数组 + final String[] emptyArray = {}; + final String[] emptyResult = ArrayUtil.sub(emptyArray, 0, 0); + assertArrayEquals(new String[]{}, emptyResult); + + // 测试边界情况 + final String[] fullCopy = ArrayUtil.sub(array, 0, 5); + assertArrayEquals(new String[]{"a", "b", "c", "d", "e"}, fullCopy); + + // 测试超出范围 + final String[] beyondEnd = ArrayUtil.sub(array, 3, 10); + assertArrayEquals(new String[]{"d", "e"}, beyondEnd); + + // 测试负索引 + final String[] negativeStart = ArrayUtil.sub(array, -4, 4); + assertArrayEquals(new String[]{"b", "c", "d"}, negativeStart); + + final String[] negativeEnd = ArrayUtil.sub(array, 1, -1); + assertArrayEquals(new String[]{"b", "c", "d"}, negativeEnd); + } + + @Test + public void testSubGeneric_withIntegerArray() { + // 测试整型数组 + final Integer[] array = {1, 2, 3, 4, 5}; + final Integer[] result = ArrayUtil.sub(array, 1, 4); + assertArrayEquals(new Integer[]{2, 3, 4}, result); + + // 测试单个元素 + final Integer[] singleResult = ArrayUtil.sub(array, 0, 1); + assertArrayEquals(new Integer[]{1}, singleResult); + + // 测试反转索引 + final Integer[] reversed = ArrayUtil.sub(array, 4, 1); + assertArrayEquals(new Integer[]{2, 3, 4}, reversed); + + // 测试负索引 + final Integer[] negativeResult = ArrayUtil.sub(array, -3, -1); + assertArrayEquals(new Integer[]{3, 4}, negativeResult); + } + + @Test + public void testSubGeneric_withObjectArray() { + // 测试混合类型对象数组 + final Object[] array = {"string", 123, 45.67, true, 'c'}; + final Object[] result = ArrayUtil.sub(array, 1, 4); + assertArrayEquals(new Object[]{123, 45.67, true}, result); + + // 测试单元素截取 + final Object[] singleResult = ArrayUtil.sub(array, 2, 3); + assertArrayEquals(new Object[]{45.67}, singleResult); + } + + @Test + public void testSubGeneric_withPrimitiveArrays() { + // 测试 int 数组 + final int[] intArray = {1, 2, 3, 4, 5}; + final int[] intResult = ArrayUtil.sub(intArray, 1, 4); + assertArrayEquals(new int[]{2, 3, 4}, intResult); + + // 测试 double 数组 + final double[] doubleArray = {1.1, 2.2, 3.3, 4.4}; + final double[] doubleResult = ArrayUtil.sub(doubleArray, 0, 2); + assertArrayEquals(new double[]{1.1, 2.2}, doubleResult, 0.001); + + // 测试 boolean 数组 + final boolean[] boolArray = {true, false, true, false}; + final boolean[] boolResult = ArrayUtil.sub(boolArray, 1, 3); + assertArrayEquals(new boolean[]{false, true}, boolResult); + + // 测试 char 数组 + final char[] charArray = {'a', 'b', 'c', 'd'}; + final char[] charResult = ArrayUtil.sub(charArray, 2, 4); + assertArrayEquals(new char[]{'c', 'd'}, charResult); + } + + @Test + public void testSubGeneric_edgeCases() { + // 测试空数组边界 + final String[] emptyArray = {}; + final String[] result1 = ArrayUtil.sub(emptyArray, 0, 0); + assertArrayEquals(new String[]{}, result1); + + final String[] result2 = ArrayUtil.sub(emptyArray, 1, 3); + assertArrayEquals(new String[]{}, result2); + + // 测试单元素数组 + final String[] singleArray = {"only"}; + final String[] singleResult = ArrayUtil.sub(singleArray, 0, 1); + assertArrayEquals(new String[]{"only"}, singleResult); + + final String[] beyondSingle = ArrayUtil.sub(singleArray, 0, 5); + assertArrayEquals(new String[]{"only"}, beyondSingle); + + final String[] emptyFromSingle = ArrayUtil.sub(singleArray, 1, 1); + assertArrayEquals(new String[]{}, emptyFromSingle); + + // 测试索引翻转 + final Integer[] array = {1, 2, 3, 4}; + final Integer[] reversed = ArrayUtil.sub(array, 3, 0); + assertArrayEquals(new Integer[]{1, 2, 3}, reversed); + } + + @Test + public void testSubGeneric_outOfBounds() { + // 测试索引超出范围的情况 + final String[] array = {"a", "b", "c"}; + + // 起始位置超出数组长度 + final String[] result1 = ArrayUtil.sub(array, 5, 10); + assertArrayEquals(new String[]{}, result1); + + // 结束位置超过数组长度但起始位置有效 + final String[] result2 = ArrayUtil.sub(array, 1, 10); + assertArrayEquals(new String[]{"b", "c"}, result2); + } + + // endregion + + // region === 测试 sub(A array, int beginInclude, int endExclude, int step) === + + @Test + public void testSubGenericWithStep_basicFunctionality() { + // 测试基本步进功能 + final String[] array = {"a", "b", "c", "d", "e", "f", "g"}; + + // 步进为1(正常截取) + final String[] step1 = ArrayUtil.sub(array, 1, 6, 1); + assertArrayEquals(new String[]{"b", "c", "d", "e", "f"}, step1); + + // 步进为2(隔一个取一个) + final String[] step2 = ArrayUtil.sub(array, 0, 7, 2); + assertArrayEquals(new String[]{"a", "c", "e", "g"}, step2); + + // 步进为3(隔两个取一个) + final String[] step3 = ArrayUtil.sub(array, 0, 7, 3); + assertArrayEquals(new String[]{"a", "d", "g"}, step3); + } + + @Test + public void testSubGenericWithStep_variousSteps() { + // 测试不同的步进值 + final Integer[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + // 步进为2 + final Integer[] step2 = ArrayUtil.sub(array, 0, 10, 2); + assertArrayEquals(new Integer[]{1, 3, 5, 7, 9}, step2); + + // 步进为3 + final Integer[] step3 = ArrayUtil.sub(array, 1, 10, 3); + assertArrayEquals(new Integer[]{2, 5, 8}, step3); + + // 步进为4 + final Integer[] step4 = ArrayUtil.sub(array, 2, 9, 4); + assertArrayEquals(new Integer[]{3, 7}, step4); + + // 步进为5 + final Integer[] step5 = ArrayUtil.sub(array, 0, 10, 5); + assertArrayEquals(new Integer[]{1, 6}, step5); + } + + @Test + public void testSubGenericWithStep_edgeCases() { + // 测试边界情况 + final String[] array = {"a", "b", "c", "d"}; + + // 步进大于数组长度 + final String[] largeStep = ArrayUtil.sub(array, 0, 4, 10); + assertArrayEquals(new String[]{"a"}, largeStep); + + // 空结果(起始位置等于结束位置) + final String[] empty = ArrayUtil.sub(array, 2, 2, 1); + assertArrayEquals(new String[]{}, empty); + + // 单元素结果 + final String[] single = ArrayUtil.sub(array, 1, 4, 3); + assertArrayEquals(new String[]{"b"}, single); + + // 负索引 + final Integer[] intArray = {1, 2, 3, 4, 5}; + final Integer[] negativeIndex = ArrayUtil.sub(intArray, -3, -1, 1); + assertArrayEquals(new Integer[]{3, 4}, negativeIndex); + } + + @Test + public void testSubGenericWithStep_primitiveArrays() { + // 测试基本类型数组 + final int[] intArray = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100}; + + // 基本步进测试 + final int[] step2 = ArrayUtil.sub(intArray, 0, 10, 2); + assertArrayEquals(new int[]{10, 30, 50, 70, 90}, step2); + + final int[] step3 = ArrayUtil.sub(intArray, 1, 8, 3); + assertArrayEquals(new int[]{20, 50, 80}, step3); + + // 测试 double 数组 + final double[] doubleArray = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6}; + final double[] doubleStep = ArrayUtil.sub(doubleArray, 1, 6, 2); + assertArrayEquals(new double[]{2.2, 4.4, 6.6}, doubleStep, 0.001); + } + + @Test + public void testSubGenericWithStep_invalidStep() { + // 测试无效步进值 - 根据 ArrayWrapper.getSub 实现,step <= 1 会被设为 1 + final String[] array = {"a", "b", "c"}; + + // 步进为0 - 应该被设为1 + final String[] step0 = ArrayUtil.sub(array, 0, 3, 0); + assertArrayEquals(new String[]{"a", "b", "c"}, step0); + + // 负步进 - 应该被设为1 + final String[] negativeStep = ArrayUtil.sub(array, 0, 3, -1); + assertArrayEquals(new String[]{"a", "b", "c"}, negativeStep); + + // 步进为1 - 正常情况 + final String[] step1 = ArrayUtil.sub(array, 0, 3, 1); + assertArrayEquals(new String[]{"a", "b", "c"}, step1); + } + + @Test + public void testSubGenericWithStep_reversedIndexes() { + // 测试索引顺序颠倒的情况 + final Integer[] array = {1, 2, 3, 4, 5}; + + // 正常顺序 + final Integer[] normal = ArrayUtil.sub(array, 1, 4, 1); + assertArrayEquals(new Integer[]{2, 3, 4}, normal); + + // 索引颠倒 - 应该自动纠正为升序 + final Integer[] reversed = ArrayUtil.sub(array, 4, 1, 1); + assertArrayEquals(new Integer[]{2, 3, 4}, reversed); + + // 步进为2的颠倒索引 + final Integer[] reversedStep2 = ArrayUtil.sub(array, 4, 1, 2); + assertArrayEquals(new Integer[]{2, 4}, reversedStep2); + } + + @Test + public void testSubGenericWithStep_emptyAndSmallArrays() { + // 测试空数组和小数组 + final String[] emptyArray = {}; + + // 空数组的各种步进 + final String[] emptyResult1 = ArrayUtil.sub(emptyArray, 0, 0, 1); + assertArrayEquals(new String[]{}, emptyResult1); + + final String[] emptyResult2 = ArrayUtil.sub(emptyArray, 0, 5, 2); + assertArrayEquals(new String[]{}, emptyResult2); + + // 单元素数组 + final String[] singleArray = {"only"}; + final String[] singleResult1 = ArrayUtil.sub(singleArray, 0, 1, 1); + assertArrayEquals(new String[]{"only"}, singleResult1); + + final String[] singleResult2 = ArrayUtil.sub(singleArray, 0, 1, 2); + assertArrayEquals(new String[]{"only"}, singleResult2); + + // 双元素数组 + final String[] doubleArray = {"first", "second"}; + final String[] doubleResult1 = ArrayUtil.sub(doubleArray, 0, 2, 1); + assertArrayEquals(new String[]{"first", "second"}, doubleResult1); + + final String[] doubleResult2 = ArrayUtil.sub(doubleArray, 0, 2, 2); + assertArrayEquals(new String[]{"first"}, doubleResult2); + } + + @Test + public void testSubGeneric_nullInput() { + // 测试空指针输入 + assertThrows(IllegalArgumentException.class, () -> { + ArrayUtil.sub((String[]) null, 0, 1); + }); + + assertThrows(IllegalArgumentException.class, () -> { + ArrayUtil.sub((String[]) null, 0, 1, 1); + }); + } + + // endregion +} diff --git a/hutool-core/src/test/java/cn/hutool/v7/core/array/ArrayUtilTest.java b/hutool-core/src/test/java/cn/hutool/v7/core/array/ArrayUtilTest.java index 822e95f6d9..a1ce0c1db5 100644 --- a/hutool-core/src/test/java/cn/hutool/v7/core/array/ArrayUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/v7/core/array/ArrayUtilTest.java @@ -1194,4 +1194,247 @@ public class ArrayUtilTest { assertNotEquals(Arrays.toString(initialArray), Arrays.toString(shuffledArray)); } + + @Test + public void swapTest() { + // 正常交换场景 + final String[] array = {"a", "b", "c", "d"}; + final String[] swapped = ArrayUtil.swap(array, 1, 2); + + // 验证交换后的数组内容 + assertArrayEquals(new String[]{"a", "c", "b", "d"}, swapped); + // 验证返回的是同一个数组对象 + assertSame(array, swapped); + // 验证原数组也被修改 + assertArrayEquals(new String[]{"a", "c", "b", "d"}, array); + } + + @Test + public void swapTestBoundaryIndices() { + // 边界索引交换:第一个和最后一个元素 + final Integer[] array = {1, 2, 3, 4, 5}; + final Integer[] swapped = ArrayUtil.swap(array, 0, 4); + + assertArrayEquals(new Integer[]{5, 2, 3, 4, 1}, swapped); + assertSame(array, swapped); + } + + @Test + public void swapTestSameIndex() { + // 相同索引交换,数组应保持不变 + final String[] array = {"x", "y", "z"}; + final String[] swapped = ArrayUtil.swap(array, 1, 1); + + assertArrayEquals(new String[]{"x", "y", "z"}, swapped); + assertSame(array, swapped); + } + + @Test + public void swapTestEmptyArray() { + // 空数组应该抛出异常 + final String[] emptyArray = {}; + final IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + () -> ArrayUtil.swap(emptyArray, 0, 1)); + + assertEquals("Array must not empty !", exception.getMessage()); + } + + @Test + public void swapTestNullArray() { + // null数组应该抛出异常 + final String[] nullArray = null; + final IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + () -> ArrayUtil.swap(nullArray, 0, 1)); + + assertEquals("Array must not empty !", exception.getMessage()); + } + + @Test + public void swapTestNegativeIndex() { + // 负索引应该抛出异常 + final Integer[] array = {1, 2, 3}; + final ArrayIndexOutOfBoundsException exception = assertThrows(ArrayIndexOutOfBoundsException.class, + () -> ArrayUtil.swap(array, -1, 1)); + + assertTrue(exception.getMessage().contains("-1")); + } + + @Test + public void swapTestIndexOutOfBounds() { + // 越界索引应该抛出异常 + final String[] array = {"a", "b", "c"}; + final ArrayIndexOutOfBoundsException exception = assertThrows(ArrayIndexOutOfBoundsException.class, + () -> ArrayUtil.swap(array, 0, 5)); + + assertTrue(exception.getMessage().contains("5")); + } + + @Test + public void swapTestMultipleTypes() { + // 测试不同类型数组的交换 + final Integer[] intArray = {1, 2, 3}; + final Integer[] swappedInt = ArrayUtil.swap(intArray, 0, 2); + assertArrayEquals(new Integer[]{3, 2, 1}, swappedInt); + + final Double[] doubleArray = {1.1, 2.2, 3.3}; + final Double[] swappedDouble = ArrayUtil.swap(doubleArray, 1, 2); + assertArrayEquals(new Double[]{1.1, 3.3, 2.2}, swappedDouble); + + final Boolean[] boolArray = {true, false, true}; + final Boolean[] swappedBool = ArrayUtil.swap(boolArray, 0, 1); + assertArrayEquals(new Boolean[]{false, true, true}, swappedBool); + } + + // region ----- getComponentType tests + + @Test + public void getComponentTypeObjectTestWithObjectArray() { + // 测试 Object 数组 + final Object[] objectArray = new Object[]{"test", 123}; + final Class result = ArrayUtil.getComponentType(objectArray); + assertEquals(Object.class, result, "Object[] 应返回 Object.class"); + } + + @Test + public void getComponentTypeObjectTestWithStringArray() { + // 测试 String 数组 + final String[] stringArray = new String[]{"a", "b", "c"}; + final Class result = ArrayUtil.getComponentType(stringArray); + assertEquals(String.class, result, "String[] 应返回 String.class"); + } + + @Test + public void getComponentTypeObjectTestWithPrimitiveIntArray() { + // 测试基本类型 int 数组 + final int[] intArray = new int[]{1, 2, 3}; + final Class result = ArrayUtil.getComponentType(intArray); + assertEquals(int.class, result, "int[] 应返回 int.class"); + } + + @Test + public void getComponentTypeObjectTestWithIntegerArray() { + // 测试包装类型 Integer 数组 + final Integer[] integerArray = new Integer[]{1, 2, 3}; + final Class result = ArrayUtil.getComponentType(integerArray); + assertEquals(Integer.class, result, "Integer[] 应返回 Integer.class"); + } + + @Test + public void getComponentTypeObjectTestWithNonArrayObject() { + // 测试非数组对象 + final String nonArray = "not an array"; + final Class result = ArrayUtil.getComponentType(nonArray); + assertNull(result, "非数组对象应返回 null"); + } + + @Test + public void getComponentTypeObjectTestWithEmptyArray() { + // 测试空数组 + final String[] emptyArray = new String[0]; + final Class result = ArrayUtil.getComponentType(emptyArray); + assertEquals(String.class, result, "空 String 数组应返回 String.class"); + } + + @Test + public void getComponentTypeObjectTestWithMultiDimensionalArray() { + // 测试多维数组 + final int[][] multiDimArray = new int[2][3]; + final Class result = ArrayUtil.getComponentType(multiDimArray); + assertEquals(int[].class, result, "int[][] 应返回 int[].class"); + } + + @Test + public void getComponentTypeClassTestWithObjectArrayClass() { + // 测试 Object 数组 Class + final Class result = ArrayUtil.getComponentType(Object[].class); + assertEquals(Object.class, result, "Object[].class 应返回 Object.class"); + } + + @Test + public void getComponentTypeClassTestWithStringArrayClass() { + // 测试 String 数组 Class + final Class result = ArrayUtil.getComponentType(String[].class); + assertEquals(String.class, result, "String[].class 应返回 String.class"); + } + + @Test + public void getComponentTypeClassTestWithPrimitiveIntArrayClass() { + // 测试基本类型 int 数组 Class + final Class result = ArrayUtil.getComponentType(int[].class); + assertEquals(int.class, result, "int[].class 应返回 int.class"); + } + + @Test + public void getComponentTypeClassTestWithIntegerArrayClass() { + // 测试包装类型 Integer 数组 Class + final Class result = ArrayUtil.getComponentType(Integer[].class); + assertEquals(Integer.class, result, "Integer[].class 应返回 Integer.class"); + } + + @Test + public void getComponentTypeClassTestWithNonArrayClass() { + // 测试非数组 Class + final Class result = ArrayUtil.getComponentType(String.class); + assertNull(result, "String.class 应返回 null"); + } + + @Test + public void getComponentTypeClassTestWithMultiDimensionalArrayClass() { + // 测试多维数组 Class + final Class result = ArrayUtil.getComponentType(int[][].class); + assertEquals(int[].class, result, "int[][].class 应返回 int[].class"); + } + + @Test + public void getComponentTypeClassTestWithPrimitiveArrayType() { + // 测试所有基本类型数组 + assertEquals(boolean.class, ArrayUtil.getComponentType(boolean[].class)); + assertEquals(byte.class, ArrayUtil.getComponentType(byte[].class)); + assertEquals(char.class, ArrayUtil.getComponentType(char[].class)); + assertEquals(short.class, ArrayUtil.getComponentType(short[].class)); + assertEquals(int.class, ArrayUtil.getComponentType(int[].class)); + assertEquals(long.class, ArrayUtil.getComponentType(long[].class)); + assertEquals(float.class, ArrayUtil.getComponentType(float[].class)); + assertEquals(double.class, ArrayUtil.getComponentType(double[].class)); + } + + @Test + public void getComponentTypeClassTestWithCustomObjectArray() { + // 测试自定义对象数组 + final Class result = ArrayUtil.getComponentType(ArrayUtil[].class); + assertEquals(ArrayUtil.class, result, "ArrayUtil[].class 应返回 ArrayUtil.class"); + } + // endregion + + // region ----- getArrayType tests + @Test + void testGetArrayTypeForPrimitive() { + assertEquals(int[].class, ArrayUtil.getArrayType(int.class)); + assertEquals(double[].class, ArrayUtil.getArrayType(double.class)); + assertEquals(boolean[].class, ArrayUtil.getArrayType(boolean.class)); + } + + @Test + void testGetArrayTypeForObject() { + assertEquals(String[].class, ArrayUtil.getArrayType(String.class)); + assertEquals(Integer[].class, ArrayUtil.getArrayType(Integer.class)); + } + + @Test + void testGetArrayTypeForInterface() { + assertEquals(Runnable[].class, ArrayUtil.getArrayType(Runnable.class)); + assertEquals(Comparable[].class, ArrayUtil.getArrayType(Comparable.class)); + } + + @Test + void testGetArrayTypeForAbstractClass() { + assertEquals(Number[].class, ArrayUtil.getArrayType(Number.class)); + } + + @Test + void testGetArrayTypeForNull() { + assertNull(ArrayUtil.getArrayType(null)); + } + // endregion } +