From 9a2cfe36909fc1da1cc0f550a33d3c79a7318bfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8D=E5=BF=98=E5=88=9D=E5=BF=83?= Date: Wed, 25 Nov 2020 13:17:10 +0800 Subject: [PATCH 01/18] =?UTF-8?q?crypto=20=E7=9A=84=20Padding=20=E6=9E=9A?= =?UTF-8?q?=E4=B8=BE=E6=96=B0=E5=A2=9E=20PKCS7Padding=20=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hutool-crypto/src/main/java/cn/hutool/crypto/Padding.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/Padding.java b/hutool-crypto/src/main/java/cn/hutool/crypto/Padding.java index 63fbfb97cc..b9237ec37c 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/Padding.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/Padding.java @@ -23,5 +23,10 @@ public enum Padding { OAEPPadding, PKCS1Padding, PKCS5Padding, + /** + * 注意需要引入对应jar 包 + * @see cn.hutool.crypto.GlobalBouncyCastleProvider#setUseBouncyCastle + */ + PKCS7Padding, SSL3Padding } From 4512ec414b97a2e6a111958d15622d5c1bf4f12d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8D=E5=BF=98=E5=88=9D=E5=BF=83?= Date: Wed, 25 Nov 2020 13:33:28 +0800 Subject: [PATCH 02/18] =?UTF-8?q?add=20=E5=A2=9E=E5=8A=A0=E5=B9=B4?= =?UTF-8?q?=E6=9C=88=E6=A0=BC=E5=BC=8F=E5=8C=96=E5=B8=B8=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/hutool/core/date/DatePattern.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DatePattern.java b/hutool-core/src/main/java/cn/hutool/core/date/DatePattern.java index 1f54dc1def..5e7cf962d8 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DatePattern.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DatePattern.java @@ -28,6 +28,30 @@ public class DatePattern { public static final Pattern REGEX_NORM = Pattern.compile("\\d{4}-\\d{1,2}-\\d{1,2}(\\s\\d{1,2}:\\d{1,2}(:\\d{1,2})?)?(.\\d{1,3})?"); //-------------------------------------------------------------------------------------------------------------------------------- Normal + /** + * 年月格式:yyyy-MM + */ + public static final String NORM_MONTH_PATTERN = "yyyy-MM"; + /** + * 年月格式 {@link FastDateFormat}:yyyy-MM + */ + public static final FastDateFormat NORM_MONTH_FORMAT = FastDateFormat.getInstance(NORM_MONTH_PATTERN); + /** + * 年月格式 {@link FastDateFormat}:yyyy-MM + */ + public static final DateTimeFormatter NORM_MONTH_FORMATTER = DateTimeFormatter.ofPattern(NORM_MONTH_PATTERN); + /** + * 简单年月格式:yyyyMM + */ + public static final String SIMPLE_MONTH_PATTERN = "yyyyMM"; + /** + * 简单年月格式 {@link FastDateFormat}:yyyyMM + */ + public static final FastDateFormat SIMPLE_MONTH_FORMAT = FastDateFormat.getInstance(SIMPLE_MONTH_PATTERN); + /** + * 简单年月格式 {@link FastDateFormat}:yyyyMM + */ + public static final DateTimeFormatter SIMPLE_MONTH_FORMATTER = DateTimeFormatter.ofPattern(SIMPLE_MONTH_PATTERN); /** * 标准日期格式:yyyy-MM-dd */ From 8a308bd13cd98b26f43149c9e9132a16a820ee48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8D=E5=BF=98=E5=88=9D=E5=BF=83?= Date: Thu, 26 Nov 2020 18:39:24 +0800 Subject: [PATCH 03/18] =?UTF-8?q?=E5=8F=96=E6=B6=88=20padding=20=E6=8F=90?= =?UTF-8?q?=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hutool-crypto/src/main/java/cn/hutool/crypto/Padding.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/Padding.java b/hutool-crypto/src/main/java/cn/hutool/crypto/Padding.java index b9237ec37c..63fbfb97cc 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/Padding.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/Padding.java @@ -23,10 +23,5 @@ public enum Padding { OAEPPadding, PKCS1Padding, PKCS5Padding, - /** - * 注意需要引入对应jar 包 - * @see cn.hutool.crypto.GlobalBouncyCastleProvider#setUseBouncyCastle - */ - PKCS7Padding, SSL3Padding } From bc998700bb8c47aa6ee6f3d7d4c1ea70176cf8c1 Mon Sep 17 00:00:00 2001 From: fengbaoheng Date: Thu, 26 Nov 2020 20:04:27 +0800 Subject: [PATCH 04/18] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E6=97=B6=E5=BC=82=E5=B8=B8=E5=8C=85=E8=A3=85=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hutool/core/exceptions/ExceptionUtil.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/exceptions/ExceptionUtil.java b/hutool-core/src/main/java/cn/hutool/core/exceptions/ExceptionUtil.java index f0cfafec69..8472b6ff52 100644 --- a/hutool-core/src/main/java/cn/hutool/core/exceptions/ExceptionUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/exceptions/ExceptionUtil.java @@ -48,7 +48,7 @@ public class ExceptionUtil { /** * 使用运行时异常包装编译异常
* - * 如果 + * 如果传入参数已经是运行时异常,则直接返回,不再额外包装 * * @param throwable 异常 * @return 运行时异常 @@ -60,6 +60,16 @@ public class ExceptionUtil { return new RuntimeException(throwable); } + /** + * 将指定的消息包装为运行时异常 + * @param message 异常消息 + * @return 运行时异常 + * @since 5.5.2 + */ + public static RuntimeException wrapRuntime(String message){ + return new RuntimeException(message); + } + /** * 包装一个异常 * @@ -93,6 +103,15 @@ public class ExceptionUtil { throw new UndeclaredThrowableException(throwable); } + /** + * 将消息包装为运行时异常并抛出 + * @param message 异常消息 + * @since 5.5.2 + */ + public static void wrapRuntimeAndThrow(String message){ + throw new RuntimeException(message); + } + /** * 剥离反射引发的InvocationTargetException、UndeclaredThrowableException中间异常,返回业务本身的异常 * From a329a1c44c4669c8366f34e5e69a42e916e5063c Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 27 Nov 2020 02:56:08 +0800 Subject: [PATCH 05/18] add method --- CHANGELOG.md | 3 +- .../hutool/core/exceptions/ExceptionUtil.java | 81 ++++++++++--------- 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c6036887f..4c7c7f1f99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.5.2 (2020-11-25) +# 5.5.2 (2020-11-26) ### 新特性 * 【crypto 】 KeyUtil增加重载,AES构造增加重载(issue#I25NNZ@Gitee) @@ -16,6 +16,7 @@ * 【core 】 ZipUtil增加get方法 * 【cache 】 对CacheObj等变量使用volatile关键字 * 【core 】 Base64增加encodeWithoutPadding方法(issue#I26J16@Gitee) +* 【core 】 ExceptionUtil增加message消息包装为运行时异常的方法(issue#1253@Gitee) ### Bug修复 * 【cron 】 修复CronTimer可能死循环的问题(issue#1224@Github) diff --git a/hutool-core/src/main/java/cn/hutool/core/exceptions/ExceptionUtil.java b/hutool-core/src/main/java/cn/hutool/core/exceptions/ExceptionUtil.java index 8472b6ff52..8904b82482 100644 --- a/hutool-core/src/main/java/cn/hutool/core/exceptions/ExceptionUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/exceptions/ExceptionUtil.java @@ -16,15 +16,14 @@ import java.util.Map; /** * 异常工具类 - * - * @author Looly * + * @author Looly */ public class ExceptionUtil { /** * 获得完整消息,包括异常名,消息格式为:{SimpleClassName}: {ThrowableMessage} - * + * * @param e 异常 * @return 完整消息 */ @@ -37,7 +36,7 @@ public class ExceptionUtil { /** * 获得消息,调用异常类的getMessage方法 - * + * * @param e 异常 * @return 消息 */ @@ -47,9 +46,9 @@ public class ExceptionUtil { /** * 使用运行时异常包装编译异常
- * + *

* 如果传入参数已经是运行时异常,则直接返回,不再额外包装 - * + * * @param throwable 异常 * @return 运行时异常 */ @@ -62,19 +61,20 @@ public class ExceptionUtil { /** * 将指定的消息包装为运行时异常 + * * @param message 异常消息 * @return 运行时异常 * @since 5.5.2 */ - public static RuntimeException wrapRuntime(String message){ + public static RuntimeException wrapRuntime(String message) { return new RuntimeException(message); } /** * 包装一个异常 * - * @param 被包装的异常类型 - * @param throwable 异常 + * @param 被包装的异常类型 + * @param throwable 异常 * @param wrapThrowable 包装后的异常类 * @return 包装后的异常 * @since 3.3.0 @@ -90,7 +90,7 @@ public class ExceptionUtil { /** * 包装异常并重新抛出此异常
* {@link RuntimeException} 和{@link Error} 直接抛出,其它检查异常包装为{@link UndeclaredThrowableException} 后抛出 - * + * * @param throwable 异常 */ public static void wrapAndThrow(Throwable throwable) { @@ -105,16 +105,17 @@ public class ExceptionUtil { /** * 将消息包装为运行时异常并抛出 + * * @param message 异常消息 * @since 5.5.2 */ - public static void wrapRuntimeAndThrow(String message){ + public static void wrapRuntimeAndThrow(String message) { throw new RuntimeException(message); } /** * 剥离反射引发的InvocationTargetException、UndeclaredThrowableException中间异常,返回业务本身的异常 - * + * * @param wrapped 包装的异常 * @return 剥离后的异常 */ @@ -133,7 +134,7 @@ public class ExceptionUtil { /** * 获取当前栈信息 - * + * * @return 当前栈信息 */ public static StackTraceElement[] getStackElements() { @@ -154,7 +155,7 @@ public class ExceptionUtil { /** * 获取入口堆栈信息 - * + * * @return 入口堆栈信息 * @since 4.1.4 */ @@ -165,7 +166,7 @@ public class ExceptionUtil { /** * 堆栈转为单行完整字符串 - * + * * @param throwable 异常对象 * @return 堆栈转为的字符串 */ @@ -175,9 +176,9 @@ public class ExceptionUtil { /** * 堆栈转为单行完整字符串 - * + * * @param throwable 异常对象 - * @param limit 限制最大长度 + * @param limit 限制最大长度 * @return 堆栈转为的字符串 */ public static String stacktraceToOneLineString(Throwable throwable, int limit) { @@ -191,7 +192,7 @@ public class ExceptionUtil { /** * 堆栈转为完整字符串 - * + * * @param throwable 异常对象 * @return 堆栈转为的字符串 */ @@ -201,9 +202,9 @@ public class ExceptionUtil { /** * 堆栈转为完整字符串 - * + * * @param throwable 异常对象 - * @param limit 限制最大长度 + * @param limit 限制最大长度 * @return 堆栈转为的字符串 */ public static String stacktraceToString(Throwable throwable, int limit) { @@ -212,9 +213,9 @@ public class ExceptionUtil { /** * 堆栈转为完整字符串 - * - * @param throwable 异常对象 - * @param limit 限制最大长度 + * + * @param throwable 异常对象 + * @param limit 限制最大长度 * @param replaceCharToStrMap 替换字符为指定字符串 * @return 堆栈转为的字符串 */ @@ -248,8 +249,8 @@ public class ExceptionUtil { /** * 判断是否由指定异常类引起 - * - * @param throwable 异常 + * + * @param throwable 异常 * @param causeClasses 定义的引起异常的类 * @return 是否由指定异常类引起 * @since 4.1.13 @@ -261,8 +262,8 @@ public class ExceptionUtil { /** * 获取由指定异常类引起的异常 - * - * @param throwable 异常 + * + * @param throwable 异常 * @param causeClasses 定义的引起异常的类 * @return 是否由指定异常类引起 * @since 4.1.13 @@ -284,7 +285,7 @@ public class ExceptionUtil { /** * 判断指定异常是否来自或者包含指定异常 * - * @param throwable 异常 + * @param throwable 异常 * @param exceptionClass 定义的引起异常的类 * @return true 来自或者包含 * @since 4.3.2 @@ -296,9 +297,9 @@ public class ExceptionUtil { /** * 判断指定异常是否来自或者包含指定异常 * - * @param throwable 异常 + * @param throwable 异常 * @param exceptionClass 定义的引起异常的类 - * @param checkCause 判断cause + * @param checkCause 判断cause * @return true 来自或者包含 * @since 4.4.1 */ @@ -309,8 +310,8 @@ public class ExceptionUtil { /** * 转化指定异常为来自或者包含指定异常 * - * @param 异常类型 - * @param throwable 异常 + * @param 异常类型 + * @param throwable 异常 * @param exceptionClass 定义的引起异常的类 * @return 结果为null 不是来自或者包含 * @since 4.3.2 @@ -322,10 +323,10 @@ public class ExceptionUtil { /** * 转化指定异常为来自或者包含指定异常 * - * @param 异常类型 - * @param throwable 异常 + * @param 异常类型 + * @param throwable 异常 * @param exceptionClass 定义的引起异常的类 - * @param checkCause 判断cause + * @param checkCause 判断cause * @return 结果为null 不是来自或者包含 * @since 4.4.1 */ @@ -357,11 +358,11 @@ public class ExceptionUtil { /** * 获取异常链上所有异常的集合,如果{@link Throwable} 对象没有cause,返回只有一个节点的List
* 如果传入null,返回空集合 - * + * *

* 此方法来自Apache-Commons-Lang3 *

- * + * * @param throwable 异常对象,可以为null * @return 异常链中所有异常集合 * @since 4.6.2 @@ -379,11 +380,11 @@ public class ExceptionUtil { * 获取异常链中最尾端的异常,即异常最早发生的异常对象。
* 此方法通过调用{@link Throwable#getCause()} 直到没有cause为止,如果异常本身没有cause,返回异常本身
* 传入null返回也为null - * + * *

* 此方法来自Apache-Commons-Lang3 *

- * + * * @param throwable 异常对象,可能为null * @return 最尾端异常,传入null参数返回也为null */ @@ -394,7 +395,7 @@ public class ExceptionUtil { /** * 获取异常链中最尾端的异常的消息,消息格式为:{SimpleClassName}: {ThrowableMessage} - * + * * @param th 异常 * @return 消息 * @since 4.6.2 From 118dee830273a7b7699bd8bf01ec26aa108da589 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 27 Nov 2020 03:47:39 +0800 Subject: [PATCH 06/18] add const --- CHANGELOG.md | 3 ++- hutool-core/src/main/java/cn/hutool/core/date/DatePattern.java | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c7c7f1f99..342a018379 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,8 @@ * 【core 】 ZipUtil增加get方法 * 【cache 】 对CacheObj等变量使用volatile关键字 * 【core 】 Base64增加encodeWithoutPadding方法(issue#I26J16@Gitee) -* 【core 】 ExceptionUtil增加message消息包装为运行时异常的方法(issue#1253@Gitee) +* 【core 】 ExceptionUtil增加message消息包装为运行时异常的方法(pr#1253@Gitee) +* 【core 】 DatePattern增加年月格式化常量(pr#220@Gitee) ### Bug修复 * 【cron 】 修复CronTimer可能死循环的问题(issue#1224@Github) diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DatePattern.java b/hutool-core/src/main/java/cn/hutool/core/date/DatePattern.java index 5e7cf962d8..9ab3817a59 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DatePattern.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DatePattern.java @@ -40,6 +40,7 @@ public class DatePattern { * 年月格式 {@link FastDateFormat}:yyyy-MM */ public static final DateTimeFormatter NORM_MONTH_FORMATTER = DateTimeFormatter.ofPattern(NORM_MONTH_PATTERN); + /** * 简单年月格式:yyyyMM */ @@ -52,6 +53,7 @@ public class DatePattern { * 简单年月格式 {@link FastDateFormat}:yyyyMM */ public static final DateTimeFormatter SIMPLE_MONTH_FORMATTER = DateTimeFormatter.ofPattern(SIMPLE_MONTH_PATTERN); + /** * 标准日期格式:yyyy-MM-dd */ From a30356a2151d9ba8b06612d3ab9fe8b945bae9a1 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 27 Nov 2020 03:54:32 +0800 Subject: [PATCH 07/18] fix code --- hutool-core/src/main/java/cn/hutool/core/date/StopWatch.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/date/StopWatch.java b/hutool-core/src/main/java/cn/hutool/core/date/StopWatch.java index 73b0be0749..e45960a3cd 100755 --- a/hutool-core/src/main/java/cn/hutool/core/date/StopWatch.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/StopWatch.java @@ -101,7 +101,7 @@ public class StopWatch { // ------------------------------------------------------------------------------------------- Constructor end /** - * 获取{@link StopWatch} 的ID,用于多个秒表对象的区分 + * 获取StopWatch 的ID,用于多个秒表对象的区分 * * @return the ID 空字符串为 * @see #StopWatch(String) From 20ac0ce6a81d7bd4d63bc284c054e94dad9bb76f Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 27 Nov 2020 04:01:09 +0800 Subject: [PATCH 08/18] add static --- .../src/main/java/cn/hutool/core/date/StopWatch.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hutool-core/src/main/java/cn/hutool/core/date/StopWatch.java b/hutool-core/src/main/java/cn/hutool/core/date/StopWatch.java index e45960a3cd..d331bfa444 100755 --- a/hutool-core/src/main/java/cn/hutool/core/date/StopWatch.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/StopWatch.java @@ -41,6 +41,17 @@ import java.util.List; */ public class StopWatch { + /** + * 创建计时任务(秒表) + * + * @param id 用于标识秒表的唯一ID + * @return StopWatch + * @since 5.5.2 + */ + public static StopWatch create(String id){ + return new StopWatch(id); + } + /** * 秒表唯一标识,用于多个秒表对象的区分 */ From 48005d8aba1c483dd1317804ade0cde1931b4afe Mon Sep 17 00:00:00 2001 From: fengbaoheng Date: Fri, 27 Nov 2020 10:00:05 +0800 Subject: [PATCH 09/18] =?UTF-8?q?=E6=B7=BB=E5=8A=A0Shuffle=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/hutool/core/util/ArrayUtil.java | 303 ++++++++++++++++++ 1 file changed, 303 insertions(+) diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java index b3f3f77e47..f3cb96e9c1 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java @@ -22,6 +22,7 @@ import java.util.LinkedHashSet; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.Random; import java.util.function.Function; /** @@ -4022,6 +4023,308 @@ public class ArrayUtil { return max; } + + // 使用Fisher–Yates洗牌算法,以线性时间复杂度打乱数组顺序 + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static int[] shuffle(int[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static int[] shuffle(int[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static long[] shuffle(long[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static long[] shuffle(long[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static double[] shuffle(double[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static double[] shuffle(double[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static float[] shuffle(float[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static float[] shuffle(float[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static boolean[] shuffle(boolean[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static boolean[] shuffle(boolean[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static byte[] shuffle(byte[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static byte[] shuffle(byte[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static char[] shuffle(char[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static char[] shuffle(char[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static short[] shuffle(short[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static short[] shuffle(short[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param 元素类型 + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static T[] shuffle(T[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param 元素类型 + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static T[] shuffle(T[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + /** * 交换数组中两个位置的值 * From b2269226d321d2f8b699c7b3df1d598937c9a0f1 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 27 Nov 2020 10:33:14 +0800 Subject: [PATCH 10/18] fix code --- hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java b/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java index e8df41fb09..79d89eb4ac 100644 --- a/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java @@ -165,6 +165,7 @@ public class JSONUtilTest { @Test public void parseObjTest() { + // 测试转义 final JSONObject jsonObject = JSONUtil.parseObj("{\n" + " \"test\": \"\\\\地库地库\",\n" + "}"); From 633ed24564a1d210a6a04d7cd572dfb8c62337a6 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 27 Nov 2020 11:32:17 +0800 Subject: [PATCH 11/18] add util --- CHANGELOG.md | 2 + .../java/cn/hutool/core/util/ArrayUtil.java | 3019 +--------------- .../hutool/core/util/PrimitiveArrayUtil.java | 3022 +++++++++++++++++ 3 files changed, 3044 insertions(+), 2999 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/util/PrimitiveArrayUtil.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 342a018379..df9bedd5f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ * 【core 】 Base64增加encodeWithoutPadding方法(issue#I26J16@Gitee) * 【core 】 ExceptionUtil增加message消息包装为运行时异常的方法(pr#1253@Gitee) * 【core 】 DatePattern增加年月格式化常量(pr#220@Gitee) +* 【core 】 ArrayUtil增加shuffle方法(pr#1255@Github) +* 【core 】 ArrayUtil部分方法分离至PrimitiveArrayUtil ### Bug修复 * 【cron 】 修复CronTimer可能死循环的问题(issue#1224@Github) diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java index f3cb96e9c1..e8eb53e206 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java @@ -30,12 +30,7 @@ import java.util.function.Function; * * @author Looly */ -public class ArrayUtil { - - /** - * 数组中元素未找到的下标,值为-1 - */ - public static final int INDEX_NOT_FOUND = -1; +public class ArrayUtil extends PrimitiveArrayUtil{ // ---------------------------------------------------------------------- isEmpty @@ -82,86 +77,6 @@ public class ArrayUtil { return true; } - /** - * 数组是否为空 - * - * @param array 数组 - * @return 是否为空 - */ - public static boolean isEmpty(long[] array) { - return array == null || array.length == 0; - } - - /** - * 数组是否为空 - * - * @param array 数组 - * @return 是否为空 - */ - public static boolean isEmpty(int[] array) { - return array == null || array.length == 0; - } - - /** - * 数组是否为空 - * - * @param array 数组 - * @return 是否为空 - */ - public static boolean isEmpty(short[] array) { - return array == null || array.length == 0; - } - - /** - * 数组是否为空 - * - * @param array 数组 - * @return 是否为空 - */ - public static boolean isEmpty(char[] array) { - return array == null || array.length == 0; - } - - /** - * 数组是否为空 - * - * @param array 数组 - * @return 是否为空 - */ - public static boolean isEmpty(byte[] array) { - return array == null || array.length == 0; - } - - /** - * 数组是否为空 - * - * @param array 数组 - * @return 是否为空 - */ - public static boolean isEmpty(double[] array) { - return array == null || array.length == 0; - } - - /** - * 数组是否为空 - * - * @param array 数组 - * @return 是否为空 - */ - public static boolean isEmpty(float[] array) { - return array == null || array.length == 0; - } - - /** - * 数组是否为空 - * - * @param array 数组 - * @return 是否为空 - */ - public static boolean isEmpty(boolean[] array) { - return array == null || array.length == 0; - } - // ---------------------------------------------------------------------- isNotEmpty /** @@ -188,86 +103,6 @@ public class ArrayUtil { return false == isEmpty(array); } - /** - * 数组是否为非空 - * - * @param array 数组 - * @return 是否为非空 - */ - public static boolean isNotEmpty(long[] array) { - return false == isEmpty(array); - } - - /** - * 数组是否为非空 - * - * @param array 数组 - * @return 是否为非空 - */ - public static boolean isNotEmpty(int[] array) { - return false == isEmpty(array); - } - - /** - * 数组是否为非空 - * - * @param array 数组 - * @return 是否为非空 - */ - public static boolean isNotEmpty(short[] array) { - return false == isEmpty(array); - } - - /** - * 数组是否为非空 - * - * @param array 数组 - * @return 是否为非空 - */ - public static boolean isNotEmpty(char[] array) { - return false == isEmpty(array); - } - - /** - * 数组是否为非空 - * - * @param array 数组 - * @return 是否为非空 - */ - public static boolean isNotEmpty(byte[] array) { - return false == isEmpty(array); - } - - /** - * 数组是否为非空 - * - * @param array 数组 - * @return 是否为非空 - */ - public static boolean isNotEmpty(double[] array) { - return false == isEmpty(array); - } - - /** - * 数组是否为非空 - * - * @param array 数组 - * @return 是否为非空 - */ - public static boolean isNotEmpty(float[] array) { - return false == isEmpty(array); - } - - /** - * 数组是否为非空 - * - * @param array 数组 - * @return 是否为非空 - */ - public static boolean isNotEmpty(boolean[] array) { - return false == isEmpty(array); - } - /** * 是否包含{@code null}元素 * @@ -594,26 +429,6 @@ public class ArrayUtil { return newArray; } - /** - * 生成一个新的重新设置大小的数组
- * 调整大小后拷贝原数组到新数组下。扩大则占位前N个位置,其它位置补充0,缩小则截断 - * - * @param bytes 原数组 - * @param newSize 新的数组大小 - * @return 调整后的新数组 - * @since 4.6.7 - */ - public static byte[] resize(byte[] bytes, int newSize) { - if (newSize < 0) { - return bytes; - } - final byte[] newArray = new byte[newSize]; - if (newSize > 0 && isNotEmpty(bytes)) { - System.arraycopy(bytes, 0, newArray, 0, Math.min(bytes.length, newSize)); - } - return newArray; - } - /** * 生成一个新的重新设置大小的数组
* 新数组的类型为原数组的类型,调整大小后拷贝原数组到新数组下。扩大则占位前N个位置,缩小则截断 @@ -659,262 +474,6 @@ public class ArrayUtil { return result; } - /** - * 将多个数组合并在一起
- * 忽略null的数组 - * - * @param arrays 数组集合 - * @return 合并后的数组 - * @since 4.6.9 - */ - public static byte[] addAll(byte[]... arrays) { - if (arrays.length == 1) { - return arrays[0]; - } - - // 计算总长度 - int length = 0; - for (byte[] array : arrays) { - if (null != array) { - length += array.length; - } - } - - final byte[] result = new byte[length]; - length = 0; - for (byte[] array : arrays) { - if (null != array) { - System.arraycopy(array, 0, result, length, array.length); - length += array.length; - } - } - return result; - } - - /** - * 将多个数组合并在一起
- * 忽略null的数组 - * - * @param arrays 数组集合 - * @return 合并后的数组 - * @since 4.6.9 - */ - public static int[] addAll(int[]... arrays) { - if (arrays.length == 1) { - return arrays[0]; - } - - // 计算总长度 - int length = 0; - for (int[] array : arrays) { - if (null != array) { - length += array.length; - } - } - - final int[] result = new int[length]; - length = 0; - for (int[] array : arrays) { - if (null != array) { - System.arraycopy(array, 0, result, length, array.length); - length += array.length; - } - } - return result; - } - - /** - * 将多个数组合并在一起
- * 忽略null的数组 - * - * @param arrays 数组集合 - * @return 合并后的数组 - * @since 4.6.9 - */ - public static long[] addAll(long[]... arrays) { - if (arrays.length == 1) { - return arrays[0]; - } - - // 计算总长度 - int length = 0; - for (long[] array : arrays) { - if (null != array) { - length += array.length; - } - } - - final long[] result = new long[length]; - length = 0; - for (long[] array : arrays) { - if (null != array) { - System.arraycopy(array, 0, result, length, array.length); - length += array.length; - } - } - return result; - } - - /** - * 将多个数组合并在一起
- * 忽略null的数组 - * - * @param arrays 数组集合 - * @return 合并后的数组 - * @since 4.6.9 - */ - public static double[] addAll(double[]... arrays) { - if (arrays.length == 1) { - return arrays[0]; - } - - // 计算总长度 - int length = 0; - for (double[] array : arrays) { - if (null != array) { - length += array.length; - } - } - - final double[] result = new double[length]; - length = 0; - for (double[] array : arrays) { - if (null != array) { - System.arraycopy(array, 0, result, length, array.length); - length += array.length; - } - } - return result; - } - - /** - * 将多个数组合并在一起
- * 忽略null的数组 - * - * @param arrays 数组集合 - * @return 合并后的数组 - * @since 4.6.9 - */ - public static float[] addAll(float[]... arrays) { - if (arrays.length == 1) { - return arrays[0]; - } - - // 计算总长度 - int length = 0; - for (float[] array : arrays) { - if (null != array) { - length += array.length; - } - } - - final float[] result = new float[length]; - length = 0; - for (float[] array : arrays) { - if (null != array) { - System.arraycopy(array, 0, result, length, array.length); - length += array.length; - } - } - return result; - } - - /** - * 将多个数组合并在一起
- * 忽略null的数组 - * - * @param arrays 数组集合 - * @return 合并后的数组 - * @since 4.6.9 - */ - public static char[] addAll(char[]... arrays) { - if (arrays.length == 1) { - return arrays[0]; - } - - // 计算总长度 - int length = 0; - for (char[] array : arrays) { - if (null != array) { - length += array.length; - } - } - - final char[] result = new char[length]; - length = 0; - for (char[] array : arrays) { - if (null != array) { - System.arraycopy(array, 0, result, length, array.length); - length += array.length; - } - } - return result; - } - - /** - * 将多个数组合并在一起
- * 忽略null的数组 - * - * @param arrays 数组集合 - * @return 合并后的数组 - * @since 4.6.9 - */ - public static boolean[] addAll(boolean[]... arrays) { - if (arrays.length == 1) { - return arrays[0]; - } - - // 计算总长度 - int length = 0; - for (boolean[] array : arrays) { - if (null != array) { - length += array.length; - } - } - - final boolean[] result = new boolean[length]; - length = 0; - for (boolean[] array : arrays) { - if (null != array) { - System.arraycopy(array, 0, result, length, array.length); - length += array.length; - } - } - return result; - } - - /** - * 将多个数组合并在一起
- * 忽略null的数组 - * - * @param arrays 数组集合 - * @return 合并后的数组 - * @since 4.6.9 - */ - public static short[] addAll(short[]... arrays) { - if (arrays.length == 1) { - return arrays[0]; - } - - // 计算总长度 - int length = 0; - for (short[] array : arrays) { - if (null != array) { - length += array.length; - } - } - - final short[] result = new short[length]; - length = 0; - for (short[] array : arrays) { - if (null != array) { - System.arraycopy(array, 0, result, length, array.length); - length += array.length; - } - } - return result; - } - /** * 包装 {@link System#arraycopy(Object, int, Object, int, int)}
* 数组复制 @@ -992,89 +551,6 @@ public class ArrayUtil { return null; } - /** - * 生成一个从0开始的数字列表
- * - * @param excludedEnd 结束的数字(不包含) - * @return 数字列表 - */ - public static int[] range(int excludedEnd) { - return range(0, excludedEnd, 1); - } - - /** - * 生成一个数字列表
- * 自动判定正序反序 - * - * @param includedStart 开始的数字(包含) - * @param excludedEnd 结束的数字(不包含) - * @return 数字列表 - */ - public static int[] range(int includedStart, int excludedEnd) { - return range(includedStart, excludedEnd, 1); - } - - /** - * 生成一个数字列表
- * 自动判定正序反序 - * - * @param includedStart 开始的数字(包含) - * @param excludedEnd 结束的数字(不包含) - * @param step 步进 - * @return 数字列表 - */ - public static int[] range(int includedStart, int excludedEnd, int step) { - if (includedStart > excludedEnd) { - int tmp = includedStart; - includedStart = excludedEnd; - excludedEnd = tmp; - } - - if (step <= 0) { - step = 1; - } - - int deviation = excludedEnd - includedStart; - int length = deviation / step; - if (deviation % step != 0) { - length += 1; - } - int[] range = new int[length]; - for (int i = 0; i < length; i++) { - range[i] = includedStart; - includedStart += step; - } - return range; - } - - /** - * 拆分byte数组为几个等份(最后一份可能小于len) - * - * @param array 数组 - * @param len 每个小节的长度 - * @return 拆分后的数组 - */ - public static byte[][] split(byte[] array, int len) { - int x = array.length / len; - int y = array.length % len; - int z = 0; - if (y != 0) { - z = 1; - } - byte[][] arrays = new byte[x + z][]; - byte[] arr; - for (int i = 0; i < x + z; i++) { - arr = new byte[len]; - if (i == x + z - 1 && y != 0) { - System.arraycopy(array, i * len, arr, 0, y); - } else { - System.arraycopy(array, i * len, arr, 0, len); - } - arrays[i] = arr; - } - return arrays; - } - /** * 过滤
* 过滤过程通过传入的Editor实现来返回需要的元素内容,这个Editor实现可以实现以下功能: @@ -1372,760 +848,8 @@ public class ArrayUtil { return indexOfIgnoreCase(array, value) > INDEX_NOT_FOUND; } - /** - * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int indexOf(long[] array, long value) { - if (null != array) { - for (int i = 0; i < array.length; i++) { - if (value == array[i]) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int lastIndexOf(long[] array, long value) { - if (null != array) { - for (int i = array.length - 1; i >= 0; i--) { - if (value == array[i]) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 数组中是否包含元素 - * - * @param array 数组 - * @param value 被检查的元素 - * @return 是否包含 - * @since 3.0.7 - */ - public static boolean contains(long[] array, long value) { - return indexOf(array, value) > INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int indexOf(int[] array, int value) { - if (null != array) { - for (int i = 0; i < array.length; i++) { - if (value == array[i]) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int lastIndexOf(int[] array, int value) { - if (null != array) { - for (int i = array.length - 1; i >= 0; i--) { - if (value == array[i]) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 数组中是否包含元素 - * - * @param array 数组 - * @param value 被检查的元素 - * @return 是否包含 - * @since 3.0.7 - */ - public static boolean contains(int[] array, int value) { - return indexOf(array, value) > INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int indexOf(short[] array, short value) { - if (null != array) { - for (int i = 0; i < array.length; i++) { - if (value == array[i]) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int lastIndexOf(short[] array, short value) { - if (null != array) { - for (int i = array.length - 1; i >= 0; i--) { - if (value == array[i]) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 数组中是否包含元素 - * - * @param array 数组 - * @param value 被检查的元素 - * @return 是否包含 - * @since 3.0.7 - */ - public static boolean contains(short[] array, short value) { - return indexOf(array, value) > INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int indexOf(char[] array, char value) { - if (null != array) { - for (int i = 0; i < array.length; i++) { - if (value == array[i]) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int lastIndexOf(char[] array, char value) { - if (null != array) { - for (int i = array.length - 1; i >= 0; i--) { - if (value == array[i]) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 数组中是否包含元素 - * - * @param array 数组 - * @param value 被检查的元素 - * @return 是否包含 - * @since 3.0.7 - */ - public static boolean contains(char[] array, char value) { - return indexOf(array, value) > INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int indexOf(byte[] array, byte value) { - if (null != array) { - for (int i = 0; i < array.length; i++) { - if (value == array[i]) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int lastIndexOf(byte[] array, byte value) { - if (null != array) { - for (int i = array.length - 1; i >= 0; i--) { - if (value == array[i]) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 数组中是否包含元素 - * - * @param array 数组 - * @param value 被检查的元素 - * @return 是否包含 - * @since 3.0.7 - */ - public static boolean contains(byte[] array, byte value) { - return indexOf(array, value) > INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int indexOf(double[] array, double value) { - if (null != array) { - for (int i = 0; i < array.length; i++) { - if (NumberUtil.equals(value, array[i])) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int lastIndexOf(double[] array, double value) { - if (null != array) { - for (int i = array.length - 1; i >= 0; i--) { - if (NumberUtil.equals(value, array[i])) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 数组中是否包含元素 - * - * @param array 数组 - * @param value 被检查的元素 - * @return 是否包含 - * @since 3.0.7 - */ - public static boolean contains(double[] array, double value) { - return indexOf(array, value) > INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int indexOf(float[] array, float value) { - if (null != array) { - for (int i = 0; i < array.length; i++) { - if (NumberUtil.equals(value, array[i])) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int lastIndexOf(float[] array, float value) { - if (null != array) { - for (int i = array.length - 1; i >= 0; i--) { - if (NumberUtil.equals(value, array[i])) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 数组中是否包含元素 - * - * @param array 数组 - * @param value 被检查的元素 - * @return 是否包含 - * @since 3.0.7 - */ - public static boolean contains(float[] array, float value) { - return indexOf(array, value) > INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int indexOf(boolean[] array, boolean value) { - if (null != array) { - for (int i = 0; i < array.length; i++) { - if (value == array[i]) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} - * - * @param array 数组 - * @param value 被检查的元素 - * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} - * @since 3.0.7 - */ - public static int lastIndexOf(boolean[] array, boolean value) { - if (null != array) { - for (int i = array.length - 1; i >= 0; i--) { - if (value == array[i]) { - return i; - } - } - } - return INDEX_NOT_FOUND; - } - - /** - * 数组中是否包含元素 - * - * @param array 数组 - * @param value 被检查的元素 - * @return 是否包含 - * @since 3.0.7 - */ - public static boolean contains(boolean[] array, boolean value) { - return indexOf(array, value) > INDEX_NOT_FOUND; - } - // ------------------------------------------------------------------- Wrap and unwrap - /** - * 将原始类型数组包装为包装类型 - * - * @param values 原始类型数组 - * @return 包装类型数组 - */ - public static Integer[] wrap(int... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new Integer[0]; - } - - final Integer[] array = new Integer[length]; - for (int i = 0; i < length; i++) { - array[i] = values[i]; - } - return array; - } - - /** - * 包装类数组转为原始类型数组,null转为0 - * - * @param values 包装类型数组 - * @return 原始类型数组 - */ - public static int[] unWrap(Integer... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new int[0]; - } - - final int[] array = new int[length]; - for (int i = 0; i < length; i++) { - array[i] = ObjectUtil.defaultIfNull(values[i], 0); - } - return array; - } - - /** - * 将原始类型数组包装为包装类型 - * - * @param values 原始类型数组 - * @return 包装类型数组 - */ - public static Long[] wrap(long... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new Long[0]; - } - - final Long[] array = new Long[length]; - for (int i = 0; i < length; i++) { - array[i] = values[i]; - } - return array; - } - - /** - * 包装类数组转为原始类型数组 - * - * @param values 包装类型数组 - * @return 原始类型数组 - */ - public static long[] unWrap(Long... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new long[0]; - } - - final long[] array = new long[length]; - for (int i = 0; i < length; i++) { - array[i] = ObjectUtil.defaultIfNull(values[i], 0L); - } - return array; - } - - /** - * 将原始类型数组包装为包装类型 - * - * @param values 原始类型数组 - * @return 包装类型数组 - */ - public static Character[] wrap(char... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new Character[0]; - } - - final Character[] array = new Character[length]; - for (int i = 0; i < length; i++) { - array[i] = values[i]; - } - return array; - } - - /** - * 包装类数组转为原始类型数组 - * - * @param values 包装类型数组 - * @return 原始类型数组 - */ - public static char[] unWrap(Character... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new char[0]; - } - - char[] array = new char[length]; - for (int i = 0; i < length; i++) { - array[i] = ObjectUtil.defaultIfNull(values[i], Character.MIN_VALUE); - } - return array; - } - - /** - * 将原始类型数组包装为包装类型 - * - * @param values 原始类型数组 - * @return 包装类型数组 - */ - public static Byte[] wrap(byte... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new Byte[0]; - } - - final Byte[] array = new Byte[length]; - for (int i = 0; i < length; i++) { - array[i] = values[i]; - } - return array; - } - - /** - * 包装类数组转为原始类型数组 - * - * @param values 包装类型数组 - * @return 原始类型数组 - */ - public static byte[] unWrap(Byte... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new byte[0]; - } - - final byte[] array = new byte[length]; - for (int i = 0; i < length; i++) { - array[i] = ObjectUtil.defaultIfNull(values[i], (byte) 0); - } - return array; - } - - /** - * 将原始类型数组包装为包装类型 - * - * @param values 原始类型数组 - * @return 包装类型数组 - */ - public static Short[] wrap(short... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new Short[0]; - } - - final Short[] array = new Short[length]; - for (int i = 0; i < length; i++) { - array[i] = values[i]; - } - return array; - } - - /** - * 包装类数组转为原始类型数组 - * - * @param values 包装类型数组 - * @return 原始类型数组 - */ - public static short[] unWrap(Short... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new short[0]; - } - - final short[] array = new short[length]; - for (int i = 0; i < length; i++) { - array[i] = ObjectUtil.defaultIfNull(values[i], (short) 0); - } - return array; - } - - /** - * 将原始类型数组包装为包装类型 - * - * @param values 原始类型数组 - * @return 包装类型数组 - */ - public static Float[] wrap(float... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new Float[0]; - } - - final Float[] array = new Float[length]; - for (int i = 0; i < length; i++) { - array[i] = values[i]; - } - return array; - } - - /** - * 包装类数组转为原始类型数组 - * - * @param values 包装类型数组 - * @return 原始类型数组 - */ - public static float[] unWrap(Float... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new float[0]; - } - - final float[] array = new float[length]; - for (int i = 0; i < length; i++) { - array[i] = ObjectUtil.defaultIfNull(values[i], 0F); - } - return array; - } - - /** - * 将原始类型数组包装为包装类型 - * - * @param values 原始类型数组 - * @return 包装类型数组 - */ - public static Double[] wrap(double... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new Double[0]; - } - - final Double[] array = new Double[length]; - for (int i = 0; i < length; i++) { - array[i] = values[i]; - } - return array; - } - - /** - * 包装类数组转为原始类型数组 - * - * @param values 包装类型数组 - * @return 原始类型数组 - */ - public static double[] unWrap(Double... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new double[0]; - } - - final double[] array = new double[length]; - for (int i = 0; i < length; i++) { - array[i] = ObjectUtil.defaultIfNull(values[i], 0D); - } - return array; - } - - /** - * 将原始类型数组包装为包装类型 - * - * @param values 原始类型数组 - * @return 包装类型数组 - */ - public static Boolean[] wrap(boolean... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new Boolean[0]; - } - - final Boolean[] array = new Boolean[length]; - for (int i = 0; i < length; i++) { - array[i] = values[i]; - } - return array; - } - - /** - * 包装类数组转为原始类型数组 - * - * @param values 包装类型数组 - * @return 原始类型数组 - */ - public static boolean[] unWrap(Boolean... values) { - if (null == values) { - return null; - } - final int length = values.length; - if (0 == length) { - return new boolean[0]; - } - - final boolean[] array = new boolean[length]; - for (int i = 0; i < length; i++) { - array[i] = ObjectUtil.defaultIfNull(values[i], false); - } - return array; - } - /** * 包装数组对象 * @@ -2263,286 +987,6 @@ public class ArrayUtil { return Arrays.copyOfRange(array, start, end); } - /** - * 获取子数组 - * - * @param array 数组 - * @param start 开始位置(包括) - * @param end 结束位置(不包括) - * @return 新的数组 - * @see Arrays#copyOfRange(Object[], int, int) - * @since 4.5.2 - */ - public static byte[] sub(byte[] array, int start, int end) { - int length = length(array); - if (start < 0) { - start += length; - } - if (end < 0) { - end += length; - } - if (start == length) { - return new byte[0]; - } - if (start > end) { - int tmp = start; - start = end; - end = tmp; - } - if (end > length) { - if (start >= length) { - return new byte[0]; - } - end = length; - } - return Arrays.copyOfRange(array, start, end); - } - - /** - * 获取子数组 - * - * @param array 数组 - * @param start 开始位置(包括) - * @param end 结束位置(不包括) - * @return 新的数组 - * @see Arrays#copyOfRange(Object[], int, int) - * @since 4.5.2 - */ - public static int[] sub(int[] array, int start, int end) { - int length = length(array); - if (start < 0) { - start += length; - } - if (end < 0) { - end += length; - } - if (start == length) { - return new int[0]; - } - if (start > end) { - int tmp = start; - start = end; - end = tmp; - } - if (end > length) { - if (start >= length) { - return new int[0]; - } - end = length; - } - return Arrays.copyOfRange(array, start, end); - } - - /** - * 获取子数组 - * - * @param array 数组 - * @param start 开始位置(包括) - * @param end 结束位置(不包括) - * @return 新的数组 - * @see Arrays#copyOfRange(Object[], int, int) - * @since 4.5.2 - */ - public static long[] sub(long[] array, int start, int end) { - int length = length(array); - if (start < 0) { - start += length; - } - if (end < 0) { - end += length; - } - if (start == length) { - return new long[0]; - } - if (start > end) { - int tmp = start; - start = end; - end = tmp; - } - if (end > length) { - if (start >= length) { - return new long[0]; - } - end = length; - } - return Arrays.copyOfRange(array, start, end); - } - - /** - * 获取子数组 - * - * @param array 数组 - * @param start 开始位置(包括) - * @param end 结束位置(不包括) - * @return 新的数组 - * @see Arrays#copyOfRange(Object[], int, int) - * @since 4.5.2 - */ - public static short[] sub(short[] array, int start, int end) { - int length = length(array); - if (start < 0) { - start += length; - } - if (end < 0) { - end += length; - } - if (start == length) { - return new short[0]; - } - if (start > end) { - int tmp = start; - start = end; - end = tmp; - } - if (end > length) { - if (start >= length) { - return new short[0]; - } - end = length; - } - return Arrays.copyOfRange(array, start, end); - } - - /** - * 获取子数组 - * - * @param array 数组 - * @param start 开始位置(包括) - * @param end 结束位置(不包括) - * @return 新的数组 - * @see Arrays#copyOfRange(Object[], int, int) - * @since 4.5.2 - */ - public static char[] sub(char[] array, int start, int end) { - int length = length(array); - if (start < 0) { - start += length; - } - if (end < 0) { - end += length; - } - if (start == length) { - return new char[0]; - } - if (start > end) { - int tmp = start; - start = end; - end = tmp; - } - if (end > length) { - if (start >= length) { - return new char[0]; - } - end = length; - } - return Arrays.copyOfRange(array, start, end); - } - - /** - * 获取子数组 - * - * @param array 数组 - * @param start 开始位置(包括) - * @param end 结束位置(不包括) - * @return 新的数组 - * @see Arrays#copyOfRange(Object[], int, int) - * @since 4.5.2 - */ - public static double[] sub(double[] array, int start, int end) { - int length = length(array); - if (start < 0) { - start += length; - } - if (end < 0) { - end += length; - } - if (start == length) { - return new double[0]; - } - if (start > end) { - int tmp = start; - start = end; - end = tmp; - } - if (end > length) { - if (start >= length) { - return new double[0]; - } - end = length; - } - return Arrays.copyOfRange(array, start, end); - } - - /** - * 获取子数组 - * - * @param array 数组 - * @param start 开始位置(包括) - * @param end 结束位置(不包括) - * @return 新的数组 - * @see Arrays#copyOfRange(Object[], int, int) - * @since 4.5.2 - */ - public static float[] sub(float[] array, int start, int end) { - int length = length(array); - if (start < 0) { - start += length; - } - if (end < 0) { - end += length; - } - if (start == length) { - return new float[0]; - } - if (start > end) { - int tmp = start; - start = end; - end = tmp; - } - if (end > length) { - if (start >= length) { - return new float[0]; - } - end = length; - } - return Arrays.copyOfRange(array, start, end); - } - - /** - * 获取子数组 - * - * @param array 数组 - * @param start 开始位置(包括) - * @param end 结束位置(不包括) - * @return 新的数组 - * @see Arrays#copyOfRange(Object[], int, int) - * @since 4.5.2 - */ - public static boolean[] sub(boolean[] array, int start, int end) { - int length = length(array); - if (start < 0) { - start += length; - } - if (end < 0) { - end += length; - } - if (start == length) { - return new boolean[0]; - } - if (start > end) { - int tmp = start; - start = end; - end = tmp; - } - if (end > length) { - if (start >= length) { - return new boolean[0]; - } - end = length; - } - return Arrays.copyOfRange(array, start, end); - } - /** * 获取子数组 * @@ -2773,181 +1217,6 @@ public class ArrayUtil { return sb.toString(); } - /** - * 以 conjunction 为分隔符将数组转换为字符串 - * - * @param array 数组 - * @param conjunction 分隔符 - * @return 连接后的字符串 - */ - public static String join(int[] array, CharSequence conjunction) { - if (null == array) { - return null; - } - - final StringBuilder sb = new StringBuilder(); - boolean isFirst = true; - for (int item : array) { - if (isFirst) { - isFirst = false; - } else { - sb.append(conjunction); - } - sb.append(item); - } - return sb.toString(); - } - - /** - * 以 conjunction 为分隔符将数组转换为字符串 - * - * @param array 数组 - * @param conjunction 分隔符 - * @return 连接后的字符串 - */ - public static String join(short[] array, CharSequence conjunction) { - if (null == array) { - return null; - } - - final StringBuilder sb = new StringBuilder(); - boolean isFirst = true; - for (short item : array) { - if (isFirst) { - isFirst = false; - } else { - sb.append(conjunction); - } - sb.append(item); - } - return sb.toString(); - } - - /** - * 以 conjunction 为分隔符将数组转换为字符串 - * - * @param array 数组 - * @param conjunction 分隔符 - * @return 连接后的字符串 - */ - public static String join(char[] array, CharSequence conjunction) { - if (null == array) { - return null; - } - - final StringBuilder sb = new StringBuilder(); - boolean isFirst = true; - for (char item : array) { - if (isFirst) { - isFirst = false; - } else { - sb.append(conjunction); - } - sb.append(item); - } - return sb.toString(); - } - - /** - * 以 conjunction 为分隔符将数组转换为字符串 - * - * @param array 数组 - * @param conjunction 分隔符 - * @return 连接后的字符串 - */ - public static String join(byte[] array, CharSequence conjunction) { - if (null == array) { - return null; - } - - final StringBuilder sb = new StringBuilder(); - boolean isFirst = true; - for (byte item : array) { - if (isFirst) { - isFirst = false; - } else { - sb.append(conjunction); - } - sb.append(item); - } - return sb.toString(); - } - - /** - * 以 conjunction 为分隔符将数组转换为字符串 - * - * @param array 数组 - * @param conjunction 分隔符 - * @return 连接后的字符串 - */ - public static String join(boolean[] array, CharSequence conjunction) { - if (null == array) { - return null; - } - - final StringBuilder sb = new StringBuilder(); - boolean isFirst = true; - for (boolean item : array) { - if (isFirst) { - isFirst = false; - } else { - sb.append(conjunction); - } - sb.append(item); - } - return sb.toString(); - } - - /** - * 以 conjunction 为分隔符将数组转换为字符串 - * - * @param array 数组 - * @param conjunction 分隔符 - * @return 连接后的字符串 - */ - public static String join(float[] array, CharSequence conjunction) { - if (null == array) { - return null; - } - - final StringBuilder sb = new StringBuilder(); - boolean isFirst = true; - for (float item : array) { - if (isFirst) { - isFirst = false; - } else { - sb.append(conjunction); - } - sb.append(item); - } - return sb.toString(); - } - - /** - * 以 conjunction 为分隔符将数组转换为字符串 - * - * @param array 数组 - * @param conjunction 分隔符 - * @return 连接后的字符串 - */ - public static String join(double[] array, CharSequence conjunction) { - if (null == array) { - return null; - } - - final StringBuilder sb = new StringBuilder(); - boolean isFirst = true; - for (double item : array) { - if (isFirst) { - isFirst = false; - } else { - sb.append(conjunction); - } - sb.append(item); - } - return sb.toString(); - } - /** * 以 conjunction 为分隔符将数组转换为字符串 * @@ -3065,149 +1334,7 @@ public class ArrayUtil { return (T[]) remove((Object) array, index); } - /** - * 移除数组中对应位置的元素
- * copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param index 位置,如果位置小于0或者大于长度,返回原数组 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static long[] remove(long[] array, int index) throws IllegalArgumentException { - return (long[]) remove((Object) array, index); - } - - /** - * 移除数组中对应位置的元素
- * copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param index 位置,如果位置小于0或者大于长度,返回原数组 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static int[] remove(int[] array, int index) throws IllegalArgumentException { - return (int[]) remove((Object) array, index); - } - - /** - * 移除数组中对应位置的元素
- * copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param index 位置,如果位置小于0或者大于长度,返回原数组 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static short[] remove(short[] array, int index) throws IllegalArgumentException { - return (short[]) remove((Object) array, index); - } - - /** - * 移除数组中对应位置的元素
- * copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param index 位置,如果位置小于0或者大于长度,返回原数组 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static char[] remove(char[] array, int index) throws IllegalArgumentException { - return (char[]) remove((Object) array, index); - } - - /** - * 移除数组中对应位置的元素
- * copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param index 位置,如果位置小于0或者大于长度,返回原数组 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static byte[] remove(byte[] array, int index) throws IllegalArgumentException { - return (byte[]) remove((Object) array, index); - } - - /** - * 移除数组中对应位置的元素
- * copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param index 位置,如果位置小于0或者大于长度,返回原数组 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static double[] remove(double[] array, int index) throws IllegalArgumentException { - return (double[]) remove((Object) array, index); - } - - /** - * 移除数组中对应位置的元素
- * copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param index 位置,如果位置小于0或者大于长度,返回原数组 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static float[] remove(float[] array, int index) throws IllegalArgumentException { - return (float[]) remove((Object) array, index); - } - - /** - * 移除数组中对应位置的元素
- * copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param index 位置,如果位置小于0或者大于长度,返回原数组 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static boolean[] remove(boolean[] array, int index) throws IllegalArgumentException { - return (boolean[]) remove((Object) array, index); - } - - /** - * 移除数组中对应位置的元素
- * copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param index 位置,如果位置小于0或者大于长度,返回原数组 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - @SuppressWarnings("SuspiciousSystemArraycopy") - public static Object remove(Object array, int index) throws IllegalArgumentException { - if (null == array) { - return null; - } - int length = length(array); - if (index < 0 || index >= length) { - return array; - } - - final Object result = Array.newInstance(array.getClass().getComponentType(), length - 1); - System.arraycopy(array, 0, result, 0, index); - if (index < length - 1) { - // 后半部分 - System.arraycopy(array, index + 1, result, index, length - index - 1); - } - - return result; - } - - // ---------------------------------------------------------------------- remove + // ---------------------------------------------------------------------- removeEle /** * 移除数组中指定的元素
@@ -3224,119 +1351,7 @@ public class ArrayUtil { return remove(array, indexOf(array, element)); } - /** - * 移除数组中指定的元素
- * 只会移除匹配到的第一个元素 copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param element 要移除的元素 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static long[] removeEle(long[] array, long element) throws IllegalArgumentException { - return remove(array, indexOf(array, element)); - } - - /** - * 移除数组中指定的元素
- * 只会移除匹配到的第一个元素 copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param element 要移除的元素 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static int[] removeEle(int[] array, int element) throws IllegalArgumentException { - return remove(array, indexOf(array, element)); - } - - /** - * 移除数组中指定的元素
- * 只会移除匹配到的第一个元素 copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param element 要移除的元素 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static short[] removeEle(short[] array, short element) throws IllegalArgumentException { - return remove(array, indexOf(array, element)); - } - - /** - * 移除数组中指定的元素
- * 只会移除匹配到的第一个元素 copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param element 要移除的元素 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static char[] removeEle(char[] array, char element) throws IllegalArgumentException { - return remove(array, indexOf(array, element)); - } - - /** - * 移除数组中指定的元素
- * 只会移除匹配到的第一个元素 copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param element 要移除的元素 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static byte[] removeEle(byte[] array, byte element) throws IllegalArgumentException { - return remove(array, indexOf(array, element)); - } - - /** - * 移除数组中指定的元素
- * 只会移除匹配到的第一个元素 copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param element 要移除的元素 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static double[] removeEle(double[] array, double element) throws IllegalArgumentException { - return remove(array, indexOf(array, element)); - } - - /** - * 移除数组中指定的元素
- * 只会移除匹配到的第一个元素 copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param element 要移除的元素 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static float[] removeEle(float[] array, float element) throws IllegalArgumentException { - return remove(array, indexOf(array, element)); - } - - /** - * 移除数组中指定的元素
- * 只会移除匹配到的第一个元素 copy from commons-lang - * - * @param array 数组对象,可以是对象数组,也可以原始类型数组 - * @param element 要移除的元素 - * @return 去掉指定元素后的新数组或原数组 - * @throws IllegalArgumentException 参数对象不为数组对象 - * @since 3.0.8 - */ - public static boolean[] removeEle(boolean[] array, boolean element) throws IllegalArgumentException { - return remove(array, indexOf(array, element)); - } - - // ------------------------------------------------------------------------------------------------------------ Reverse array + // ---------------------------------------------------------------------- Reverse array /** * 反转数组,会变更原数组 @@ -3348,7 +1363,7 @@ public class ArrayUtil { * @return 变更后的原数组 * @since 3.0.9 */ - public static T[] reverse(final T[] array, final int startIndexInclusive, final int endIndexExclusive) { + public static T[] reverse(T[] array, final int startIndexInclusive, final int endIndexExclusive) { if (isEmpty(array)) { return array; } @@ -3373,303 +1388,7 @@ public class ArrayUtil { * @return 变更后的原数组 * @since 3.0.9 */ - public static T[] reverse(final T[] array) { - return reverse(array, 0, array.length); - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @param startIndexInclusive 其实位置(包含) - * @param endIndexExclusive 结束位置(不包含) - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static long[] reverse(final long[] array, final int startIndexInclusive, final int endIndexExclusive) { - if (isEmpty(array)) { - return array; - } - int i = Math.max(startIndexInclusive, 0); - int j = Math.min(array.length, endIndexExclusive) - 1; - long tmp; - while (j > i) { - tmp = array[j]; - array[j] = array[i]; - array[i] = tmp; - j--; - i++; - } - return array; - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static long[] reverse(final long[] array) { - return reverse(array, 0, array.length); - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @param startIndexInclusive 其实位置(包含) - * @param endIndexExclusive 结束位置(不包含) - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static int[] reverse(final int[] array, final int startIndexInclusive, final int endIndexExclusive) { - if (isEmpty(array)) { - return array; - } - int i = Math.max(startIndexInclusive, 0); - int j = Math.min(array.length, endIndexExclusive) - 1; - int tmp; - while (j > i) { - tmp = array[j]; - array[j] = array[i]; - array[i] = tmp; - j--; - i++; - } - return array; - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static int[] reverse(final int[] array) { - return reverse(array, 0, array.length); - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @param startIndexInclusive 其实位置(包含) - * @param endIndexExclusive 结束位置(不包含) - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static short[] reverse(final short[] array, final int startIndexInclusive, final int endIndexExclusive) { - if (isEmpty(array)) { - return array; - } - int i = Math.max(startIndexInclusive, 0); - int j = Math.min(array.length, endIndexExclusive) - 1; - short tmp; - while (j > i) { - tmp = array[j]; - array[j] = array[i]; - array[i] = tmp; - j--; - i++; - } - return array; - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static short[] reverse(final short[] array) { - return reverse(array, 0, array.length); - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @param startIndexInclusive 其实位置(包含) - * @param endIndexExclusive 结束位置(不包含) - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static char[] reverse(final char[] array, final int startIndexInclusive, final int endIndexExclusive) { - if (isEmpty(array)) { - return array; - } - int i = Math.max(startIndexInclusive, 0); - int j = Math.min(array.length, endIndexExclusive) - 1; - char tmp; - while (j > i) { - tmp = array[j]; - array[j] = array[i]; - array[i] = tmp; - j--; - i++; - } - return array; - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static char[] reverse(final char[] array) { - return reverse(array, 0, array.length); - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @param startIndexInclusive 其实位置(包含) - * @param endIndexExclusive 结束位置(不包含) - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static byte[] reverse(final byte[] array, final int startIndexInclusive, final int endIndexExclusive) { - if (isEmpty(array)) { - return array; - } - int i = Math.max(startIndexInclusive, 0); - int j = Math.min(array.length, endIndexExclusive) - 1; - byte tmp; - while (j > i) { - tmp = array[j]; - array[j] = array[i]; - array[i] = tmp; - j--; - i++; - } - return array; - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static byte[] reverse(final byte[] array) { - return reverse(array, 0, array.length); - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @param startIndexInclusive 其实位置(包含) - * @param endIndexExclusive 结束位置(不包含) - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static double[] reverse(final double[] array, final int startIndexInclusive, final int endIndexExclusive) { - if (isEmpty(array)) { - return array; - } - int i = Math.max(startIndexInclusive, 0); - int j = Math.min(array.length, endIndexExclusive) - 1; - double tmp; - while (j > i) { - tmp = array[j]; - array[j] = array[i]; - array[i] = tmp; - j--; - i++; - } - return array; - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static double[] reverse(final double[] array) { - return reverse(array, 0, array.length); - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @param startIndexInclusive 其实位置(包含) - * @param endIndexExclusive 结束位置(不包含) - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static float[] reverse(final float[] array, final int startIndexInclusive, final int endIndexExclusive) { - if (isEmpty(array)) { - return array; - } - int i = Math.max(startIndexInclusive, 0); - int j = Math.min(array.length, endIndexExclusive) - 1; - float tmp; - while (j > i) { - tmp = array[j]; - array[j] = array[i]; - array[i] = tmp; - j--; - i++; - } - return array; - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static float[] reverse(final float[] array) { - return reverse(array, 0, array.length); - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @param startIndexInclusive 其实位置(包含) - * @param endIndexExclusive 结束位置(不包含) - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static boolean[] reverse(final boolean[] array, final int startIndexInclusive, final int endIndexExclusive) { - if (isEmpty(array)) { - return array; - } - int i = Math.max(startIndexInclusive, 0); - int j = Math.min(array.length, endIndexExclusive) - 1; - boolean tmp; - while (j > i) { - tmp = array[j]; - array[j] = array[i]; - array[i] = tmp; - j--; - i++; - } - return array; - } - - /** - * 反转数组,会变更原数组 - * - * @param array 数组,会变更 - * @return 变更后的原数组 - * @since 3.0.9 - */ - public static boolean[] reverse(final boolean[] array) { + public static T[] reverse(T[] array) { return reverse(array, 0, array.length); } @@ -3709,146 +1428,6 @@ public class ArrayUtil { return min; } - /** - * 取最小值 - * - * @param numberArray 数字数组 - * @return 最小值 - * @since 3.0.9 - */ - public static long min(long... numberArray) { - if (isEmpty(numberArray)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - long min = numberArray[0]; - for (int i = 1; i < numberArray.length; i++) { - if (min > numberArray[i]) { - min = numberArray[i]; - } - } - return min; - } - - /** - * 取最小值 - * - * @param numberArray 数字数组 - * @return 最小值 - * @since 3.0.9 - */ - public static int min(int... numberArray) { - if (isEmpty(numberArray)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - int min = numberArray[0]; - for (int i = 1; i < numberArray.length; i++) { - if (min > numberArray[i]) { - min = numberArray[i]; - } - } - return min; - } - - /** - * 取最小值 - * - * @param numberArray 数字数组 - * @return 最小值 - * @since 3.0.9 - */ - public static short min(short... numberArray) { - if (isEmpty(numberArray)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - short min = numberArray[0]; - for (int i = 1; i < numberArray.length; i++) { - if (min > numberArray[i]) { - min = numberArray[i]; - } - } - return min; - } - - /** - * 取最小值 - * - * @param numberArray 数字数组 - * @return 最小值 - * @since 3.0.9 - */ - public static char min(char... numberArray) { - if (isEmpty(numberArray)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - char min = numberArray[0]; - for (int i = 1; i < numberArray.length; i++) { - if (min > numberArray[i]) { - min = numberArray[i]; - } - } - return min; - } - - /** - * 取最小值 - * - * @param numberArray 数字数组 - * @return 最小值 - * @since 3.0.9 - */ - public static byte min(byte... numberArray) { - if (isEmpty(numberArray)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - byte min = numberArray[0]; - for (int i = 1; i < numberArray.length; i++) { - if (min > numberArray[i]) { - min = numberArray[i]; - } - } - return min; - } - - /** - * 取最小值 - * - * @param numberArray 数字数组 - * @return 最小值 - * @since 3.0.9 - */ - public static double min(double... numberArray) { - if (isEmpty(numberArray)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - double min = numberArray[0]; - for (int i = 1; i < numberArray.length; i++) { - if (min > numberArray[i]) { - min = numberArray[i]; - } - } - return min; - } - - /** - * 取最小值 - * - * @param numberArray 数字数组 - * @return 最小值 - * @since 3.0.9 - */ - public static float min(float... numberArray) { - if (isEmpty(numberArray)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - float min = numberArray[0]; - for (int i = 1; i < numberArray.length; i++) { - if (min > numberArray[i]) { - min = numberArray[i]; - } - } - return min; - } - /** * 取最大值 * @@ -3883,417 +1462,12 @@ public class ArrayUtil { return max; } - /** - * 取最大值 - * - * @param numberArray 数字数组 - * @return 最大值 - * @since 3.0.9 - */ - public static long max(long... numberArray) { - if (isEmpty(numberArray)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - long max = numberArray[0]; - for (int i = 1; i < numberArray.length; i++) { - if (max < numberArray[i]) { - max = numberArray[i]; - } - } - return max; - } - - /** - * 取最大值 - * - * @param numberArray 数字数组 - * @return 最大值 - * @since 3.0.9 - */ - public static int max(int... numberArray) { - if (isEmpty(numberArray)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - int max = numberArray[0]; - for (int i = 1; i < numberArray.length; i++) { - if (max < numberArray[i]) { - max = numberArray[i]; - } - } - return max; - } - - /** - * 取最大值 - * - * @param numberArray 数字数组 - * @return 最大值 - * @since 3.0.9 - */ - public static short max(short... numberArray) { - if (isEmpty(numberArray)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - short max = numberArray[0]; - for (int i = 1; i < numberArray.length; i++) { - if (max < numberArray[i]) { - max = numberArray[i]; - } - } - return max; - } - - /** - * 取最大值 - * - * @param numberArray 数字数组 - * @return 最大值 - * @since 3.0.9 - */ - public static char max(char... numberArray) { - if (isEmpty(numberArray)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - char max = numberArray[0]; - for (int i = 1; i < numberArray.length; i++) { - if (max < numberArray[i]) { - max = numberArray[i]; - } - } - return max; - } - - /** - * 取最大值 - * - * @param numberArray 数字数组 - * @return 最大值 - * @since 3.0.9 - */ - public static byte max(byte... numberArray) { - if (isEmpty(numberArray)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - byte max = numberArray[0]; - for (int i = 1; i < numberArray.length; i++) { - if (max < numberArray[i]) { - max = numberArray[i]; - } - } - return max; - } - - /** - * 取最大值 - * - * @param numberArray 数字数组 - * @return 最大值 - * @since 3.0.9 - */ - public static double max(double... numberArray) { - if (isEmpty(numberArray)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - double max = numberArray[0]; - for (int i = 1; i < numberArray.length; i++) { - if (max < numberArray[i]) { - max = numberArray[i]; - } - } - return max; - } - - /** - * 取最大值 - * - * @param numberArray 数字数组 - * @return 最大值 - * @since 3.0.9 - */ - public static float max(float... numberArray) { - if (isEmpty(numberArray)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - float max = numberArray[0]; - for (int i = 1; i < numberArray.length; i++) { - if (max < numberArray[i]) { - max = numberArray[i]; - } - } - return max; - } - - // 使用Fisher–Yates洗牌算法,以线性时间复杂度打乱数组顺序 /** * 打乱数组顺序,会变更原数组 * - * @param array 数组,会变更 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static int[] shuffle(int[] array) { - return shuffle(array, RandomUtil.getRandom()); - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @param random 随机数生成器 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static int[] shuffle(int[] array, Random random) { - if (array == null || random == null || array.length <= 1) { - return array; - } - - for (int i = array.length; i > 1; i--) { - swap(array, i - 1, random.nextInt(i)); - } - - return array; - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static long[] shuffle(long[] array) { - return shuffle(array, RandomUtil.getRandom()); - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @param random 随机数生成器 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static long[] shuffle(long[] array, Random random) { - if (array == null || random == null || array.length <= 1) { - return array; - } - - for (int i = array.length; i > 1; i--) { - swap(array, i - 1, random.nextInt(i)); - } - - return array; - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static double[] shuffle(double[] array) { - return shuffle(array, RandomUtil.getRandom()); - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @param random 随机数生成器 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static double[] shuffle(double[] array, Random random) { - if (array == null || random == null || array.length <= 1) { - return array; - } - - for (int i = array.length; i > 1; i--) { - swap(array, i - 1, random.nextInt(i)); - } - - return array; - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static float[] shuffle(float[] array) { - return shuffle(array, RandomUtil.getRandom()); - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @param random 随机数生成器 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static float[] shuffle(float[] array, Random random) { - if (array == null || random == null || array.length <= 1) { - return array; - } - - for (int i = array.length; i > 1; i--) { - swap(array, i - 1, random.nextInt(i)); - } - - return array; - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static boolean[] shuffle(boolean[] array) { - return shuffle(array, RandomUtil.getRandom()); - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @param random 随机数生成器 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static boolean[] shuffle(boolean[] array, Random random) { - if (array == null || random == null || array.length <= 1) { - return array; - } - - for (int i = array.length; i > 1; i--) { - swap(array, i - 1, random.nextInt(i)); - } - - return array; - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static byte[] shuffle(byte[] array) { - return shuffle(array, RandomUtil.getRandom()); - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @param random 随机数生成器 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static byte[] shuffle(byte[] array, Random random) { - if (array == null || random == null || array.length <= 1) { - return array; - } - - for (int i = array.length; i > 1; i--) { - swap(array, i - 1, random.nextInt(i)); - } - - return array; - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static char[] shuffle(char[] array) { - return shuffle(array, RandomUtil.getRandom()); - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @param random 随机数生成器 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static char[] shuffle(char[] array, Random random) { - if (array == null || random == null || array.length <= 1) { - return array; - } - - for (int i = array.length; i > 1; i--) { - swap(array, i - 1, random.nextInt(i)); - } - - return array; - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static short[] shuffle(short[] array) { - return shuffle(array, RandomUtil.getRandom()); - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param array 数组,会变更 - * @param random 随机数生成器 - * @return 打乱后的数组 - * @author FengBaoheng - * @since 5.5.2 - */ - public static short[] shuffle(short[] array, Random random) { - if (array == null || random == null || array.length <= 1) { - return array; - } - - for (int i = array.length; i > 1; i--) { - swap(array, i - 1, random.nextInt(i)); - } - - return array; - } - - /** - * 打乱数组顺序,会变更原数组 - * - * @param 元素类型 + * @param 元素类型 * @param array 数组,会变更 * @return 打乱后的数组 * @author FengBaoheng @@ -4306,7 +1480,7 @@ public class ArrayUtil { /** * 打乱数组顺序,会变更原数组 * - * @param 元素类型 + * @param 元素类型 * @param array 数组,会变更 * @param random 随机数生成器 * @return 打乱后的数组 @@ -4325,158 +1499,6 @@ public class ArrayUtil { return array; } - /** - * 交换数组中两个位置的值 - * - * @param array 数组 - * @param index1 位置1 - * @param index2 位置2 - * @return 交换后的数组,与传入数组为同一对象 - * @since 4.0.7 - */ - public static int[] swap(int[] array, int index1, int index2) { - if (isEmpty(array)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - int tmp = array[index1]; - array[index1] = array[index2]; - array[index2] = tmp; - return array; - } - - /** - * 交换数组中两个位置的值 - * - * @param array 数组 - * @param index1 位置1 - * @param index2 位置2 - * @return 交换后的数组,与传入数组为同一对象 - * @since 4.0.7 - */ - public static long[] swap(long[] array, int index1, int index2) { - if (isEmpty(array)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - long tmp = array[index1]; - array[index1] = array[index2]; - array[index2] = tmp; - return array; - } - - /** - * 交换数组中两个位置的值 - * - * @param array 数组 - * @param index1 位置1 - * @param index2 位置2 - * @return 交换后的数组,与传入数组为同一对象 - * @since 4.0.7 - */ - public static double[] swap(double[] array, int index1, int index2) { - if (isEmpty(array)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - double tmp = array[index1]; - array[index1] = array[index2]; - array[index2] = tmp; - return array; - } - - /** - * 交换数组中两个位置的值 - * - * @param array 数组 - * @param index1 位置1 - * @param index2 位置2 - * @return 交换后的数组,与传入数组为同一对象 - * @since 4.0.7 - */ - public static float[] swap(float[] array, int index1, int index2) { - if (isEmpty(array)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - float tmp = array[index1]; - array[index1] = array[index2]; - array[index2] = tmp; - return array; - } - - /** - * 交换数组中两个位置的值 - * - * @param array 数组 - * @param index1 位置1 - * @param index2 位置2 - * @return 交换后的数组,与传入数组为同一对象 - * @since 4.0.7 - */ - public static boolean[] swap(boolean[] array, int index1, int index2) { - if (isEmpty(array)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - boolean tmp = array[index1]; - array[index1] = array[index2]; - array[index2] = tmp; - return array; - } - - /** - * 交换数组中两个位置的值 - * - * @param array 数组 - * @param index1 位置1 - * @param index2 位置2 - * @return 交换后的数组,与传入数组为同一对象 - * @since 4.0.7 - */ - public static byte[] swap(byte[] array, int index1, int index2) { - if (isEmpty(array)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - byte tmp = array[index1]; - array[index1] = array[index2]; - array[index2] = tmp; - return array; - } - - /** - * 交换数组中两个位置的值 - * - * @param array 数组 - * @param index1 位置1 - * @param index2 位置2 - * @return 交换后的数组,与传入数组为同一对象 - * @since 4.0.7 - */ - public static char[] swap(char[] array, int index1, int index2) { - if (isEmpty(array)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - char tmp = array[index1]; - array[index1] = array[index2]; - array[index2] = tmp; - return array; - } - - /** - * 交换数组中两个位置的值 - * - * @param array 数组 - * @param index1 位置1 - * @param index2 位置2 - * @return 交换后的数组,与传入数组为同一对象 - * @since 4.0.7 - */ - public static short[] swap(short[] array, int index1, int index2) { - if (isEmpty(array)) { - throw new IllegalArgumentException("Number array must not empty !"); - } - short tmp = array[index1]; - array[index1] = array[index2]; - array[index2] = tmp; - return array; - } - /** * 交换数组中两个位置的值 * @@ -4575,6 +1597,19 @@ public class ArrayUtil { return false == hasEmpty(args); } + /** + * 多个字段是否全部不为null + * + * @param 数组元素类型 + * @param array 被检查的数组 + * @return 多个字段是否全部不为null + * @since 5.4.0 + */ + @SuppressWarnings("unchecked") + public static boolean isAllNotNull(T... array) { + return false == hasNull(array); + } + /** * 去重数组中的元素,去重后生成新的数组,原数组不变
* 此方法通过{@link LinkedHashSet} 去重 @@ -4594,20 +1629,6 @@ public class ArrayUtil { return toArray(set, (Class) getComponentType(array)); } - - /** - * 多个字段是否全部不为null - * - * @param 数组元素类型 - * @param array 被检查的数组 - * @return 多个字段是否全部不为null - * @since 5.4.0 - */ - @SuppressWarnings("unchecked") - public static boolean isAllNotNull(T... array) { - return false == hasNull(array); - } - /** * 按照指定规则,将一种类型的数组转换为另一种类型 * diff --git a/hutool-core/src/main/java/cn/hutool/core/util/PrimitiveArrayUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/PrimitiveArrayUtil.java new file mode 100644 index 0000000000..b77130d3ad --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/util/PrimitiveArrayUtil.java @@ -0,0 +1,3022 @@ +package cn.hutool.core.util; + +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.Random; + +/** + * 原始类型数组工具类 + * + * @author looly + * @since 5.5.2 + */ +public class PrimitiveArrayUtil { + /** + * 数组中元素未找到的下标,值为-1 + */ + public static final int INDEX_NOT_FOUND = -1; + + // ---------------------------------------------------------------------- isEmpty + + /** + * 数组是否为空 + * + * @param array 数组 + * @return 是否为空 + */ + public static boolean isEmpty(long[] array) { + return array == null || array.length == 0; + } + + /** + * 数组是否为空 + * + * @param array 数组 + * @return 是否为空 + */ + public static boolean isEmpty(int[] array) { + return array == null || array.length == 0; + } + + /** + * 数组是否为空 + * + * @param array 数组 + * @return 是否为空 + */ + public static boolean isEmpty(short[] array) { + return array == null || array.length == 0; + } + + /** + * 数组是否为空 + * + * @param array 数组 + * @return 是否为空 + */ + public static boolean isEmpty(char[] array) { + return array == null || array.length == 0; + } + + /** + * 数组是否为空 + * + * @param array 数组 + * @return 是否为空 + */ + public static boolean isEmpty(byte[] array) { + return array == null || array.length == 0; + } + + /** + * 数组是否为空 + * + * @param array 数组 + * @return 是否为空 + */ + public static boolean isEmpty(double[] array) { + return array == null || array.length == 0; + } + + /** + * 数组是否为空 + * + * @param array 数组 + * @return 是否为空 + */ + public static boolean isEmpty(float[] array) { + return array == null || array.length == 0; + } + + /** + * 数组是否为空 + * + * @param array 数组 + * @return 是否为空 + */ + public static boolean isEmpty(boolean[] array) { + return array == null || array.length == 0; + } + + // ---------------------------------------------------------------------- isNotEmpty + + /** + * 数组是否为非空 + * + * @param array 数组 + * @return 是否为非空 + */ + public static boolean isNotEmpty(long[] array) { + return false == isEmpty(array); + } + + /** + * 数组是否为非空 + * + * @param array 数组 + * @return 是否为非空 + */ + public static boolean isNotEmpty(int[] array) { + return false == isEmpty(array); + } + + /** + * 数组是否为非空 + * + * @param array 数组 + * @return 是否为非空 + */ + public static boolean isNotEmpty(short[] array) { + return false == isEmpty(array); + } + + /** + * 数组是否为非空 + * + * @param array 数组 + * @return 是否为非空 + */ + public static boolean isNotEmpty(char[] array) { + return false == isEmpty(array); + } + + /** + * 数组是否为非空 + * + * @param array 数组 + * @return 是否为非空 + */ + public static boolean isNotEmpty(byte[] array) { + return false == isEmpty(array); + } + + /** + * 数组是否为非空 + * + * @param array 数组 + * @return 是否为非空 + */ + public static boolean isNotEmpty(double[] array) { + return false == isEmpty(array); + } + + /** + * 数组是否为非空 + * + * @param array 数组 + * @return 是否为非空 + */ + public static boolean isNotEmpty(float[] array) { + return false == isEmpty(array); + } + + /** + * 数组是否为非空 + * + * @param array 数组 + * @return 是否为非空 + */ + public static boolean isNotEmpty(boolean[] array) { + return false == isEmpty(array); + } + + // ---------------------------------------------------------------------- resize + + /** + * 生成一个新的重新设置大小的数组
+ * 调整大小后拷贝原数组到新数组下。扩大则占位前N个位置,其它位置补充0,缩小则截断 + * + * @param bytes 原数组 + * @param newSize 新的数组大小 + * @return 调整后的新数组 + * @since 4.6.7 + */ + public static byte[] resize(byte[] bytes, int newSize) { + if (newSize < 0) { + return bytes; + } + final byte[] newArray = new byte[newSize]; + if (newSize > 0 && isNotEmpty(bytes)) { + System.arraycopy(bytes, 0, newArray, 0, Math.min(bytes.length, newSize)); + } + return newArray; + } + + // ---------------------------------------------------------------------- addAll + + /** + * 将多个数组合并在一起
+ * 忽略null的数组 + * + * @param arrays 数组集合 + * @return 合并后的数组 + * @since 4.6.9 + */ + public static byte[] addAll(byte[]... arrays) { + if (arrays.length == 1) { + return arrays[0]; + } + + // 计算总长度 + int length = 0; + for (byte[] array : arrays) { + if (null != array) { + length += array.length; + } + } + + final byte[] result = new byte[length]; + length = 0; + for (byte[] array : arrays) { + if (null != array) { + System.arraycopy(array, 0, result, length, array.length); + length += array.length; + } + } + return result; + } + + /** + * 将多个数组合并在一起
+ * 忽略null的数组 + * + * @param arrays 数组集合 + * @return 合并后的数组 + * @since 4.6.9 + */ + public static int[] addAll(int[]... arrays) { + if (arrays.length == 1) { + return arrays[0]; + } + + // 计算总长度 + int length = 0; + for (int[] array : arrays) { + if (null != array) { + length += array.length; + } + } + + final int[] result = new int[length]; + length = 0; + for (int[] array : arrays) { + if (null != array) { + System.arraycopy(array, 0, result, length, array.length); + length += array.length; + } + } + return result; + } + + /** + * 将多个数组合并在一起
+ * 忽略null的数组 + * + * @param arrays 数组集合 + * @return 合并后的数组 + * @since 4.6.9 + */ + public static long[] addAll(long[]... arrays) { + if (arrays.length == 1) { + return arrays[0]; + } + + // 计算总长度 + int length = 0; + for (long[] array : arrays) { + if (null != array) { + length += array.length; + } + } + + final long[] result = new long[length]; + length = 0; + for (long[] array : arrays) { + if (null != array) { + System.arraycopy(array, 0, result, length, array.length); + length += array.length; + } + } + return result; + } + + /** + * 将多个数组合并在一起
+ * 忽略null的数组 + * + * @param arrays 数组集合 + * @return 合并后的数组 + * @since 4.6.9 + */ + public static double[] addAll(double[]... arrays) { + if (arrays.length == 1) { + return arrays[0]; + } + + // 计算总长度 + int length = 0; + for (double[] array : arrays) { + if (null != array) { + length += array.length; + } + } + + final double[] result = new double[length]; + length = 0; + for (double[] array : arrays) { + if (null != array) { + System.arraycopy(array, 0, result, length, array.length); + length += array.length; + } + } + return result; + } + + /** + * 将多个数组合并在一起
+ * 忽略null的数组 + * + * @param arrays 数组集合 + * @return 合并后的数组 + * @since 4.6.9 + */ + public static float[] addAll(float[]... arrays) { + if (arrays.length == 1) { + return arrays[0]; + } + + // 计算总长度 + int length = 0; + for (float[] array : arrays) { + if (null != array) { + length += array.length; + } + } + + final float[] result = new float[length]; + length = 0; + for (float[] array : arrays) { + if (null != array) { + System.arraycopy(array, 0, result, length, array.length); + length += array.length; + } + } + return result; + } + + /** + * 将多个数组合并在一起
+ * 忽略null的数组 + * + * @param arrays 数组集合 + * @return 合并后的数组 + * @since 4.6.9 + */ + public static char[] addAll(char[]... arrays) { + if (arrays.length == 1) { + return arrays[0]; + } + + // 计算总长度 + int length = 0; + for (char[] array : arrays) { + if (null != array) { + length += array.length; + } + } + + final char[] result = new char[length]; + length = 0; + for (char[] array : arrays) { + if (null != array) { + System.arraycopy(array, 0, result, length, array.length); + length += array.length; + } + } + return result; + } + + /** + * 将多个数组合并在一起
+ * 忽略null的数组 + * + * @param arrays 数组集合 + * @return 合并后的数组 + * @since 4.6.9 + */ + public static boolean[] addAll(boolean[]... arrays) { + if (arrays.length == 1) { + return arrays[0]; + } + + // 计算总长度 + int length = 0; + for (boolean[] array : arrays) { + if (null != array) { + length += array.length; + } + } + + final boolean[] result = new boolean[length]; + length = 0; + for (boolean[] array : arrays) { + if (null != array) { + System.arraycopy(array, 0, result, length, array.length); + length += array.length; + } + } + return result; + } + + /** + * 将多个数组合并在一起
+ * 忽略null的数组 + * + * @param arrays 数组集合 + * @return 合并后的数组 + * @since 4.6.9 + */ + public static short[] addAll(short[]... arrays) { + if (arrays.length == 1) { + return arrays[0]; + } + + // 计算总长度 + int length = 0; + for (short[] array : arrays) { + if (null != array) { + length += array.length; + } + } + + final short[] result = new short[length]; + length = 0; + for (short[] array : arrays) { + if (null != array) { + System.arraycopy(array, 0, result, length, array.length); + length += array.length; + } + } + return result; + } + + // ---------------------------------------------------------------------- range + + /** + * 生成一个从0开始的数字列表
+ * + * @param excludedEnd 结束的数字(不包含) + * @return 数字列表 + */ + public static int[] range(int excludedEnd) { + return range(0, excludedEnd, 1); + } + + /** + * 生成一个数字列表
+ * 自动判定正序反序 + * + * @param includedStart 开始的数字(包含) + * @param excludedEnd 结束的数字(不包含) + * @return 数字列表 + */ + public static int[] range(int includedStart, int excludedEnd) { + return range(includedStart, excludedEnd, 1); + } + + /** + * 生成一个数字列表
+ * 自动判定正序反序 + * + * @param includedStart 开始的数字(包含) + * @param excludedEnd 结束的数字(不包含) + * @param step 步进 + * @return 数字列表 + */ + public static int[] range(int includedStart, int excludedEnd, int step) { + if (includedStart > excludedEnd) { + int tmp = includedStart; + includedStart = excludedEnd; + excludedEnd = tmp; + } + + if (step <= 0) { + step = 1; + } + + int deviation = excludedEnd - includedStart; + int length = deviation / step; + if (deviation % step != 0) { + length += 1; + } + int[] range = new int[length]; + for (int i = 0; i < length; i++) { + range[i] = includedStart; + includedStart += step; + } + return range; + } + + // ---------------------------------------------------------------------- split + + /** + * 拆分byte数组为几个等份(最后一份可能小于len) + * + * @param array 数组 + * @param len 每个小节的长度 + * @return 拆分后的数组 + */ + public static byte[][] split(byte[] array, int len) { + int x = array.length / len; + int y = array.length % len; + int z = 0; + if (y != 0) { + z = 1; + } + byte[][] arrays = new byte[x + z][]; + byte[] arr; + for (int i = 0; i < x + z; i++) { + arr = new byte[len]; + if (i == x + z - 1 && y != 0) { + System.arraycopy(array, i * len, arr, 0, y); + } else { + System.arraycopy(array, i * len, arr, 0, len); + } + arrays[i] = arr; + } + return arrays; + } + + // ---------------------------------------------------------------------- indexOf、LastIndexOf、contains + + /** + * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int indexOf(long[] array, long value) { + if (null != array) { + for (int i = 0; i < array.length; i++) { + if (value == array[i]) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int lastIndexOf(long[] array, long value) { + if (null != array) { + for (int i = array.length - 1; i >= 0; i--) { + if (value == array[i]) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 数组中是否包含元素 + * + * @param array 数组 + * @param value 被检查的元素 + * @return 是否包含 + * @since 3.0.7 + */ + public static boolean contains(long[] array, long value) { + return indexOf(array, value) > INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int indexOf(int[] array, int value) { + if (null != array) { + for (int i = 0; i < array.length; i++) { + if (value == array[i]) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int lastIndexOf(int[] array, int value) { + if (null != array) { + for (int i = array.length - 1; i >= 0; i--) { + if (value == array[i]) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 数组中是否包含元素 + * + * @param array 数组 + * @param value 被检查的元素 + * @return 是否包含 + * @since 3.0.7 + */ + public static boolean contains(int[] array, int value) { + return indexOf(array, value) > INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int indexOf(short[] array, short value) { + if (null != array) { + for (int i = 0; i < array.length; i++) { + if (value == array[i]) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int lastIndexOf(short[] array, short value) { + if (null != array) { + for (int i = array.length - 1; i >= 0; i--) { + if (value == array[i]) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 数组中是否包含元素 + * + * @param array 数组 + * @param value 被检查的元素 + * @return 是否包含 + * @since 3.0.7 + */ + public static boolean contains(short[] array, short value) { + return indexOf(array, value) > INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int indexOf(char[] array, char value) { + if (null != array) { + for (int i = 0; i < array.length; i++) { + if (value == array[i]) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int lastIndexOf(char[] array, char value) { + if (null != array) { + for (int i = array.length - 1; i >= 0; i--) { + if (value == array[i]) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 数组中是否包含元素 + * + * @param array 数组 + * @param value 被检查的元素 + * @return 是否包含 + * @since 3.0.7 + */ + public static boolean contains(char[] array, char value) { + return indexOf(array, value) > INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int indexOf(byte[] array, byte value) { + if (null != array) { + for (int i = 0; i < array.length; i++) { + if (value == array[i]) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int lastIndexOf(byte[] array, byte value) { + if (null != array) { + for (int i = array.length - 1; i >= 0; i--) { + if (value == array[i]) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 数组中是否包含元素 + * + * @param array 数组 + * @param value 被检查的元素 + * @return 是否包含 + * @since 3.0.7 + */ + public static boolean contains(byte[] array, byte value) { + return indexOf(array, value) > INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int indexOf(double[] array, double value) { + if (null != array) { + for (int i = 0; i < array.length; i++) { + if (NumberUtil.equals(value, array[i])) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int lastIndexOf(double[] array, double value) { + if (null != array) { + for (int i = array.length - 1; i >= 0; i--) { + if (NumberUtil.equals(value, array[i])) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 数组中是否包含元素 + * + * @param array 数组 + * @param value 被检查的元素 + * @return 是否包含 + * @since 3.0.7 + */ + public static boolean contains(double[] array, double value) { + return indexOf(array, value) > INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int indexOf(float[] array, float value) { + if (null != array) { + for (int i = 0; i < array.length; i++) { + if (NumberUtil.equals(value, array[i])) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int lastIndexOf(float[] array, float value) { + if (null != array) { + for (int i = array.length - 1; i >= 0; i--) { + if (NumberUtil.equals(value, array[i])) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 数组中是否包含元素 + * + * @param array 数组 + * @param value 被检查的元素 + * @return 是否包含 + * @since 3.0.7 + */ + public static boolean contains(float[] array, float value) { + return indexOf(array, value) > INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int indexOf(boolean[] array, boolean value) { + if (null != array) { + for (int i = 0; i < array.length; i++) { + if (value == array[i]) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 返回数组中指定元素所在最后的位置,未找到返回{@link #INDEX_NOT_FOUND} + * + * @param array 数组 + * @param value 被检查的元素 + * @return 数组中指定元素所在位置,未找到返回{@link #INDEX_NOT_FOUND} + * @since 3.0.7 + */ + public static int lastIndexOf(boolean[] array, boolean value) { + if (null != array) { + for (int i = array.length - 1; i >= 0; i--) { + if (value == array[i]) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + * 数组中是否包含元素 + * + * @param array 数组 + * @param value 被检查的元素 + * @return 是否包含 + * @since 3.0.7 + */ + public static boolean contains(boolean[] array, boolean value) { + return indexOf(array, value) > INDEX_NOT_FOUND; + } + + // ------------------------------------------------------------------- Wrap and unwrap + + /** + * 将原始类型数组包装为包装类型 + * + * @param values 原始类型数组 + * @return 包装类型数组 + */ + public static Integer[] wrap(int... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new Integer[0]; + } + + final Integer[] array = new Integer[length]; + for (int i = 0; i < length; i++) { + array[i] = values[i]; + } + return array; + } + + /** + * 包装类数组转为原始类型数组,null转为0 + * + * @param values 包装类型数组 + * @return 原始类型数组 + */ + public static int[] unWrap(Integer... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new int[0]; + } + + final int[] array = new int[length]; + for (int i = 0; i < length; i++) { + array[i] = ObjectUtil.defaultIfNull(values[i], 0); + } + return array; + } + + /** + * 将原始类型数组包装为包装类型 + * + * @param values 原始类型数组 + * @return 包装类型数组 + */ + public static Long[] wrap(long... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new Long[0]; + } + + final Long[] array = new Long[length]; + for (int i = 0; i < length; i++) { + array[i] = values[i]; + } + return array; + } + + /** + * 包装类数组转为原始类型数组 + * + * @param values 包装类型数组 + * @return 原始类型数组 + */ + public static long[] unWrap(Long... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new long[0]; + } + + final long[] array = new long[length]; + for (int i = 0; i < length; i++) { + array[i] = ObjectUtil.defaultIfNull(values[i], 0L); + } + return array; + } + + /** + * 将原始类型数组包装为包装类型 + * + * @param values 原始类型数组 + * @return 包装类型数组 + */ + public static Character[] wrap(char... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new Character[0]; + } + + final Character[] array = new Character[length]; + for (int i = 0; i < length; i++) { + array[i] = values[i]; + } + return array; + } + + /** + * 包装类数组转为原始类型数组 + * + * @param values 包装类型数组 + * @return 原始类型数组 + */ + public static char[] unWrap(Character... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new char[0]; + } + + char[] array = new char[length]; + for (int i = 0; i < length; i++) { + array[i] = ObjectUtil.defaultIfNull(values[i], Character.MIN_VALUE); + } + return array; + } + + /** + * 将原始类型数组包装为包装类型 + * + * @param values 原始类型数组 + * @return 包装类型数组 + */ + public static Byte[] wrap(byte... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new Byte[0]; + } + + final Byte[] array = new Byte[length]; + for (int i = 0; i < length; i++) { + array[i] = values[i]; + } + return array; + } + + /** + * 包装类数组转为原始类型数组 + * + * @param values 包装类型数组 + * @return 原始类型数组 + */ + public static byte[] unWrap(Byte... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new byte[0]; + } + + final byte[] array = new byte[length]; + for (int i = 0; i < length; i++) { + array[i] = ObjectUtil.defaultIfNull(values[i], (byte) 0); + } + return array; + } + + /** + * 将原始类型数组包装为包装类型 + * + * @param values 原始类型数组 + * @return 包装类型数组 + */ + public static Short[] wrap(short... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new Short[0]; + } + + final Short[] array = new Short[length]; + for (int i = 0; i < length; i++) { + array[i] = values[i]; + } + return array; + } + + /** + * 包装类数组转为原始类型数组 + * + * @param values 包装类型数组 + * @return 原始类型数组 + */ + public static short[] unWrap(Short... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new short[0]; + } + + final short[] array = new short[length]; + for (int i = 0; i < length; i++) { + array[i] = ObjectUtil.defaultIfNull(values[i], (short) 0); + } + return array; + } + + /** + * 将原始类型数组包装为包装类型 + * + * @param values 原始类型数组 + * @return 包装类型数组 + */ + public static Float[] wrap(float... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new Float[0]; + } + + final Float[] array = new Float[length]; + for (int i = 0; i < length; i++) { + array[i] = values[i]; + } + return array; + } + + /** + * 包装类数组转为原始类型数组 + * + * @param values 包装类型数组 + * @return 原始类型数组 + */ + public static float[] unWrap(Float... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new float[0]; + } + + final float[] array = new float[length]; + for (int i = 0; i < length; i++) { + array[i] = ObjectUtil.defaultIfNull(values[i], 0F); + } + return array; + } + + /** + * 将原始类型数组包装为包装类型 + * + * @param values 原始类型数组 + * @return 包装类型数组 + */ + public static Double[] wrap(double... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new Double[0]; + } + + final Double[] array = new Double[length]; + for (int i = 0; i < length; i++) { + array[i] = values[i]; + } + return array; + } + + /** + * 包装类数组转为原始类型数组 + * + * @param values 包装类型数组 + * @return 原始类型数组 + */ + public static double[] unWrap(Double... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new double[0]; + } + + final double[] array = new double[length]; + for (int i = 0; i < length; i++) { + array[i] = ObjectUtil.defaultIfNull(values[i], 0D); + } + return array; + } + + /** + * 将原始类型数组包装为包装类型 + * + * @param values 原始类型数组 + * @return 包装类型数组 + */ + public static Boolean[] wrap(boolean... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new Boolean[0]; + } + + final Boolean[] array = new Boolean[length]; + for (int i = 0; i < length; i++) { + array[i] = values[i]; + } + return array; + } + + /** + * 包装类数组转为原始类型数组 + * + * @param values 包装类型数组 + * @return 原始类型数组 + */ + public static boolean[] unWrap(Boolean... values) { + if (null == values) { + return null; + } + final int length = values.length; + if (0 == length) { + return new boolean[0]; + } + + final boolean[] array = new boolean[length]; + for (int i = 0; i < length; i++) { + array[i] = ObjectUtil.defaultIfNull(values[i], false); + } + return array; + } + + // ------------------------------------------------------------------- sub + + /** + * 获取子数组 + * + * @param array 数组 + * @param start 开始位置(包括) + * @param end 结束位置(不包括) + * @return 新的数组 + * @see Arrays#copyOfRange(Object[], int, int) + * @since 4.5.2 + */ + public static byte[] sub(byte[] array, int start, int end) { + int length = Array.getLength(array); + if (start < 0) { + start += length; + } + if (end < 0) { + end += length; + } + if (start == length) { + return new byte[0]; + } + if (start > end) { + int tmp = start; + start = end; + end = tmp; + } + if (end > length) { + if (start >= length) { + return new byte[0]; + } + end = length; + } + return Arrays.copyOfRange(array, start, end); + } + + /** + * 获取子数组 + * + * @param array 数组 + * @param start 开始位置(包括) + * @param end 结束位置(不包括) + * @return 新的数组 + * @see Arrays#copyOfRange(Object[], int, int) + * @since 4.5.2 + */ + public static int[] sub(int[] array, int start, int end) { + int length = Array.getLength(array); + if (start < 0) { + start += length; + } + if (end < 0) { + end += length; + } + if (start == length) { + return new int[0]; + } + if (start > end) { + int tmp = start; + start = end; + end = tmp; + } + if (end > length) { + if (start >= length) { + return new int[0]; + } + end = length; + } + return Arrays.copyOfRange(array, start, end); + } + + /** + * 获取子数组 + * + * @param array 数组 + * @param start 开始位置(包括) + * @param end 结束位置(不包括) + * @return 新的数组 + * @see Arrays#copyOfRange(Object[], int, int) + * @since 4.5.2 + */ + public static long[] sub(long[] array, int start, int end) { + int length = Array.getLength(array); + if (start < 0) { + start += length; + } + if (end < 0) { + end += length; + } + if (start == length) { + return new long[0]; + } + if (start > end) { + int tmp = start; + start = end; + end = tmp; + } + if (end > length) { + if (start >= length) { + return new long[0]; + } + end = length; + } + return Arrays.copyOfRange(array, start, end); + } + + /** + * 获取子数组 + * + * @param array 数组 + * @param start 开始位置(包括) + * @param end 结束位置(不包括) + * @return 新的数组 + * @see Arrays#copyOfRange(Object[], int, int) + * @since 4.5.2 + */ + public static short[] sub(short[] array, int start, int end) { + int length = Array.getLength(array); + if (start < 0) { + start += length; + } + if (end < 0) { + end += length; + } + if (start == length) { + return new short[0]; + } + if (start > end) { + int tmp = start; + start = end; + end = tmp; + } + if (end > length) { + if (start >= length) { + return new short[0]; + } + end = length; + } + return Arrays.copyOfRange(array, start, end); + } + + /** + * 获取子数组 + * + * @param array 数组 + * @param start 开始位置(包括) + * @param end 结束位置(不包括) + * @return 新的数组 + * @see Arrays#copyOfRange(Object[], int, int) + * @since 4.5.2 + */ + public static char[] sub(char[] array, int start, int end) { + int length = Array.getLength(array); + if (start < 0) { + start += length; + } + if (end < 0) { + end += length; + } + if (start == length) { + return new char[0]; + } + if (start > end) { + int tmp = start; + start = end; + end = tmp; + } + if (end > length) { + if (start >= length) { + return new char[0]; + } + end = length; + } + return Arrays.copyOfRange(array, start, end); + } + + /** + * 获取子数组 + * + * @param array 数组 + * @param start 开始位置(包括) + * @param end 结束位置(不包括) + * @return 新的数组 + * @see Arrays#copyOfRange(Object[], int, int) + * @since 4.5.2 + */ + public static double[] sub(double[] array, int start, int end) { + int length = Array.getLength(array); + if (start < 0) { + start += length; + } + if (end < 0) { + end += length; + } + if (start == length) { + return new double[0]; + } + if (start > end) { + int tmp = start; + start = end; + end = tmp; + } + if (end > length) { + if (start >= length) { + return new double[0]; + } + end = length; + } + return Arrays.copyOfRange(array, start, end); + } + + /** + * 获取子数组 + * + * @param array 数组 + * @param start 开始位置(包括) + * @param end 结束位置(不包括) + * @return 新的数组 + * @see Arrays#copyOfRange(Object[], int, int) + * @since 4.5.2 + */ + public static float[] sub(float[] array, int start, int end) { + int length = Array.getLength(array); + if (start < 0) { + start += length; + } + if (end < 0) { + end += length; + } + if (start == length) { + return new float[0]; + } + if (start > end) { + int tmp = start; + start = end; + end = tmp; + } + if (end > length) { + if (start >= length) { + return new float[0]; + } + end = length; + } + return Arrays.copyOfRange(array, start, end); + } + + /** + * 获取子数组 + * + * @param array 数组 + * @param start 开始位置(包括) + * @param end 结束位置(不包括) + * @return 新的数组 + * @see Arrays#copyOfRange(Object[], int, int) + * @since 4.5.2 + */ + public static boolean[] sub(boolean[] array, int start, int end) { + int length = Array.getLength(array); + if (start < 0) { + start += length; + } + if (end < 0) { + end += length; + } + if (start == length) { + return new boolean[0]; + } + if (start > end) { + int tmp = start; + start = end; + end = tmp; + } + if (end > length) { + if (start >= length) { + return new boolean[0]; + } + end = length; + } + return Arrays.copyOfRange(array, start, end); + } + + // ------------------------------------------------------------------- join + + /** + * 以 conjunction 为分隔符将数组转换为字符串 + * + * @param array 数组 + * @param conjunction 分隔符 + * @return 连接后的字符串 + */ + public static String join(int[] array, CharSequence conjunction) { + if (null == array) { + return null; + } + + final StringBuilder sb = new StringBuilder(); + boolean isFirst = true; + for (int item : array) { + if (isFirst) { + isFirst = false; + } else { + sb.append(conjunction); + } + sb.append(item); + } + return sb.toString(); + } + + /** + * 以 conjunction 为分隔符将数组转换为字符串 + * + * @param array 数组 + * @param conjunction 分隔符 + * @return 连接后的字符串 + */ + public static String join(short[] array, CharSequence conjunction) { + if (null == array) { + return null; + } + + final StringBuilder sb = new StringBuilder(); + boolean isFirst = true; + for (short item : array) { + if (isFirst) { + isFirst = false; + } else { + sb.append(conjunction); + } + sb.append(item); + } + return sb.toString(); + } + + /** + * 以 conjunction 为分隔符将数组转换为字符串 + * + * @param array 数组 + * @param conjunction 分隔符 + * @return 连接后的字符串 + */ + public static String join(char[] array, CharSequence conjunction) { + if (null == array) { + return null; + } + + final StringBuilder sb = new StringBuilder(); + boolean isFirst = true; + for (char item : array) { + if (isFirst) { + isFirst = false; + } else { + sb.append(conjunction); + } + sb.append(item); + } + return sb.toString(); + } + + /** + * 以 conjunction 为分隔符将数组转换为字符串 + * + * @param array 数组 + * @param conjunction 分隔符 + * @return 连接后的字符串 + */ + public static String join(byte[] array, CharSequence conjunction) { + if (null == array) { + return null; + } + + final StringBuilder sb = new StringBuilder(); + boolean isFirst = true; + for (byte item : array) { + if (isFirst) { + isFirst = false; + } else { + sb.append(conjunction); + } + sb.append(item); + } + return sb.toString(); + } + + /** + * 以 conjunction 为分隔符将数组转换为字符串 + * + * @param array 数组 + * @param conjunction 分隔符 + * @return 连接后的字符串 + */ + public static String join(boolean[] array, CharSequence conjunction) { + if (null == array) { + return null; + } + + final StringBuilder sb = new StringBuilder(); + boolean isFirst = true; + for (boolean item : array) { + if (isFirst) { + isFirst = false; + } else { + sb.append(conjunction); + } + sb.append(item); + } + return sb.toString(); + } + + /** + * 以 conjunction 为分隔符将数组转换为字符串 + * + * @param array 数组 + * @param conjunction 分隔符 + * @return 连接后的字符串 + */ + public static String join(float[] array, CharSequence conjunction) { + if (null == array) { + return null; + } + + final StringBuilder sb = new StringBuilder(); + boolean isFirst = true; + for (float item : array) { + if (isFirst) { + isFirst = false; + } else { + sb.append(conjunction); + } + sb.append(item); + } + return sb.toString(); + } + + /** + * 以 conjunction 为分隔符将数组转换为字符串 + * + * @param array 数组 + * @param conjunction 分隔符 + * @return 连接后的字符串 + */ + public static String join(double[] array, CharSequence conjunction) { + if (null == array) { + return null; + } + + final StringBuilder sb = new StringBuilder(); + boolean isFirst = true; + for (double item : array) { + if (isFirst) { + isFirst = false; + } else { + sb.append(conjunction); + } + sb.append(item); + } + return sb.toString(); + } + + // ------------------------------------------------------------------- remove + + /** + * 移除数组中对应位置的元素
+ * copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param index 位置,如果位置小于0或者大于长度,返回原数组 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static long[] remove(long[] array, int index) throws IllegalArgumentException { + return (long[]) remove((Object) array, index); + } + + /** + * 移除数组中对应位置的元素
+ * copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param index 位置,如果位置小于0或者大于长度,返回原数组 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static int[] remove(int[] array, int index) throws IllegalArgumentException { + return (int[]) remove((Object) array, index); + } + + /** + * 移除数组中对应位置的元素
+ * copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param index 位置,如果位置小于0或者大于长度,返回原数组 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static short[] remove(short[] array, int index) throws IllegalArgumentException { + return (short[]) remove((Object) array, index); + } + + /** + * 移除数组中对应位置的元素
+ * copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param index 位置,如果位置小于0或者大于长度,返回原数组 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static char[] remove(char[] array, int index) throws IllegalArgumentException { + return (char[]) remove((Object) array, index); + } + + /** + * 移除数组中对应位置的元素
+ * copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param index 位置,如果位置小于0或者大于长度,返回原数组 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static byte[] remove(byte[] array, int index) throws IllegalArgumentException { + return (byte[]) remove((Object) array, index); + } + + /** + * 移除数组中对应位置的元素
+ * copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param index 位置,如果位置小于0或者大于长度,返回原数组 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static double[] remove(double[] array, int index) throws IllegalArgumentException { + return (double[]) remove((Object) array, index); + } + + /** + * 移除数组中对应位置的元素
+ * copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param index 位置,如果位置小于0或者大于长度,返回原数组 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static float[] remove(float[] array, int index) throws IllegalArgumentException { + return (float[]) remove((Object) array, index); + } + + /** + * 移除数组中对应位置的元素
+ * copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param index 位置,如果位置小于0或者大于长度,返回原数组 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static boolean[] remove(boolean[] array, int index) throws IllegalArgumentException { + return (boolean[]) remove((Object) array, index); + } + + /** + * 移除数组中对应位置的元素
+ * copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param index 位置,如果位置小于0或者大于长度,返回原数组 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + @SuppressWarnings("SuspiciousSystemArraycopy") + public static Object remove(Object array, int index) throws IllegalArgumentException { + if (null == array) { + return null; + } + int length = Array.getLength(array); + if (index < 0 || index >= length) { + return array; + } + + final Object result = Array.newInstance(array.getClass().getComponentType(), length - 1); + System.arraycopy(array, 0, result, 0, index); + if (index < length - 1) { + // 后半部分 + System.arraycopy(array, index + 1, result, index, length - index - 1); + } + + return result; + } + + // ---------------------------------------------------------------------- removeEle + + /** + * 移除数组中指定的元素
+ * 只会移除匹配到的第一个元素 copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param element 要移除的元素 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static long[] removeEle(long[] array, long element) throws IllegalArgumentException { + return remove(array, indexOf(array, element)); + } + + /** + * 移除数组中指定的元素
+ * 只会移除匹配到的第一个元素 copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param element 要移除的元素 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static int[] removeEle(int[] array, int element) throws IllegalArgumentException { + return remove(array, indexOf(array, element)); + } + + /** + * 移除数组中指定的元素
+ * 只会移除匹配到的第一个元素 copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param element 要移除的元素 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static short[] removeEle(short[] array, short element) throws IllegalArgumentException { + return remove(array, indexOf(array, element)); + } + + /** + * 移除数组中指定的元素
+ * 只会移除匹配到的第一个元素 copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param element 要移除的元素 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static char[] removeEle(char[] array, char element) throws IllegalArgumentException { + return remove(array, indexOf(array, element)); + } + + /** + * 移除数组中指定的元素
+ * 只会移除匹配到的第一个元素 copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param element 要移除的元素 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static byte[] removeEle(byte[] array, byte element) throws IllegalArgumentException { + return remove(array, indexOf(array, element)); + } + + /** + * 移除数组中指定的元素
+ * 只会移除匹配到的第一个元素 copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param element 要移除的元素 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static double[] removeEle(double[] array, double element) throws IllegalArgumentException { + return remove(array, indexOf(array, element)); + } + + /** + * 移除数组中指定的元素
+ * 只会移除匹配到的第一个元素 copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param element 要移除的元素 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static float[] removeEle(float[] array, float element) throws IllegalArgumentException { + return remove(array, indexOf(array, element)); + } + + /** + * 移除数组中指定的元素
+ * 只会移除匹配到的第一个元素 copy from commons-lang + * + * @param array 数组对象,可以是对象数组,也可以原始类型数组 + * @param element 要移除的元素 + * @return 去掉指定元素后的新数组或原数组 + * @throws IllegalArgumentException 参数对象不为数组对象 + * @since 3.0.8 + */ + public static boolean[] removeEle(boolean[] array, boolean element) throws IllegalArgumentException { + return remove(array, indexOf(array, element)); + } + + // ---------------------------------------------------------------------- reverse + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @param startIndexInclusive 其实位置(包含) + * @param endIndexExclusive 结束位置(不包含) + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static long[] reverse(long[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (isEmpty(array)) { + return array; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + long tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + return array; + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static long[] reverse(long[] array) { + return reverse(array, 0, array.length); + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @param startIndexInclusive 其实位置(包含) + * @param endIndexExclusive 结束位置(不包含) + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static int[] reverse(int[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (isEmpty(array)) { + return array; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + int tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + return array; + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static int[] reverse(int[] array) { + return reverse(array, 0, array.length); + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @param startIndexInclusive 其实位置(包含) + * @param endIndexExclusive 结束位置(不包含) + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static short[] reverse(short[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (isEmpty(array)) { + return array; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + short tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + return array; + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static short[] reverse(short[] array) { + return reverse(array, 0, array.length); + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @param startIndexInclusive 其实位置(包含) + * @param endIndexExclusive 结束位置(不包含) + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static char[] reverse(char[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (isEmpty(array)) { + return array; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + char tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + return array; + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static char[] reverse(char[] array) { + return reverse(array, 0, array.length); + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @param startIndexInclusive 其实位置(包含) + * @param endIndexExclusive 结束位置(不包含) + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static byte[] reverse(byte[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (isEmpty(array)) { + return array; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + byte tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + return array; + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static byte[] reverse(byte[] array) { + return reverse(array, 0, array.length); + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @param startIndexInclusive 其实位置(包含) + * @param endIndexExclusive 结束位置(不包含) + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static double[] reverse(double[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (isEmpty(array)) { + return array; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + double tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + return array; + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static double[] reverse(double[] array) { + return reverse(array, 0, array.length); + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @param startIndexInclusive 其实位置(包含) + * @param endIndexExclusive 结束位置(不包含) + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static float[] reverse(float[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (isEmpty(array)) { + return array; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + float tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + return array; + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static float[] reverse(float[] array) { + return reverse(array, 0, array.length); + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @param startIndexInclusive 其实位置(包含) + * @param endIndexExclusive 结束位置(不包含) + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static boolean[] reverse(boolean[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (isEmpty(array)) { + return array; + } + int i = Math.max(startIndexInclusive, 0); + int j = Math.min(array.length, endIndexExclusive) - 1; + boolean tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + return array; + } + + /** + * 反转数组,会变更原数组 + * + * @param array 数组,会变更 + * @return 变更后的原数组 + * @since 3.0.9 + */ + public static boolean[] reverse(boolean[] array) { + return reverse(array, 0, array.length); + } + + // ------------------------------------------------------------------------------------------------------------ min and max + + /** + * 取最小值 + * + * @param numberArray 数字数组 + * @return 最小值 + * @since 3.0.9 + */ + public static long min(long... numberArray) { + if (isEmpty(numberArray)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + long min = numberArray[0]; + for (int i = 1; i < numberArray.length; i++) { + if (min > numberArray[i]) { + min = numberArray[i]; + } + } + return min; + } + + /** + * 取最小值 + * + * @param numberArray 数字数组 + * @return 最小值 + * @since 3.0.9 + */ + public static int min(int... numberArray) { + if (isEmpty(numberArray)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + int min = numberArray[0]; + for (int i = 1; i < numberArray.length; i++) { + if (min > numberArray[i]) { + min = numberArray[i]; + } + } + return min; + } + + /** + * 取最小值 + * + * @param numberArray 数字数组 + * @return 最小值 + * @since 3.0.9 + */ + public static short min(short... numberArray) { + if (isEmpty(numberArray)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + short min = numberArray[0]; + for (int i = 1; i < numberArray.length; i++) { + if (min > numberArray[i]) { + min = numberArray[i]; + } + } + return min; + } + + /** + * 取最小值 + * + * @param numberArray 数字数组 + * @return 最小值 + * @since 3.0.9 + */ + public static char min(char... numberArray) { + if (isEmpty(numberArray)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + char min = numberArray[0]; + for (int i = 1; i < numberArray.length; i++) { + if (min > numberArray[i]) { + min = numberArray[i]; + } + } + return min; + } + + /** + * 取最小值 + * + * @param numberArray 数字数组 + * @return 最小值 + * @since 3.0.9 + */ + public static byte min(byte... numberArray) { + if (isEmpty(numberArray)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + byte min = numberArray[0]; + for (int i = 1; i < numberArray.length; i++) { + if (min > numberArray[i]) { + min = numberArray[i]; + } + } + return min; + } + + /** + * 取最小值 + * + * @param numberArray 数字数组 + * @return 最小值 + * @since 3.0.9 + */ + public static double min(double... numberArray) { + if (isEmpty(numberArray)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + double min = numberArray[0]; + for (int i = 1; i < numberArray.length; i++) { + if (min > numberArray[i]) { + min = numberArray[i]; + } + } + return min; + } + + /** + * 取最小值 + * + * @param numberArray 数字数组 + * @return 最小值 + * @since 3.0.9 + */ + public static float min(float... numberArray) { + if (isEmpty(numberArray)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + float min = numberArray[0]; + for (int i = 1; i < numberArray.length; i++) { + if (min > numberArray[i]) { + min = numberArray[i]; + } + } + return min; + } + + /** + * 取最大值 + * + * @param numberArray 数字数组 + * @return 最大值 + * @since 3.0.9 + */ + public static long max(long... numberArray) { + if (isEmpty(numberArray)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + long max = numberArray[0]; + for (int i = 1; i < numberArray.length; i++) { + if (max < numberArray[i]) { + max = numberArray[i]; + } + } + return max; + } + + /** + * 取最大值 + * + * @param numberArray 数字数组 + * @return 最大值 + * @since 3.0.9 + */ + public static int max(int... numberArray) { + if (isEmpty(numberArray)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + int max = numberArray[0]; + for (int i = 1; i < numberArray.length; i++) { + if (max < numberArray[i]) { + max = numberArray[i]; + } + } + return max; + } + + /** + * 取最大值 + * + * @param numberArray 数字数组 + * @return 最大值 + * @since 3.0.9 + */ + public static short max(short... numberArray) { + if (isEmpty(numberArray)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + short max = numberArray[0]; + for (int i = 1; i < numberArray.length; i++) { + if (max < numberArray[i]) { + max = numberArray[i]; + } + } + return max; + } + + /** + * 取最大值 + * + * @param numberArray 数字数组 + * @return 最大值 + * @since 3.0.9 + */ + public static char max(char... numberArray) { + if (isEmpty(numberArray)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + char max = numberArray[0]; + for (int i = 1; i < numberArray.length; i++) { + if (max < numberArray[i]) { + max = numberArray[i]; + } + } + return max; + } + + /** + * 取最大值 + * + * @param numberArray 数字数组 + * @return 最大值 + * @since 3.0.9 + */ + public static byte max(byte... numberArray) { + if (isEmpty(numberArray)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + byte max = numberArray[0]; + for (int i = 1; i < numberArray.length; i++) { + if (max < numberArray[i]) { + max = numberArray[i]; + } + } + return max; + } + + /** + * 取最大值 + * + * @param numberArray 数字数组 + * @return 最大值 + * @since 3.0.9 + */ + public static double max(double... numberArray) { + if (isEmpty(numberArray)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + double max = numberArray[0]; + for (int i = 1; i < numberArray.length; i++) { + if (max < numberArray[i]) { + max = numberArray[i]; + } + } + return max; + } + + /** + * 取最大值 + * + * @param numberArray 数字数组 + * @return 最大值 + * @since 3.0.9 + */ + public static float max(float... numberArray) { + if (isEmpty(numberArray)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + float max = numberArray[0]; + for (int i = 1; i < numberArray.length; i++) { + if (max < numberArray[i]) { + max = numberArray[i]; + } + } + return max; + } + + // ---------------------------------------------------------------------- shuffle + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static int[] shuffle(int[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static int[] shuffle(int[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static long[] shuffle(long[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static long[] shuffle(long[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static double[] shuffle(double[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static double[] shuffle(double[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static float[] shuffle(float[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static float[] shuffle(float[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static boolean[] shuffle(boolean[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static boolean[] shuffle(boolean[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static byte[] shuffle(byte[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static byte[] shuffle(byte[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static char[] shuffle(char[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static char[] shuffle(char[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static short[] shuffle(short[] array) { + return shuffle(array, RandomUtil.getRandom()); + } + + /** + * 打乱数组顺序,会变更原数组 + * + * @param array 数组,会变更 + * @param random 随机数生成器 + * @return 打乱后的数组 + * @author FengBaoheng + * @since 5.5.2 + */ + public static short[] shuffle(short[] array, Random random) { + if (array == null || random == null || array.length <= 1) { + return array; + } + + for (int i = array.length; i > 1; i--) { + swap(array, i - 1, random.nextInt(i)); + } + + return array; + } + + // ---------------------------------------------------------------------- shuffle + + /** + * 交换数组中两个位置的值 + * + * @param array 数组 + * @param index1 位置1 + * @param index2 位置2 + * @return 交换后的数组,与传入数组为同一对象 + * @since 4.0.7 + */ + public static int[] swap(int[] array, int index1, int index2) { + if (isEmpty(array)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + int tmp = array[index1]; + array[index1] = array[index2]; + array[index2] = tmp; + return array; + } + + /** + * 交换数组中两个位置的值 + * + * @param array 数组 + * @param index1 位置1 + * @param index2 位置2 + * @return 交换后的数组,与传入数组为同一对象 + * @since 4.0.7 + */ + public static long[] swap(long[] array, int index1, int index2) { + if (isEmpty(array)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + long tmp = array[index1]; + array[index1] = array[index2]; + array[index2] = tmp; + return array; + } + + /** + * 交换数组中两个位置的值 + * + * @param array 数组 + * @param index1 位置1 + * @param index2 位置2 + * @return 交换后的数组,与传入数组为同一对象 + * @since 4.0.7 + */ + public static double[] swap(double[] array, int index1, int index2) { + if (isEmpty(array)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + double tmp = array[index1]; + array[index1] = array[index2]; + array[index2] = tmp; + return array; + } + + /** + * 交换数组中两个位置的值 + * + * @param array 数组 + * @param index1 位置1 + * @param index2 位置2 + * @return 交换后的数组,与传入数组为同一对象 + * @since 4.0.7 + */ + public static float[] swap(float[] array, int index1, int index2) { + if (isEmpty(array)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + float tmp = array[index1]; + array[index1] = array[index2]; + array[index2] = tmp; + return array; + } + + /** + * 交换数组中两个位置的值 + * + * @param array 数组 + * @param index1 位置1 + * @param index2 位置2 + * @return 交换后的数组,与传入数组为同一对象 + * @since 4.0.7 + */ + public static boolean[] swap(boolean[] array, int index1, int index2) { + if (isEmpty(array)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + boolean tmp = array[index1]; + array[index1] = array[index2]; + array[index2] = tmp; + return array; + } + + /** + * 交换数组中两个位置的值 + * + * @param array 数组 + * @param index1 位置1 + * @param index2 位置2 + * @return 交换后的数组,与传入数组为同一对象 + * @since 4.0.7 + */ + public static byte[] swap(byte[] array, int index1, int index2) { + if (isEmpty(array)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + byte tmp = array[index1]; + array[index1] = array[index2]; + array[index2] = tmp; + return array; + } + + /** + * 交换数组中两个位置的值 + * + * @param array 数组 + * @param index1 位置1 + * @param index2 位置2 + * @return 交换后的数组,与传入数组为同一对象 + * @since 4.0.7 + */ + public static char[] swap(char[] array, int index1, int index2) { + if (isEmpty(array)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + char tmp = array[index1]; + array[index1] = array[index2]; + array[index2] = tmp; + return array; + } + + /** + * 交换数组中两个位置的值 + * + * @param array 数组 + * @param index1 位置1 + * @param index2 位置2 + * @return 交换后的数组,与传入数组为同一对象 + * @since 4.0.7 + */ + public static short[] swap(short[] array, int index1, int index2) { + if (isEmpty(array)) { + throw new IllegalArgumentException("Number array must not empty !"); + } + short tmp = array[index1]; + array[index1] = array[index2]; + array[index2] = tmp; + return array; + } +} From 4827c61641a157e84a0a3a370bf473d49c344b0a Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 27 Nov 2020 12:03:01 +0800 Subject: [PATCH 12/18] fix code --- .../src/main/java/cn/hutool/cache/impl/AbstractCache.java | 4 ++-- hutool-cache/src/main/java/cn/hutool/cache/impl/CacheObj.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java b/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java index 8888324f82..844fcd2cae 100644 --- a/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java +++ b/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java @@ -45,11 +45,11 @@ public abstract class AbstractCache implements Cache { /** * 命中数 */ - protected AtomicLong hitCount; + protected AtomicLong hitCount = new AtomicLong(); /** * 丢失数 */ - protected AtomicLong missCount; + protected AtomicLong missCount = new AtomicLong(); // ---------------------------------------------------------------- put start @Override diff --git a/hutool-cache/src/main/java/cn/hutool/cache/impl/CacheObj.java b/hutool-cache/src/main/java/cn/hutool/cache/impl/CacheObj.java index fea9009ddf..1a8f082155 100644 --- a/hutool-cache/src/main/java/cn/hutool/cache/impl/CacheObj.java +++ b/hutool-cache/src/main/java/cn/hutool/cache/impl/CacheObj.java @@ -19,7 +19,7 @@ public class CacheObj implements Serializable{ /** 上次访问时间 */ private volatile long lastAccess; /** 访问次数 */ - protected AtomicLong accessCount; + protected AtomicLong accessCount = new AtomicLong(); /** 对象存活时长,0表示永久存活*/ private final long ttl; From 2954fe0520f8b4d5bd9ecba519d235297c7375e4 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 27 Nov 2020 14:20:17 +0800 Subject: [PATCH 13/18] rename --- CHANGELOG.md | 1 + .../cn/hutool/crypto/digest/{opt => otp}/HOTP.java | 2 +- .../crypto/digest/{opt/TOPT.java => otp/TOTP.java} | 12 ++++++------ .../crypto/digest/{opt => otp}/package-info.java | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) rename hutool-crypto/src/main/java/cn/hutool/crypto/digest/{opt => otp}/HOTP.java (95%) rename hutool-crypto/src/main/java/cn/hutool/crypto/digest/{opt/TOPT.java => otp/TOTP.java} (84%) rename hutool-crypto/src/main/java/cn/hutool/crypto/digest/{opt => otp}/package-info.java (88%) diff --git a/CHANGELOG.md b/CHANGELOG.md index df9bedd5f9..4641bd49b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ * 【core 】 DatePattern增加年月格式化常量(pr#220@Gitee) * 【core 】 ArrayUtil增加shuffle方法(pr#1255@Github) * 【core 】 ArrayUtil部分方法分离至PrimitiveArrayUtil +* 【crypto 】 opt改为otp包(issue#1257@Github) ### Bug修复 * 【cron 】 修复CronTimer可能死循环的问题(issue#1224@Github) diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/digest/opt/HOTP.java b/hutool-crypto/src/main/java/cn/hutool/crypto/digest/otp/HOTP.java similarity index 95% rename from hutool-crypto/src/main/java/cn/hutool/crypto/digest/opt/HOTP.java rename to hutool-crypto/src/main/java/cn/hutool/crypto/digest/otp/HOTP.java index cc3598aa5f..ba4b31623b 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/digest/opt/HOTP.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/digest/otp/HOTP.java @@ -1,4 +1,4 @@ -package cn.hutool.crypto.digest.opt; +package cn.hutool.crypto.digest.otp; import cn.hutool.crypto.digest.HMac; import cn.hutool.crypto.digest.HmacAlgorithm; diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/digest/opt/TOPT.java b/hutool-crypto/src/main/java/cn/hutool/crypto/digest/otp/TOTP.java similarity index 84% rename from hutool-crypto/src/main/java/cn/hutool/crypto/digest/opt/TOPT.java rename to hutool-crypto/src/main/java/cn/hutool/crypto/digest/otp/TOTP.java index 84ec7b5f5d..b03214c760 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/digest/opt/TOPT.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/digest/otp/TOTP.java @@ -1,4 +1,4 @@ -package cn.hutool.crypto.digest.opt; +package cn.hutool.crypto.digest.otp; import cn.hutool.crypto.digest.HmacAlgorithm; @@ -13,7 +13,7 @@ import java.time.Instant; * * @author Looly */ -public class TOPT extends HOTP { +public class TOTP extends HOTP { /** * 默认步进 (30秒). @@ -27,7 +27,7 @@ public class TOPT extends HOTP { * * @param key 共享密码,RFC 4226要求最少128位 */ - public TOPT(byte[] key) { + public TOTP(byte[] key) { this(DEFAULT_TIME_STEP, key); } @@ -37,7 +37,7 @@ public class TOPT extends HOTP { * @param timeStep 日期步进,用于生成移动因子(moving factor) * @param key 共享密码,RFC 4226要求最少128位 */ - public TOPT(Duration timeStep, byte[] key) { + public TOTP(Duration timeStep, byte[] key) { this(timeStep, DEFAULT_PASSWORD_LENGTH, key); } @@ -48,7 +48,7 @@ public class TOPT extends HOTP { * @param passwordLength 密码长度,可以是6,7,8 * @param key 共享密码,RFC 4226要求最少128位 */ - public TOPT(Duration timeStep, int passwordLength, byte[] key) { + public TOTP(Duration timeStep, int passwordLength, byte[] key) { this(timeStep, passwordLength, HOTP_HMAC_ALGORITHM, key); } @@ -60,7 +60,7 @@ public class TOPT extends HOTP { * @param algorithm HMAC算法枚举 * @param key 共享密码,RFC 4226要求最少128位 */ - public TOPT(Duration timeStep, int passwordLength, HmacAlgorithm algorithm, byte[] key) { + public TOTP(Duration timeStep, int passwordLength, HmacAlgorithm algorithm, byte[] key) { super(passwordLength, algorithm, key); this.timeStep = timeStep; } diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/digest/opt/package-info.java b/hutool-crypto/src/main/java/cn/hutool/crypto/digest/otp/package-info.java similarity index 88% rename from hutool-crypto/src/main/java/cn/hutool/crypto/digest/opt/package-info.java rename to hutool-crypto/src/main/java/cn/hutool/crypto/digest/otp/package-info.java index e496dd688b..be6e2b0f0d 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/digest/opt/package-info.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/digest/otp/package-info.java @@ -11,4 +11,4 @@ * * @author looly */ -package cn.hutool.crypto.digest.opt; \ No newline at end of file +package cn.hutool.crypto.digest.otp; \ No newline at end of file From a09861b033c00e41b80d0707146858d3e86cf6be Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 27 Nov 2020 17:01:35 +0800 Subject: [PATCH 14/18] add test --- CHANGELOG.md | 1 + hutool-json/src/main/java/cn/hutool/json/JSONObject.java | 2 +- .../src/test/java/cn/hutool/json/JSONObjectTest.java | 6 ++++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4641bd49b6..2586fe0867 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ * 【poi 】 修复ExcelUtil.getSaxReader使用非MarkSupport流报错问题(issue#1225@Github) * 【core 】 修复HexUtil.format问题(issue#I268XT@Gitee) * 【core 】 修复ZipUtil判断压缩文件是否位于压缩目录内的逻辑有误的问题(issue#1251@Github) +* 【json 】 修复JSONObject.accumulate问题 ------------------------------------------------------------------------------------------------------------- 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 3ce391de45..0edcec2209 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java @@ -432,7 +432,7 @@ public class JSONObject implements JSON, JSONGetter, Map InternalJSONUtil.testValidity(value); Object object = this.getObj(key); if (object == null) { - this.set(key, value instanceof JSONArray ? new JSONArray(this.config).set(value) : value); + this.set(key, (value instanceof JSONArray) ? value : new JSONArray(this.config).set(value)); } else if (object instanceof JSONArray) { ((JSONArray) object).set(value); } else { diff --git a/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java b/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java index 8ad66b43ed..802263c585 100644 --- a/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java @@ -535,4 +535,10 @@ public class JSONObjectTest { final String s = JSONUtil.toJsonStr(map); Console.log(s); } + + @Test + public void accumulateTest(){ + final JSONObject accumulate = JSONUtil.createObj().accumulate("key1", "value1"); + Assert.assertEquals("{\"key1\":[\"value1\"]}", accumulate.toString()); + } } From a302a11483c9dca528ac596ccb8ce309a3585cd3 Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 28 Nov 2020 23:29:10 +0800 Subject: [PATCH 15/18] add groupTimeInterval --- CHANGELOG.md | 2 + .../src/main/java/cn/hutool/cache/Cache.java | 12 +- .../java/cn/hutool/cache/CacheListener.java | 20 ++ .../cn/hutool/cache/impl/AbstractCache.java | 28 ++- .../java/cn/hutool/cache/test/CacheTest.java | 6 + .../hutool/core/date/GroupTimeInterval.java | 177 ++++++++++++++++++ .../cn/hutool/core/date/TimeInterval.java | 48 ++--- .../hutool/core/thread/ConcurrencyTester.java | 4 + .../cn/hutool/core/date/TimeIntervalTest.java | 20 ++ 9 files changed, 282 insertions(+), 35 deletions(-) create mode 100644 hutool-cache/src/main/java/cn/hutool/cache/CacheListener.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/date/GroupTimeInterval.java create mode 100644 hutool-core/src/test/java/cn/hutool/core/date/TimeIntervalTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 2586fe0867..413de071b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ * 【core 】 ArrayUtil增加shuffle方法(pr#1255@Github) * 【core 】 ArrayUtil部分方法分离至PrimitiveArrayUtil * 【crypto 】 opt改为otp包(issue#1257@Github) +* 【cache 】 增加CacheListener(issue#1257@Github) +* 【core 】 TimeInterval支持分组(issue#1238@Github) ### Bug修复 * 【cron 】 修复CronTimer可能死循环的问题(issue#1224@Github) diff --git a/hutool-cache/src/main/java/cn/hutool/cache/Cache.java b/hutool-cache/src/main/java/cn/hutool/cache/Cache.java index 1478b192ec..bc5172c712 100644 --- a/hutool-cache/src/main/java/cn/hutool/cache/Cache.java +++ b/hutool-cache/src/main/java/cn/hutool/cache/Cache.java @@ -45,7 +45,6 @@ public interface Cache extends Iterable, Serializable { * @param key 键 * @param object 缓存的对象 * @param timeout 失效时长,单位毫秒 - * @see Cache#put(Object, Object, long) */ void put(K key, V object, long timeout); @@ -159,4 +158,15 @@ public interface Cache extends Iterable, Serializable { * @return 是否包含key */ boolean containsKey(K key); + + /** + * 设置监听 + * + * @param listener 监听 + * @return this + * @since 5.5.2 + */ + default Cache setListener(CacheListener listener){ + return this; + } } diff --git a/hutool-cache/src/main/java/cn/hutool/cache/CacheListener.java b/hutool-cache/src/main/java/cn/hutool/cache/CacheListener.java new file mode 100644 index 0000000000..7e5ab018bc --- /dev/null +++ b/hutool-cache/src/main/java/cn/hutool/cache/CacheListener.java @@ -0,0 +1,20 @@ +package cn.hutool.cache; + +/** + * 缓存监听,用于实现缓存操作时的回调监听,例如缓存对象的移除事件等 + * + * @param 缓存键 + * @param 缓存值 + * @author looly + * @since 5.5.2 + */ +public interface CacheListener { + + /** + * 对象移除回调 + * + * @param key 键 + * @param cachedObject 被缓存的对象 + */ + void onRemove(K key, V cachedObject); +} diff --git a/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java b/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java index 844fcd2cae..fa54d16bae 100644 --- a/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java +++ b/hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java @@ -1,6 +1,7 @@ package cn.hutool.cache.impl; import cn.hutool.cache.Cache; +import cn.hutool.cache.CacheListener; import cn.hutool.core.collection.CopiedIter; import cn.hutool.core.lang.func.Func0; @@ -51,6 +52,11 @@ public abstract class AbstractCache implements Cache { */ protected AtomicLong missCount = new AtomicLong(); + /** + * 缓存监听 + */ + protected CacheListener listener; + // ---------------------------------------------------------------- put start @Override public void put(K key, V object) { @@ -164,7 +170,7 @@ public abstract class AbstractCache implements Cache { if (co.isExpired()) { missCount.getAndIncrement(); - } else{ + } else { // 命中 hitCount.getAndIncrement(); return co.get(isUpdateLastAccess); @@ -280,13 +286,29 @@ public abstract class AbstractCache implements Cache { // ---------------------------------------------------------------- common end /** - * 对象移除回调。默认无动作 + * 设置监听 + * + * @param listener 监听 + * @return this + * @since 5.5.2 + */ + public AbstractCache setListener(CacheListener listener) { + this.listener = listener; + return this; + } + + /** + * 对象移除回调。默认无动作
+ * 子类可重写此方法用于监听移除事件,如果重写,listener将无效 * * @param key 键 * @param cachedObject 被缓存的对象 */ protected void onRemove(K key, V cachedObject) { - // ignore + final CacheListener listener = this.listener; + if (null != listener) { + listener.onRemove(key, cachedObject); + } } /** diff --git a/hutool-cache/src/test/java/cn/hutool/cache/test/CacheTest.java b/hutool-cache/src/test/java/cn/hutool/cache/test/CacheTest.java index c1832ce287..1e843ae84e 100644 --- a/hutool-cache/src/test/java/cn/hutool/cache/test/CacheTest.java +++ b/hutool-cache/src/test/java/cn/hutool/cache/test/CacheTest.java @@ -18,6 +18,12 @@ public class CacheTest { @Test public void fifoCacheTest(){ Cache fifoCache = CacheUtil.newFIFOCache(3); + fifoCache.setListener((key, value)->{ + // 监听测试,此测试中只有key1被移除,测试是否监听成功 + Assert.assertEquals("key1", key); + Assert.assertEquals("value1", value); + }); + fifoCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3); fifoCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3); fifoCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3); diff --git a/hutool-core/src/main/java/cn/hutool/core/date/GroupTimeInterval.java b/hutool-core/src/main/java/cn/hutool/core/date/GroupTimeInterval.java new file mode 100644 index 0000000000..518959a8cf --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/date/GroupTimeInterval.java @@ -0,0 +1,177 @@ +package cn.hutool.core.date; + +import cn.hutool.core.util.ObjectUtil; + +import java.io.Serializable; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 分组计时器
+ * 计算某几个过程花费的时间,精确到毫秒或纳秒 + * + * @author Looly + * @since 5.5.2 + */ +public class GroupTimeInterval implements Serializable { + private static final long serialVersionUID = 1L; + + private final boolean isNano; + protected final Map groupMap; + + /** + * 构造 + * + * @param isNano 是否使用纳秒计数,false则使用毫秒 + */ + public GroupTimeInterval(boolean isNano) { + this.isNano = isNano; + groupMap = new ConcurrentHashMap<>(); + } + + /** + * 清空所有定时记录 + * + * @return this + */ + public GroupTimeInterval clear(){ + this.groupMap.clear(); + return this; + } + + /** + * 开始计时并返回当前时间 + * + * @param id 分组ID + * @return 开始计时并返回当前时间 + */ + public long start(String id) { + final long time = getTime(); + this.groupMap.put(id, time); + return time; + } + + /** + * 重新计时并返回从开始到当前的持续时间秒
+ * 如果此分组下没有记录,则返回0; + * + * @param id 分组ID + * @return 重新计时并返回从开始到当前的持续时间 + */ + public long intervalRestart(String id) { + final long now = getTime(); + return now - ObjectUtil.defaultIfNull(this.groupMap.put(id, now), now); + } + + //----------------------------------------------------------- Interval + + /** + * 从开始到当前的间隔时间(毫秒数)
+ * 如果使用纳秒计时,返回纳秒差,否则返回毫秒差
+ * 如果分组下没有开始时间,返回{@code null} + * + * @param id 分组ID + * @return 从开始到当前的间隔时间(毫秒数) + */ + public long interval(String id) { + final Long lastTime = this.groupMap.get(id); + if (null == lastTime) { + return 0; + } + return getTime() - lastTime; + } + + /** + * 从开始到当前的间隔时间 + * + * @param id 分组ID + * @param dateUnit 时间单位 + * @return 从开始到当前的间隔时间(毫秒数) + */ + public long interval(String id, DateUnit dateUnit) { + final long intervalMs = isNano ? interval(id) / 1000000L : interval(id); + if (DateUnit.MS == dateUnit) { + return intervalMs; + } + return intervalMs / dateUnit.getMillis(); + } + + /** + * 从开始到当前的间隔时间(毫秒数) + * + * @param id 分组ID + * @return 从开始到当前的间隔时间(毫秒数) + */ + public long intervalMs(String id) { + return interval(id, DateUnit.MS); + } + + /** + * 从开始到当前的间隔秒数,取绝对值 + * + * @param id 分组ID + * @return 从开始到当前的间隔秒数,取绝对值 + */ + public long intervalSecond(String id) { + return interval(id, DateUnit.SECOND); + } + + /** + * 从开始到当前的间隔分钟数,取绝对值 + * + * @param id 分组ID + * @return 从开始到当前的间隔分钟数,取绝对值 + */ + public long intervalMinute(String id) { + return interval(id, DateUnit.MINUTE); + } + + /** + * 从开始到当前的间隔小时数,取绝对值 + * + * @param id 分组ID + * @return 从开始到当前的间隔小时数,取绝对值 + */ + public long intervalHour(String id) { + return interval(id, DateUnit.HOUR); + } + + /** + * 从开始到当前的间隔天数,取绝对值 + * + * @param id 分组ID + * @return 从开始到当前的间隔天数,取绝对值 + */ + public long intervalDay(String id) { + return interval(id, DateUnit.DAY); + } + + /** + * 从开始到当前的间隔周数,取绝对值 + * + * @param id 分组ID + * @return 从开始到当前的间隔周数,取绝对值 + */ + public long intervalWeek(String id) { + return interval(id, DateUnit.WEEK); + } + + /** + * 从开始到当前的间隔时间(毫秒数),返回XX天XX小时XX分XX秒XX毫秒 + * + * @param id 分组ID + * @return 从开始到当前的间隔时间(毫秒数) + */ + public String intervalPretty(String id) { + return DateUtil.formatBetween(intervalMs(id)); + } + + /** + * 获取时间的毫秒或纳秒数,纳秒非时间戳 + * + * @return 时间 + */ + private long getTime() { + return this.isNano ? System.nanoTime() : System.currentTimeMillis(); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/date/TimeInterval.java b/hutool-core/src/main/java/cn/hutool/core/date/TimeInterval.java index 8168d2e705..2b58dbb9f6 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/TimeInterval.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/TimeInterval.java @@ -1,6 +1,6 @@ package cn.hutool.core.date; -import java.io.Serializable; +import cn.hutool.core.util.StrUtil; /** * 计时器
@@ -8,11 +8,9 @@ import java.io.Serializable; * * @author Looly */ -public class TimeInterval implements Serializable { +public class TimeInterval extends GroupTimeInterval { private static final long serialVersionUID = 1L; - - private long time; - private final boolean isNano; + private static final String DEFAULT_ID = StrUtil.EMPTY; /** * 构造,默认使用毫秒计数 @@ -23,10 +21,11 @@ public class TimeInterval implements Serializable { /** * 构造 + * * @param isNano 是否使用纳秒计数,false则使用毫秒 */ public TimeInterval(boolean isNano) { - this.isNano = isNano; + super(isNano); start(); } @@ -34,28 +33,25 @@ public class TimeInterval implements Serializable { * @return 开始计时并返回当前时间 */ public long start() { - time = getTime(isNano); - return time; + return start(DEFAULT_ID); } /** * @return 重新计时并返回从开始到当前的持续时间 */ public long intervalRestart() { - long now = getTime(isNano); - long d = now - time; - time = now; - return d; + return intervalRestart(DEFAULT_ID); } /** * 重新开始计算时间(重置开始时间) * * @return this + * @see #start() * @since 3.0.1 */ public TimeInterval restart() { - time = getTime(isNano); + start(DEFAULT_ID); return this; } @@ -68,7 +64,7 @@ public class TimeInterval implements Serializable { * @return 从开始到当前的间隔时间(毫秒数) */ public long interval() { - return getTime(isNano) - time; + return interval(DEFAULT_ID); } /** @@ -78,7 +74,7 @@ public class TimeInterval implements Serializable { * @since 4.6.7 */ public String intervalPretty() { - return DateUtil.formatBetween(intervalMs()); + return intervalPretty(DEFAULT_ID); } /** @@ -87,7 +83,7 @@ public class TimeInterval implements Serializable { * @return 从开始到当前的间隔时间(毫秒数) */ public long intervalMs() { - return isNano ? interval() / 1000000L : interval(); + return intervalMs(DEFAULT_ID); } /** @@ -96,7 +92,7 @@ public class TimeInterval implements Serializable { * @return 从开始到当前的间隔秒数,取绝对值 */ public long intervalSecond() { - return intervalMs() / DateUnit.SECOND.getMillis(); + return intervalSecond(DEFAULT_ID); } /** @@ -105,7 +101,7 @@ public class TimeInterval implements Serializable { * @return 从开始到当前的间隔分钟数,取绝对值 */ public long intervalMinute() { - return intervalMs() / DateUnit.MINUTE.getMillis(); + return intervalMinute(DEFAULT_ID); } /** @@ -114,7 +110,7 @@ public class TimeInterval implements Serializable { * @return 从开始到当前的间隔小时数,取绝对值 */ public long intervalHour() { - return intervalMs() / DateUnit.HOUR.getMillis(); + return intervalHour(DEFAULT_ID); } /** @@ -123,7 +119,7 @@ public class TimeInterval implements Serializable { * @return 从开始到当前的间隔天数,取绝对值 */ public long intervalDay() { - return intervalMs() / DateUnit.DAY.getMillis(); + return intervalDay(DEFAULT_ID); } /** @@ -132,16 +128,6 @@ public class TimeInterval implements Serializable { * @return 从开始到当前的间隔周数,取绝对值 */ public long intervalWeek() { - return intervalMs() / DateUnit.WEEK.getMillis(); - } - - /** - * 获取时间的毫秒或纳秒数,纳秒非时间戳 - * - * @param isNano 是否为高精度时间 - * @return 时间 - */ - private static long getTime(boolean isNano) { - return isNano ? System.nanoTime() : System.currentTimeMillis(); + return intervalWeek(DEFAULT_ID); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/ConcurrencyTester.java b/hutool-core/src/main/java/cn/hutool/core/thread/ConcurrencyTester.java index 20b42f4eec..252294a70d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/thread/ConcurrencyTester.java +++ b/hutool-core/src/main/java/cn/hutool/core/thread/ConcurrencyTester.java @@ -21,6 +21,10 @@ public class ConcurrencyTester { private final TimeInterval timeInterval; private long interval; + /** + * 构造 + * @param threadSize 线程数 + */ public ConcurrencyTester(int threadSize) { this.sf = new SyncFinisher(threadSize); this.timeInterval = new TimeInterval(); diff --git a/hutool-core/src/test/java/cn/hutool/core/date/TimeIntervalTest.java b/hutool-core/src/test/java/cn/hutool/core/date/TimeIntervalTest.java new file mode 100644 index 0000000000..67daa4d2fe --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/date/TimeIntervalTest.java @@ -0,0 +1,20 @@ +package cn.hutool.core.date; + +import cn.hutool.core.lang.Console; +import cn.hutool.core.thread.ThreadUtil; +import org.junit.Test; + +public class TimeIntervalTest { + @Test + public void intervalGroupTest(){ + final TimeInterval timer = new TimeInterval(); + timer.start("1"); + ThreadUtil.sleep(800); + timer.start("2"); + ThreadUtil.sleep(900); + + + Console.log("Timer 1 took {} ms", timer.intervalMs("1")); + Console.log("Timer 2 took {} ms", timer.intervalMs("2")); + } +} From db8ff64bf939ea9eb51ce740ff6157d55c3523a5 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 29 Nov 2020 00:32:04 +0800 Subject: [PATCH 16/18] add compile --- CHANGELOG.md | 1 + .../core/compiler/JavaClassFileManager.java | 146 +++-- .../core/compiler/JavaClassFileObject.java | 76 ++- .../core/compiler/JavaSourceCompiler.java | 503 +++++++++--------- .../core/compiler/JavaSourceFileObject.java | 141 +++-- .../core/compiler/JavaSourceCompilerTest.java | 44 +- 6 files changed, 452 insertions(+), 459 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 413de071b4..43c6b360e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ * 【crypto 】 opt改为otp包(issue#1257@Github) * 【cache 】 增加CacheListener(issue#1257@Github) * 【core 】 TimeInterval支持分组(issue#1238@Github) +* 【core 】 增加compile包(pr#1243@Github) ### Bug修复 * 【cron 】 修复CronTimer可能死循环的问题(issue#1224@Github) diff --git a/hutool-core/src/main/java/cn/hutool/core/compiler/JavaClassFileManager.java b/hutool-core/src/main/java/cn/hutool/core/compiler/JavaClassFileManager.java index ce2d4af49b..0de53681c5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/compiler/JavaClassFileManager.java +++ b/hutool-core/src/main/java/cn/hutool/core/compiler/JavaClassFileManager.java @@ -1,12 +1,16 @@ package cn.hutool.core.compiler; +import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.ClassLoaderUtil; +import cn.hutool.core.util.ObjectUtil; import javax.tools.FileObject; import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.JavaFileObject.Kind; +import java.io.IOException; import java.io.InputStream; import java.security.SecureClassLoader; import java.util.HashMap; @@ -18,88 +22,78 @@ import java.util.Map; * 我们采取此对象来管理运行时动态编译类生成的字节码 * * @author lzpeng - * @see JavaSourceCompilerBak#compile() - * @see com.sun.tools.javac.api.ClientCodeWrapper.WrappedJavaFileManager#getJavaFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, javax.tools.JavaFileObject.Kind, javax.tools.FileObject) + * @since 5.5.2 */ -final class JavaClassFileManager extends ForwardingJavaFileManager { +class JavaClassFileManager extends ForwardingJavaFileManager { - /** - * 存储java字节码文件对象映射 - */ - private final Map javaFileObjectMap = new HashMap<>(); + /** + * 存储java字节码文件对象映射 + */ + private final Map javaFileObjectMap = new HashMap<>(); - /** - * 加载动态编译生成类的父类加载器 - */ - private final ClassLoader parent; + /** + * 加载动态编译生成类的父类加载器 + */ + private final ClassLoader parent; - /** - * 构造 - * - * @param parent 父类加载器 - * @param fileManager 字节码文件管理器 - * @see JavaSourceCompilerBak#compile() - */ - protected JavaClassFileManager(final ClassLoader parent, final JavaFileManager fileManager) { - super(fileManager); - if (parent == null) { - this.parent = Thread.currentThread().getContextClassLoader(); - } else { - this.parent = parent; - } - } + /** + * 构造 + * + * @param parent 父类加载器 + * @param fileManager 字节码文件管理器 + */ + protected JavaClassFileManager(ClassLoader parent, JavaFileManager fileManager) { + super(fileManager); + this.parent = ObjectUtil.defaultIfNull(parent, ClassLoaderUtil.getClassLoader()); + } - /** - * 获得动态编译生成的类的类加载器 - * - * @param location 源码位置 - * @return 动态编译生成的类的类加载器 - * @see JavaSourceCompilerBak#compile() - */ - @Override - public ClassLoader getClassLoader(final Location location) { - return new SecureClassLoader(parent) { + /** + * 获得动态编译生成的类的类加载器 + * + * @param location 源码位置 + * @return 动态编译生成的类的类加载器 + */ + @Override + public ClassLoader getClassLoader(final Location location) { + return new SecureClassLoader(parent) { - /** - * 查找类 - * @param name 类名 - * @return 类的class对象 - * @throws ClassNotFoundException 未找到类异常 - */ - @Override - protected Class findClass(final String name) throws ClassNotFoundException { - final JavaFileObject javaFileObject = javaFileObjectMap.get(name); - if (javaFileObject != null) { - try { - final InputStream inputStream = javaFileObject.openInputStream(); - final byte[] bytes = IoUtil.readBytes(inputStream); - final Class c = defineClass(name, bytes, 0, bytes.length); - return c; - } catch (Exception e) { - e.printStackTrace(); - } - } - throw new ClassNotFoundException(name); - } - }; - } + /** + * 查找类 + * @param name 类名 + * @return 类的class对象 + * @throws ClassNotFoundException 未找到类异常 + */ + @Override + protected Class findClass(final String name) throws ClassNotFoundException { + final JavaFileObject javaFileObject = javaFileObjectMap.get(name); + if (null != javaFileObject) { + try(final InputStream inputStream = javaFileObject.openInputStream()){ + final byte[] bytes = IoUtil.readBytes(inputStream); + return defineClass(name, bytes, 0, bytes.length); + } catch (IOException e) { + throw new IORuntimeException(e); + } + } + throw new ClassNotFoundException(name); + } + }; + } - /** - * 获得Java字节码文件对象 - * 编译器编译源码时会将Java源码对象编译转为Java字节码对象 - * - * @param location 源码位置 - * @param className 类名 - * @param kind 文件类型 - * @param sibling 将Java源码对象 - * @return Java字节码文件对象 - * @see com.sun.tools.javac.api.lientCodeWrapper.WrappedJavaFileManager#getJavaFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, javax.tools.JavaFileObject.Kind, javax.tools.FileObject) - */ - @Override - public JavaFileObject getJavaFileForOutput(final Location location, final String className, final Kind kind, final FileObject sibling) { - final JavaFileObject javaFileObject = new JavaClassFileObject(className, kind); - javaFileObjectMap.put(className, javaFileObject); - return javaFileObject; - } + /** + * 获得Java字节码文件对象 + * 编译器编译源码时会将Java源码对象编译转为Java字节码对象 + * + * @param location 源码位置 + * @param className 类名 + * @param kind 文件类型 + * @param sibling 将Java源码对象 + * @return Java字节码文件对象 + */ + @Override + public JavaFileObject getJavaFileForOutput(final Location location, final String className, final Kind kind, final FileObject sibling) { + final JavaFileObject javaFileObject = new JavaClassFileObject(className, kind); + javaFileObjectMap.put(className, javaFileObject); + return javaFileObject; + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/compiler/JavaClassFileObject.java b/hutool-core/src/main/java/cn/hutool/core/compiler/JavaClassFileObject.java index c9f92bc705..d707a1c183 100644 --- a/hutool-core/src/main/java/cn/hutool/core/compiler/JavaClassFileObject.java +++ b/hutool-core/src/main/java/cn/hutool/core/compiler/JavaClassFileObject.java @@ -14,50 +14,48 @@ import java.net.URI; * @author lzpeng * @see JavaClassFileManager#getClassLoader(javax.tools.JavaFileManager.Location * @see JavaClassFileManager#getJavaFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, javax.tools.JavaFileObject.Kind, javax.tools.FileObject) - * @see com.sun.tools.javac.jvm.ClassWriter.ClassWriter#writeClass(com.sun.tools.javac.code.Symbol.ClassSymbol) + * @since 5.5.2 */ final class JavaClassFileObject extends SimpleJavaFileObject { - /** - * 字节码输出流 - */ - private final ByteArrayOutputStream byteArrayOutputStream; + /** + * 字节码输出流 + */ + private final ByteArrayOutputStream byteArrayOutputStream; - /** - * 构造 - * - * @param className 需要编译的类名 - * @param kind 需要编译的文件类型 - * @see JavaClassFileManager#getJavaFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, javax.tools.JavaFileObject.Kind, javax.tools.FileObject) - */ - protected JavaClassFileObject(final String className, final Kind kind) { - super(URI.create("string:///" + className.replaceAll("\\.", "/") + kind.extension), kind); - this.byteArrayOutputStream = new ByteArrayOutputStream(); - } + /** + * 构造 + * + * @param className 需要编译的类名 + * @param kind 需要编译的文件类型 + * @see JavaClassFileManager#getJavaFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, javax.tools.JavaFileObject.Kind, javax.tools.FileObject) + */ + protected JavaClassFileObject(final String className, final Kind kind) { + super(URI.create("string:///" + className.replaceAll("\\.", "/") + kind.extension), kind); + this.byteArrayOutputStream = new ByteArrayOutputStream(); + } - /** - * 获得字节码输入流 - * 编译器编辑源码后,我们将通过此输出流获得编译后的字节码,以便运行时加载类 - * - * @return 字节码输入流 - * @see JavaClassFileManager#getClassLoader(javax.tools.JavaFileManager.Location) - */ - @Override - public InputStream openInputStream() { - final byte[] bytes = byteArrayOutputStream.toByteArray(); - return new ByteArrayInputStream(bytes); - } + /** + * 获得字节码输入流 + * 编译器编辑源码后,我们将通过此输出流获得编译后的字节码,以便运行时加载类 + * + * @return 字节码输入流 + * @see JavaClassFileManager#getClassLoader(javax.tools.JavaFileManager.Location) + */ + @Override + public InputStream openInputStream() { + return new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); + } - /** - * 获得字节码输出流 - * 编译器编辑源码时,会将编译结果输出到本输出流中 - * - * @return 字节码输出流 - * @see com.sun.tools.javac.jvm.ClassWriter.ClassWriter#writeClass(com.sun.tools.javac.code.Symbol.ClassSymbol) - */ - @Override - public OutputStream openOutputStream() { - return this.byteArrayOutputStream; - } + /** + * 获得字节码输出流 + * 编译器编辑源码时,会将编译结果输出到本输出流中 + * + * @return 字节码输出流 + */ + @Override + public OutputStream openOutputStream() { + return this.byteArrayOutputStream; + } } \ No newline at end of file diff --git a/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceCompiler.java b/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceCompiler.java index c88e579fae..9f2650c8eb 100644 --- a/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceCompiler.java +++ b/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceCompiler.java @@ -3,17 +3,31 @@ package cn.hutool.core.compiler; import cn.hutool.core.io.FileUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.ClassLoaderUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.URLUtil; -import javax.tools.*; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; -import javax.tools.JavaFileObject.Kind; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -23,270 +37,269 @@ import java.util.zip.ZipFile; * * @author lzpeng */ -public final class JavaSourceCompiler { +public class JavaSourceCompiler { - /** - * java 编译器 - */ - private static final JavaCompiler JAVA_COMPILER = ToolProvider.getSystemJavaCompiler(); + /** + * java 编译器 + */ + private static final JavaCompiler JAVA_COMPILER = ToolProvider.getSystemJavaCompiler(); - /** - * 待编译的文件 可以是 .java文件 压缩文件 文件夹 递归搜索文件夹内的zip包和jar包 - */ - private final List sourceFileList = new ArrayList<>(); + /** + * 待编译的文件 可以是 .java文件 压缩文件 文件夹 递归搜索文件夹内的zip包和jar包 + */ + private final List sourceFileList = new ArrayList<>(); - /** - * 编译时需要加入classpath中的文件 可以是 压缩文件 文件夹递归搜索文件夹内的zip包和jar包 - */ - private final List libraryFileList = new ArrayList<>(); + /** + * 编译时需要加入classpath中的文件 可以是 压缩文件 文件夹递归搜索文件夹内的zip包和jar包 + */ + private final List libraryFileList = new ArrayList<>(); - /** - * 源码映射 key: 类名 value: 类源码 - */ - private final Map sourceCodeMap = new LinkedHashMap<>(); + /** + * 源码映射 key: 类名 value: 类源码 + */ + private final Map sourceCodeMap = new LinkedHashMap<>(); - /** - * 编译类时使用的父类加载器 - */ - private final ClassLoader parentClassLoader; + /** + * 编译类时使用的父类加载器 + */ + private final ClassLoader parentClassLoader; - /** - * 构造 - * - * @param parent 父类加载器 - */ - private JavaSourceCompiler(ClassLoader parent) { - this.parentClassLoader = parent; - } + /** + * 构造 + * + * @param parent 父类加载器 + */ + private JavaSourceCompiler(ClassLoader parent) { + this.parentClassLoader = parent; + } - /** - * 创建Java源码编译器 - * - * @param parent 父类加载器 - * @return Java源码编译器 - */ - public static JavaSourceCompiler create(ClassLoader parent) { - return new JavaSourceCompiler(parent); - } + /** + * 创建Java源码编译器 + * + * @param parent 父类加载器 + * @return Java源码编译器 + */ + public static JavaSourceCompiler create(ClassLoader parent) { + return new JavaSourceCompiler(parent); + } - /** - * 向编译器中加入待编译的文件 支持 .java, 文件夹, 压缩文件 递归搜索文件夹内的压缩文件和jar包 - * - * @param files 待编译的文件 支持 .java, 文件夹, 压缩文件 递归搜索文件夹内的压缩文件和jar包 - * @return Java源码编译器 - */ - public JavaSourceCompiler addSource(final File... files) { - if (ArrayUtil.isNotEmpty(files)) { - this.sourceFileList.addAll(Arrays.asList(files)); - } - return this; - } + /** + * 向编译器中加入待编译的文件 支持 .java, 文件夹, 压缩文件 递归搜索文件夹内的压缩文件和jar包 + * + * @param files 待编译的文件 支持 .java, 文件夹, 压缩文件 递归搜索文件夹内的压缩文件和jar包 + * @return Java源码编译器 + */ + public JavaSourceCompiler addSource(final File... files) { + if (ArrayUtil.isNotEmpty(files)) { + this.sourceFileList.addAll(Arrays.asList(files)); + } + return this; + } - /** - * 向编译器中加入待编译的源码Map - * - * @param sourceCodeMap 源码Map key: 类名 value 源码 - * @return Java源码编译器 - */ - public JavaSourceCompiler addSource(final Map sourceCodeMap) { - if (MapUtil.isNotEmpty(sourceCodeMap)) { - this.sourceCodeMap.putAll(sourceCodeMap); - } - return this; - } + /** + * 向编译器中加入待编译的源码Map + * + * @param sourceCodeMap 源码Map key: 类名 value 源码 + * @return Java源码编译器 + */ + public JavaSourceCompiler addSource(final Map sourceCodeMap) { + if (MapUtil.isNotEmpty(sourceCodeMap)) { + this.sourceCodeMap.putAll(sourceCodeMap); + } + return this; + } - /** - * 加入编译Java源码时所需要的jar包 - * - * @param files 编译Java源码时所需要的jar包 - * @return Java源码编译器 - */ - public JavaSourceCompiler addLibrary(final File... files) { - if (ArrayUtil.isNotEmpty(files)) { - this.libraryFileList.addAll(Arrays.asList(files)); - } - return this; - } + /** + * 加入编译Java源码时所需要的jar包 + * + * @param files 编译Java源码时所需要的jar包 + * @return Java源码编译器 + */ + public JavaSourceCompiler addLibrary(final File... files) { + if (ArrayUtil.isNotEmpty(files)) { + this.libraryFileList.addAll(Arrays.asList(files)); + } + return this; + } - /** - * 向编译器中加入待编译的源码Map - * - * @param className 类名 - * @param sourceCode 源码 - * @return Java文件编译器 - */ - public JavaSourceCompiler addSource(final String className, final String sourceCode) { - if (className != null && sourceCode != null) { - this.sourceCodeMap.put(className, sourceCode); - } - return this; - } + /** + * 向编译器中加入待编译的源码Map + * + * @param className 类名 + * @param sourceCode 源码 + * @return Java文件编译器 + */ + public JavaSourceCompiler addSource(final String className, final String sourceCode) { + if (className != null && sourceCode != null) { + this.sourceCodeMap.put(className, sourceCode); + } + return this; + } - /** - * 编译所有文件并返回类加载器 - * - * @return 类加载器 - */ - public ClassLoader compile() { - final ClassLoader parent; - if (this.parentClassLoader == null) { - parent = Thread.currentThread().getContextClassLoader(); - } else { - parent = this.parentClassLoader; - } - // 获得classPath - final List classPath = getClassPath(); - final URL[] urLs = URLUtil.getURLs(classPath.toArray(new File[0])); - final URLClassLoader ucl = URLClassLoader.newInstance(urLs, parent); - if (sourceCodeMap.isEmpty() && sourceFileList.isEmpty()) { - // 没有需要编译的源码 - return ucl; - } - // 没有需要编译的源码文件返回加载zip或jar包的类加载器 - final Iterable javaFileObjectList = getJavaFileObject(); - // 创建编译器 - final JavaFileManager standardJavaFileManager = JAVA_COMPILER.getStandardFileManager(null, null, null); - final JavaFileManager javaFileManager = new JavaClassFileManager(ucl, standardJavaFileManager); - final DiagnosticCollector diagnosticCollector = new DiagnosticCollector<>(); - final List options = new ArrayList<>(); - if (!classPath.isEmpty()) { - final List cp = classPath.stream().map(File::getAbsolutePath).collect(Collectors.toList()); - options.add("-cp"); - options.addAll(cp); - } - // 编译文件 - final CompilationTask task = JAVA_COMPILER.getTask(null, javaFileManager, diagnosticCollector, - options, null, javaFileObjectList); - final Boolean result = task.call(); - if (Boolean.TRUE.equals(result)) { - return javaFileManager.getClassLoader(StandardLocation.CLASS_OUTPUT); - } else { - // 编译失败,收集错误信息 - final List diagnostics = diagnosticCollector.getDiagnostics(); - final String errorMsg = diagnostics.stream().map(String::valueOf) - .collect(Collectors.joining(System.lineSeparator())); - // CompileException - throw new RuntimeException(errorMsg); - } - } + /** + * 编译所有文件并返回类加载器 + * + * @return 类加载器 + */ + public ClassLoader compile() { + final ClassLoader parent = ObjectUtil.defaultIfNull(this.parentClassLoader, ClassLoaderUtil.getClassLoader()); - /** - * 获得编译源码时需要的classpath - * - * @return 编译源码时需要的classpath - */ - private List getClassPath() { - List classPathFileList = new ArrayList<>(); - for (File file : libraryFileList) { - List jarOrZipFile = FileUtil.loopFiles(file, this::isJarOrZipFile); - classPathFileList.addAll(jarOrZipFile); - if (file.isDirectory()) { - classPathFileList.add(file); - } - } - return classPathFileList; - } + // 获得classPath + final List classPath = getClassPath(); + final URL[] urLs = URLUtil.getURLs(classPath.toArray(new File[0])); + final URLClassLoader ucl = URLClassLoader.newInstance(urLs, parent); + if (sourceCodeMap.isEmpty() && sourceFileList.isEmpty()) { + // 没有需要编译的源码 + return ucl; + } + // 没有需要编译的源码文件返回加载zip或jar包的类加载器 + final Iterable javaFileObjectList = getJavaFileObject(); - /** - * 获得待编译的Java文件对象 - * - * @return 待编译的Java文件对象 - */ - private Iterable getJavaFileObject() { - final Collection collection = new ArrayList<>(); - for (File file : sourceFileList) { - // .java 文件 - final List javaFileList = FileUtil.loopFiles(file, this::isJavaFile); - for (File javaFile : javaFileList) { - collection.add(getJavaFileObjectByJavaFile(javaFile)); - } - // 压缩包 - final List jarOrZipFileList = FileUtil.loopFiles(file, this::isJarOrZipFile); - for (File jarOrZipFile : jarOrZipFileList) { - collection.addAll(getJavaFileObjectByZipOrJarFile(jarOrZipFile)); - } - } - // 源码Map - collection.addAll(getJavaFileObjectByMap(this.sourceCodeMap)); - return collection; - } + // 创建编译器 + final JavaFileManager standardJavaFileManager = JAVA_COMPILER.getStandardFileManager(null, null, null); + final JavaFileManager javaFileManager = new JavaClassFileManager(ucl, standardJavaFileManager); - /** - * 通过源码Map获得Java文件对象 - * - * @param sourceCodeMap 源码Map - * @return Java文件对象集合 - */ - private Collection getJavaFileObjectByMap(final Map sourceCodeMap) { - if (MapUtil.isNotEmpty(sourceCodeMap)) { - return sourceCodeMap.entrySet().stream() - .map(entry -> new JavaSourceFileObject(entry.getKey(), entry.getValue(), Kind.SOURCE)) - .collect(Collectors.toList()); - } - return Collections.emptySet(); - } + // classpath + final List options = new ArrayList<>(); + if (false == classPath.isEmpty()) { + final List cp = classPath.stream().map(File::getAbsolutePath).collect(Collectors.toList()); + options.add("-cp"); + options.addAll(cp); + } - /** - * 通过.java文件创建Java文件对象 - * - * @param file .java文件 - * @return Java文件对象 - */ - private JavaFileObject getJavaFileObjectByJavaFile(final File file) { - return new JavaSourceFileObject(file.toURI(), Kind.SOURCE); - } + // 编译文件 + final DiagnosticCollector diagnosticCollector = new DiagnosticCollector<>(); + final CompilationTask task = JAVA_COMPILER.getTask(null, javaFileManager, diagnosticCollector, + options, null, javaFileObjectList); + if (task.call()) { + return javaFileManager.getClassLoader(StandardLocation.CLASS_OUTPUT); + } else { + // 编译失败,收集错误信息 + final List diagnostics = diagnosticCollector.getDiagnostics(); + final String errorMsg = diagnostics.stream().map(String::valueOf) + .collect(Collectors.joining(System.lineSeparator())); + // CompileException + throw new RuntimeException(errorMsg); + } + } - /** - * 通过zip包或jar包创建Java文件对象 - * - * @param file 压缩文件 - * @return Java文件对象 - */ - private Collection getJavaFileObjectByZipOrJarFile(final File file) { - final Collection collection = new ArrayList<>(); - try { - final ZipFile zipFile = new ZipFile(file); - final Enumeration entries = zipFile.entries(); - while (entries.hasMoreElements()) { - final ZipEntry zipEntry = entries.nextElement(); - final String name = zipEntry.getName(); - if (name.endsWith(".java")) { - final InputStream inputStream = zipFile.getInputStream(zipEntry); - final JavaSourceFileObject fileObject = new JavaSourceFileObject(name, inputStream, Kind.SOURCE); - collection.add(fileObject); - } - } - return collection; - } catch (IOException e) { - e.printStackTrace(); - } - return Collections.emptyList(); - } + /** + * 获得编译源码时需要的classpath + * + * @return 编译源码时需要的classpath + */ + private List getClassPath() { + List classPathFileList = new ArrayList<>(); + for (File file : libraryFileList) { + List jarOrZipFile = FileUtil.loopFiles(file, this::isJarOrZipFile); + classPathFileList.addAll(jarOrZipFile); + if (file.isDirectory()) { + classPathFileList.add(file); + } + } + return classPathFileList; + } + + /** + * 获得待编译的Java文件对象 + * + * @return 待编译的Java文件对象 + */ + private Iterable getJavaFileObject() { + final Collection collection = new ArrayList<>(); + for (File file : sourceFileList) { + // .java 文件 + final List javaFileList = FileUtil.loopFiles(file, this::isJavaFile); + for (File javaFile : javaFileList) { + collection.add(getJavaFileObjectByJavaFile(javaFile)); + } + // 压缩包 + final List jarOrZipFileList = FileUtil.loopFiles(file, this::isJarOrZipFile); + for (File jarOrZipFile : jarOrZipFileList) { + collection.addAll(getJavaFileObjectByZipOrJarFile(jarOrZipFile)); + } + } + // 源码Map + collection.addAll(getJavaFileObjectByMap(this.sourceCodeMap)); + return collection; + } + + /** + * 通过源码Map获得Java文件对象 + * + * @param sourceCodeMap 源码Map + * @return Java文件对象集合 + */ + private Collection getJavaFileObjectByMap(final Map sourceCodeMap) { + if (MapUtil.isNotEmpty(sourceCodeMap)) { + return sourceCodeMap.entrySet().stream() + .map(entry -> new JavaSourceFileObject(entry.getKey(), entry.getValue(), CharsetUtil.CHARSET_UTF_8)) + .collect(Collectors.toList()); + } + return Collections.emptySet(); + } + + /** + * 通过.java文件创建Java文件对象 + * + * @param file .java文件 + * @return Java文件对象 + */ + private JavaFileObject getJavaFileObjectByJavaFile(final File file) { + return new JavaSourceFileObject(file.toURI()); + } + + /** + * 通过zip包或jar包创建Java文件对象 + * + * @param file 压缩文件 + * @return Java文件对象 + */ + private Collection getJavaFileObjectByZipOrJarFile(final File file) { + final Collection collection = new ArrayList<>(); + try { + final ZipFile zipFile = new ZipFile(file); + final Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + final ZipEntry zipEntry = entries.nextElement(); + final String name = zipEntry.getName(); + if (name.endsWith(".java")) { + final InputStream inputStream = zipFile.getInputStream(zipEntry); + final JavaSourceFileObject fileObject = new JavaSourceFileObject(name, inputStream); + collection.add(fileObject); + } + } + return collection; + } catch (IOException e) { + e.printStackTrace(); + } + return Collections.emptyList(); + } - /** - * 是否是jar 或 zip 文件 - * - * @param file 文件 - * @return 是否是jar 或 zip 文件 - */ - private boolean isJarOrZipFile(final File file) { - final String fileName = file.getName(); - return fileName.endsWith(".jar") || fileName.endsWith(".zip"); - } + /** + * 是否是jar 或 zip 文件 + * + * @param file 文件 + * @return 是否是jar 或 zip 文件 + */ + private boolean isJarOrZipFile(final File file) { + final String fileName = file.getName(); + return fileName.endsWith(".jar") || fileName.endsWith(".zip"); + } - /** - * 是否是.java文件 - * - * @param file 文件 - * @return 是否是.java文件 - */ - private boolean isJavaFile(final File file) { - final String fileName = file.getName(); - return fileName.endsWith(".java"); - } + /** + * 是否是.java文件 + * + * @param file 文件 + * @return 是否是.java文件 + */ + private boolean isJavaFile(final File file) { + final String fileName = file.getName(); + return fileName.endsWith(".java"); + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceFileObject.java b/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceFileObject.java index a13cc48416..e8cae9da8c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceFileObject.java +++ b/hutool-core/src/main/java/cn/hutool/core/compiler/JavaSourceFileObject.java @@ -1,98 +1,85 @@ package cn.hutool.core.compiler; +import cn.hutool.core.io.IoUtil; + +import javax.tools.SimpleJavaFileObject; import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.nio.charset.Charset; -import javax.tools.SimpleJavaFileObject; - -import cn.hutool.core.io.IoUtil; - /** * Java 源码文件对象 * * @author lzpeng - * @see JavaSourceCompilerBak#getJavaFileObjectByJavaFile(java.io.File) - * @see JavaSourceCompilerBak#getJavaFileObjectByZipOrJarFile(java.io.File) - * @see JavaSourceCompilerBak#getJavaFileObject(java.util.Map) - * @see com.sun.tools.javac.api.ClientCodeWrapper.WrappedFileObject#getCharContent(boolean) + * @since 5.5.2 */ -final class JavaSourceFileObject extends SimpleJavaFileObject { +class JavaSourceFileObject extends SimpleJavaFileObject { - /** - * 输入流 - */ - private InputStream inputStream; + /** + * 输入流 + */ + private InputStream inputStream; - /** - * 构造 - * - * @param uri 需要编译的文件uri - * @param kind 需要编译的文件类型 - * @see JavaSourceCompilerBak#getJavaFileObjectByJavaFile(java.io.File) - */ - protected JavaSourceFileObject(URI uri, Kind kind) { - super(uri, kind); - } + /** + * 构造 + * + * @param uri 需要编译的文件uri + */ + protected JavaSourceFileObject(URI uri) { + super(uri, Kind.SOURCE); + } - /** - * 构造 - * - * @param name 需要编译的文件名 - * @param inputStream 输入流 - * @param kind 需要编译的文件类型 - * @see JavaSourceCompilerBak#getJavaFileObjectByZipOrJarFile(java.io.File) - */ - protected JavaSourceFileObject(final String name, final InputStream inputStream, final Kind kind) { - super(URI.create("string:///" + name), kind); - this.inputStream = inputStream; - } + /** + * 构造 + * + * @param name 需要编译的文件名 + * @param inputStream 输入流 + */ + protected JavaSourceFileObject(String name, InputStream inputStream) { + this(URI.create("string:///" + name)); + this.inputStream = inputStream; + } - /** - * 构造 - * - * @param className 需要编译的类名 - * @param code 需要编译的类源码 - * @param kind 需要编译的文件类型 - * @see JavaSourceCompilerBak#getJavaFileObject(java.util.Map) - */ - protected JavaSourceFileObject(final String className, final String code, final Kind kind) { - super(URI.create("string:///" + className.replaceAll("\\.", "/") + kind.extension), kind); - this.inputStream = new ByteArrayInputStream(code.getBytes()); - } + /** + * 构造 + * + * @param className 需要编译的类名 + * @param code 需要编译的类源码 + */ + protected JavaSourceFileObject(String className, String code, Charset charset) { + this(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension)); + this.inputStream = IoUtil.toStream(code, charset); + } - /** - * 获得类源码的输入流 - * - * @return 类源码的输入流 - * @throws IOException IO 异常 - */ - @Override - public InputStream openInputStream() throws IOException { - if (inputStream == null) { - inputStream = toUri().toURL().openStream(); - } - return new BufferedInputStream(inputStream); - } + /** + * 获得类源码的输入流 + * + * @return 类源码的输入流 + * @throws IOException IO 异常 + */ + @Override + public InputStream openInputStream() throws IOException { + if (inputStream == null) { + inputStream = toUri().toURL().openStream(); + } + return new BufferedInputStream(inputStream); + } - /** - * 获得类源码 - * 编译器编辑源码前,会通过此方法获取类的源码 - * - * @param ignoreEncodingErrors 是否忽略编码错误 - * @return 需要编译的类的源码 - * @throws IOException IO异常 - * @see com.sun.tools.javac.api.ClientCodeWrapper.WrappedFileObject#getCharContent(boolean) - */ - @Override - public CharSequence getCharContent(final boolean ignoreEncodingErrors) throws IOException { - final InputStream in = openInputStream(); - final String code = IoUtil.read(in, Charset.defaultCharset()); - IoUtil.close(in); - return code; - } + /** + * 获得类源码 + * 编译器编辑源码前,会通过此方法获取类的源码 + * + * @param ignoreEncodingErrors 是否忽略编码错误 + * @return 需要编译的类的源码 + * @throws IOException IO异常 + */ + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + try(final InputStream in = openInputStream()){ + return IoUtil.readUtf8(in); + } + } } \ No newline at end of file diff --git a/hutool-core/src/test/java/cn/hutool/core/compiler/JavaSourceCompilerTest.java b/hutool-core/src/test/java/cn/hutool/core/compiler/JavaSourceCompilerTest.java index b8ce0a6c76..3e24514d7b 100644 --- a/hutool-core/src/test/java/cn/hutool/core/compiler/JavaSourceCompilerTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/compiler/JavaSourceCompilerTest.java @@ -16,27 +16,27 @@ import java.io.InputStream; */ public class JavaSourceCompilerTest { - /** - * 测试编译Java源码 - */ - @Test - public void testCompile() throws ClassNotFoundException { - final File libFile = ZipUtil.zip(FileUtil.file("lib.jar"), - new String[]{"a/A.class", "a/A$1.class", "a/A$InnerClass.class"}, - new InputStream[]{ - FileUtil.getInputStream("test-compile/a/A.class"), - FileUtil.getInputStream("test-compile/a/A$1.class"), - FileUtil.getInputStream("test-compile/a/A$InnerClass.class") - }); - final ClassLoader classLoader = JavaSourceCompiler.create(null) - .addSource(FileUtil.file("test-compile/b/B.java")) - .addSource("c.C", FileUtil.readUtf8String("test-compile/c/C.java")) - .addLibrary(libFile) - .compile(); - final Class clazz = classLoader.loadClass("c.C"); - Object obj = ReflectUtil.newInstance(clazz); - Assert.assertTrue(String.valueOf(obj).startsWith("c.C@")); - FileUtil.del(libFile); - } + /** + * 测试编译Java源码 + */ + @Test + public void testCompile() throws ClassNotFoundException { + final File libFile = ZipUtil.zip(FileUtil.file("lib.jar"), + new String[]{"a/A.class", "a/A$1.class", "a/A$InnerClass.class"}, + new InputStream[]{ + FileUtil.getInputStream("test-compile/a/A.class"), + FileUtil.getInputStream("test-compile/a/A$1.class"), + FileUtil.getInputStream("test-compile/a/A$InnerClass.class") + }); + final ClassLoader classLoader = JavaSourceCompiler.create(null) + .addSource(FileUtil.file("test-compile/b/B.java")) + .addSource("c.C", FileUtil.readUtf8String("test-compile/c/C.java")) + .addLibrary(libFile) + .compile(); + final Class clazz = classLoader.loadClass("c.C"); + Object obj = ReflectUtil.newInstance(clazz); + Assert.assertTrue(String.valueOf(obj).startsWith("c.C@")); + FileUtil.del(libFile); + } } \ No newline at end of file From 07c2870685f12922bb34e79ac5c2edefafa6da01 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 29 Nov 2020 00:37:14 +0800 Subject: [PATCH 17/18] fix --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43c6b360e8..c44ecbfa6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ * 【crypto 】 增加判空(issue#1230@Github) * 【core 】 xml.setXmlStandalone(true)格式优化(pr#1234@Github) * 【core 】 AnnotationUtil增加setValue方法(pr#1250@Github) -* 【core 】 ZipUtil增加get方法 +* 【core 】 ZipUtil增加get方法(issue#I27CUF@Gitee) * 【cache 】 对CacheObj等变量使用volatile关键字 * 【core 】 Base64增加encodeWithoutPadding方法(issue#I26J16@Gitee) * 【core 】 ExceptionUtil增加message消息包装为运行时异常的方法(pr#1253@Gitee) From 9857ac4484cf001d21397e0ecad48df22bb1f3e3 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 29 Nov 2020 00:46:37 +0800 Subject: [PATCH 18/18] fix test --- .../src/main/java/cn/hutool/json/JSONObject.java | 6 +++--- .../src/test/java/cn/hutool/json/JSONObjectTest.java | 10 ++++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) 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 0edcec2209..67a5e20aeb 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java @@ -420,7 +420,7 @@ public class JSONObject implements JSON, JSONGetter, Map } /** - * 积累值。类似于put,当key对应value已经存在时,与value组成新的JSONArray.
+ * 积累值。类似于set,当key对应value已经存在时,与value组成新的JSONArray.
* 如果只有一个值,此值就是value,如果多个值,则是添加到新的JSONArray中 * * @param key 键 @@ -432,11 +432,11 @@ public class JSONObject implements JSON, JSONGetter, Map InternalJSONUtil.testValidity(value); Object object = this.getObj(key); if (object == null) { - this.set(key, (value instanceof JSONArray) ? value : new JSONArray(this.config).set(value)); + this.set(key, value); } else if (object instanceof JSONArray) { ((JSONArray) object).set(value); } else { - this.set(key, new JSONArray(this.config).set(object).set(value)); + this.set(key, JSONUtil.createArray(this.config).set(object).set(value)); } return this; } diff --git a/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java b/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java index 802263c585..da14f1e765 100644 --- a/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java @@ -538,7 +538,13 @@ public class JSONObjectTest { @Test public void accumulateTest(){ - final JSONObject accumulate = JSONUtil.createObj().accumulate("key1", "value1"); - Assert.assertEquals("{\"key1\":[\"value1\"]}", accumulate.toString()); + final JSONObject jsonObject = JSONUtil.createObj().accumulate("key1", "value1"); + Assert.assertEquals("{\"key1\":\"value1\"}", jsonObject.toString()); + + jsonObject.accumulate("key1", "value2"); + Assert.assertEquals("{\"key1\":[\"value1\",\"value2\"]}", jsonObject.toString()); + + jsonObject.accumulate("key1", "value3"); + Assert.assertEquals("{\"key1\":[\"value1\",\"value2\",\"value3\"]}", jsonObject.toString()); } }