From a1d2c3052646495566142a8b024bcc207dec45c6 Mon Sep 17 00:00:00 2001 From: looly Date: Sat, 20 Nov 2021 16:38:40 +0800 Subject: [PATCH 1/6] fix code and add test --- .../src/main/java/cn/hutool/core/util/NumberUtil.java | 3 +++ .../src/test/java/cn/hutool/core/util/NumberUtilTest.java | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java index 8953e48b0..c5e2f7aed 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java @@ -716,6 +716,9 @@ public class NumberUtil { * @since 3.1.0 */ public static BigDecimal div(Number v1, Number v2, int scale, RoundingMode roundingMode) { + if(v1 instanceof BigDecimal && v2 instanceof BigDecimal){ + return div((BigDecimal)v1, (BigDecimal)v2, scale, roundingMode); + } return div(v1.toString(), v2.toString(), scale, roundingMode); } diff --git a/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java index 137c849cd..e5ee4565e 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java @@ -87,6 +87,12 @@ public class NumberUtilTest { Assert.assertEquals(0.0, result, 0); } + @Test + public void divBigDecimalTest() { + BigDecimal result = NumberUtil.div(BigDecimal.ZERO, BigDecimal.ONE); + Assert.assertEquals(BigDecimal.ZERO, result.stripTrailingZeros()); + } + @Test public void roundTest() { From 490e5129754a908ebff55c04b62b04c85d36d558 Mon Sep 17 00:00:00 2001 From: looly Date: Sat, 20 Nov 2021 17:08:28 +0800 Subject: [PATCH 2/6] fix bug --- CHANGELOG.md | 3 ++- .../src/main/java/cn/hutool/core/util/ZipUtil.java | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c1df9dd0..a0f10bfb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.7.17 (2021-11-19) +# 5.7.17 (2021-11-20) ### 🐣新特性 * 【core 】 增加AsyncUtil(pr#457@Gitee) @@ -24,6 +24,7 @@ ### 🐞Bug修复 * 【core 】 修复FileResource构造fileName参数无效问题(issue#1942@Github) * 【cache 】 修复WeakCache键值强关联导致的无法回收问题(issue#1953@Github) +* 【core 】 修复ZipUtil相对路径父路径获取null问题(issue#1961@Github) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ZipUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ZipUtil.java index ddce403fb..3b1ac5655 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ZipUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ZipUtil.java @@ -1002,8 +1002,17 @@ public class ZipUtil { throw new UtilException(StrUtil.format("File [{}] not exist!", srcFile.getAbsolutePath())); } + // issue#1961@Github + // 当 zipFile = new File("temp.zip") 时, zipFile.getParentFile() == null + File parentFile; + try { + parentFile = zipFile.getCanonicalFile().getParentFile(); + } catch (IOException e) { + parentFile = zipFile.getParentFile(); + } + // 压缩文件不能位于被压缩的目录内 - if (srcFile.isDirectory() && FileUtil.isSub(srcFile, zipFile.getParentFile())) { + if (srcFile.isDirectory() && FileUtil.isSub(srcFile, parentFile)) { throw new UtilException("Zip file path [{}] must not be the child directory of [{}] !", zipFile.getPath(), srcFile.getPath()); } } From 147cc683a56ce1bff5f0b4f705c1940acfe0098b Mon Sep 17 00:00:00 2001 From: looly Date: Sat, 20 Nov 2021 17:36:31 +0800 Subject: [PATCH 3/6] update version --- hutool-log/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hutool-log/pom.xml b/hutool-log/pom.xml index b1cd3eea1..7cbda2096 100644 --- a/hutool-log/pom.xml +++ b/hutool-log/pom.xml @@ -25,7 +25,7 @@ 1.2 1.3.6 3.4.2.Final - 0.39.2 + 0.41.0 From 42fbf36042cc65afb26c3f06f7aff541d3135f98 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 21 Nov 2021 04:50:48 +0800 Subject: [PATCH 4/6] fix code --- .../cn/hutool/core/io/FastStringWriter.java | 2 +- .../main/java/cn/hutool/core/lang/Opt.java | 36 +++++++++---------- .../cn/hutool/core/text/CharSequenceUtil.java | 21 +++++------ .../java/cn/hutool/core/text/StrJoiner.java | 3 +- .../java/cn/hutool/core/text/UnicodeUtil.java | 4 +-- .../java/cn/hutool/core/util/StrUtil.java | 6 ++-- 6 files changed, 34 insertions(+), 38 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/io/FastStringWriter.java b/hutool-core/src/main/java/cn/hutool/core/io/FastStringWriter.java index aabdf84fa..1545ab99f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/FastStringWriter.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/FastStringWriter.java @@ -87,4 +87,4 @@ public final class FastStringWriter extends Writer { return this.builder.toString(); } -} \ No newline at end of file +} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java b/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java index 6f95a8c7a..6e8f74ac7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java @@ -110,6 +110,21 @@ public class Opt { return CollectionUtil.isEmpty(value) ? empty() : new Opt<>(value); } + /** + * 执行一系列操作,如果途中发生 {@code NPE} 和 {@code IndexOutOfBoundsException},返回一个空的{@code Opt} + * + * @param supplier 操作 + * @param 类型 + * @return 操作执行后的值 + */ + public static Opt exec(Supplier supplier) { + try { + return Opt.ofNullable(supplier.get()); + } catch (NullPointerException | IndexOutOfBoundsException e) { + return empty(); + } + } + /** * 包裹里实际的元素 */ @@ -411,10 +426,7 @@ public class Opt { * @throws NoSuchElementException 如果包裹里的值不存在则抛出该异常 */ public T orElseThrow() { - if (value == null) { - throw new NoSuchElementException("No value present"); - } - return value; + return orElseThrow(NoSuchElementException::new, "No value present"); } /** @@ -469,22 +481,6 @@ public class Opt { return Optional.ofNullable(this.value); } - - /** - * 执行一系列操作,如果途中发生 {@code NPE} 和 {@code IndexOutOfBoundsException},返回一个空的{@code Opt} - * - * @param supplier 操作 - * @param 类型 - * @return 操作执行后的值 - */ - public static Opt exec(Supplier supplier) { - try { - return Opt.ofNullable(supplier.get()); - } catch (NullPointerException | IndexOutOfBoundsException e) { - return empty(); - } - } - /** * 判断传入参数是否与 {@code Opt}相等 * 在以下情况下返回true diff --git a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java index 2ff065d9f..8310c72de 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java @@ -2471,21 +2471,22 @@ public class CharSequenceUtil { * * @param str 被重复的字符串 * @param count 数量 - * @param conjunction 分界符 + * @param delimiter 分界符 * @return 连接后的字符串 * @since 4.0.1 */ - public static String repeatAndJoin(CharSequence str, int count, CharSequence conjunction) { + public static String repeatAndJoin(CharSequence str, int count, CharSequence delimiter) { if (count <= 0) { return EMPTY; } - final StrBuilder builder = StrBuilder.create(); - boolean isFirst = true; + final StringBuilder builder = new StringBuilder(str.length() * count); + builder.append(str); + count--; + + final boolean isAppendDelimiter = isNotEmpty(delimiter); while (count-- > 0) { - if (isFirst) { - isFirst = false; - } else if (isNotEmpty(conjunction)) { - builder.append(conjunction); + if (isAppendDelimiter) { + builder.append(delimiter); } builder.append(str); } @@ -3521,7 +3522,7 @@ public class CharSequenceUtil { fromIndex = 0; } - final StrBuilder result = StrBuilder.create(strLength + 16); + final StringBuilder result = new StringBuilder(strLength - searchStrLength + replacement.length()); if (0 != fromIndex) { result.append(str.subSequence(0, fromIndex)); } @@ -4285,7 +4286,7 @@ public class CharSequenceUtil { // 循环位移,当越界时循环 moveLength = moveLength % len; } - final StrBuilder strBuilder = StrBuilder.create(len); + final StringBuilder strBuilder = new StringBuilder(len); if (moveLength > 0) { int endAfterMove = Math.min(endExclude + moveLength, str.length()); strBuilder.append(str.subSequence(0, startInclude))// diff --git a/hutool-core/src/main/java/cn/hutool/core/text/StrJoiner.java b/hutool-core/src/main/java/cn/hutool/core/text/StrJoiner.java index 862b6ff8f..bfebd8703 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/StrJoiner.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/StrJoiner.java @@ -191,11 +191,10 @@ public class StrJoiner implements Appendable, Serializable { /** * 追加对象到拼接器中 * - * @param 元素类型 * @param obj 对象,支持数组、集合等 * @return this */ - public StrJoiner append(Object obj) { + public StrJoiner append(Object obj) { if (null == obj) { append((CharSequence) null); } else if (ArrayUtil.isArray(obj)) { diff --git a/hutool-core/src/main/java/cn/hutool/core/text/UnicodeUtil.java b/hutool-core/src/main/java/cn/hutool/core/text/UnicodeUtil.java index ff8c77273..e0789e66b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/UnicodeUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/UnicodeUtil.java @@ -25,7 +25,7 @@ public class UnicodeUtil { } final int len = unicode.length(); - StrBuilder sb = StrBuilder.create(len); + StringBuilder sb = new StringBuilder(len); int i; int pos = 0; while ((i = StrUtil.indexOfIgnoreCase(unicode, "\\u", pos)) != -1) { @@ -101,7 +101,7 @@ public class UnicodeUtil { } final int len = str.length(); - final StrBuilder unicode = StrBuilder.create(str.length() * 6); + final StringBuilder unicode = new StringBuilder(str.length() * 6); char c; for (int i = 0; i < len; i++) { c = str.charAt(i); diff --git a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java index bcfcaa77c..f208ad2a1 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java @@ -177,7 +177,7 @@ public class StrUtil extends CharSequenceUtil implements StrPool { * @return 字符串 */ public static String str(byte[] bytes, String charset) { - return str(bytes, isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset)); + return str(bytes, CharsetUtil.charset(charset)); } /** @@ -206,7 +206,7 @@ public class StrUtil extends CharSequenceUtil implements StrPool { * @return 字符串 */ public static String str(Byte[] bytes, String charset) { - return str(bytes, isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset)); + return str(bytes, CharsetUtil.charset(charset)); } /** @@ -243,7 +243,7 @@ public class StrUtil extends CharSequenceUtil implements StrPool { return null; } - return str(data, Charset.forName(charset)); + return str(data, CharsetUtil.charset(charset)); } /** From 9818263d30523fade69b58f9f924d35ada13866a Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 21 Nov 2021 05:23:41 +0800 Subject: [PATCH 5/6] add methods --- .../main/java/cn/hutool/core/lang/Opt.java | 79 +++++++++++++------ .../java/cn/hutool/core/util/StrUtil.java | 11 +++ .../java/cn/hutool/core/lang/OptTest.java | 8 +- 3 files changed, 71 insertions(+), 27 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java b/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java index 6e8f74ac7..f3b23892c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java @@ -25,6 +25,7 @@ package cn.hutool.core.lang; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.lang.func.Func0; import cn.hutool.core.lang.func.VoidFunc0; import cn.hutool.core.util.StrUtil; @@ -105,23 +106,25 @@ public class Opt { * @param value 传入需要包裹的元素 * @param 包裹里元素的类型 * @return 一个包裹里元素可能为空的 {@code Opt} + * @since 5.7.17 */ public static Opt> ofEmptyAble(List value) { return CollectionUtil.isEmpty(value) ? empty() : new Opt<>(value); } /** - * 执行一系列操作,如果途中发生 {@code NPE} 和 {@code IndexOutOfBoundsException},返回一个空的{@code Opt} * * @param supplier 操作 * @param 类型 * @return 操作执行后的值 */ - public static Opt exec(Supplier supplier) { + public static Opt ofTry(Func0 supplier) { try { - return Opt.ofNullable(supplier.get()); - } catch (NullPointerException | IndexOutOfBoundsException e) { - return empty(); + return Opt.ofNullable(supplier.call()); + } catch (Exception e) { + final Opt empty = Opt.empty(); + empty.exception = e; + return empty; } } @@ -129,6 +132,7 @@ public class Opt { * 包裹里实际的元素 */ private final T value; + private Exception exception; /** * {@code Opt}的构造函数 @@ -151,16 +155,7 @@ public class Opt { * @return 包裹里的元素,有可能为{@code null} */ public T get() { - return value; - } - - /** - * 判断包裹里元素的值是否存在,存在为 {@code true},否则为{@code false} - * - * @return 包裹里元素的值存在为 {@code true},否则为{@code false} - */ - public boolean isPresent() { - return value != null; + return this.value; } /** @@ -173,6 +168,37 @@ public class Opt { return value == null; } + /** + * 获取异常
+ * 当调用 {@link #ofTry(Func0)}时,异常信息不会抛出,而是保存,调用此方法获取抛出的异常 + * + * @return 异常 + * @since 5.7.17 + */ + public Exception getException(){ + return this.exception; + } + + /** + * 是否失败
+ * 当调用 {@link #ofTry(Func0)}时,抛出异常则表示失败 + * + * @return 是否失败 + * @since 5.7.17 + */ + public boolean isFail(){ + return null != this.exception; + } + + /** + * 判断包裹里元素的值是否存在,存在为 {@code true},否则为{@code false} + * + * @return 包裹里元素的值存在为 {@code true},否则为{@code false} + */ + public boolean isPresent() { + return value != null; + } + /** * 如果包裹里的值存在,就执行传入的操作({@link Consumer#accept}) * @@ -405,7 +431,18 @@ public class Opt { * @return 如果包裹里元素的值存在,则返回该值,否则返回传入的{@code other} */ public T orElse(T other) { - return value != null ? value : other; + return isPresent() ? value : other; + } + + /** + * 异常则返回另一个可选值 + * + * @param other 可选值 + * @return 如果未发生异常,则返回该值,否则返回传入的{@code other} + * @since 5.7.17 + */ + public T exceptionOrElse(T other){ + return isFail() ? other : value; } /** @@ -416,7 +453,7 @@ public class Opt { * @throws NullPointerException 如果之不存在,并且传入的操作为空,则抛出 {@code NPE} */ public T orElseGet(Supplier supplier) { - return value != null ? value : supplier.get(); + return isPresent() ? value : supplier.get(); } /** @@ -440,7 +477,7 @@ public class Opt { * @throws NullPointerException 如果值不存在并且 传入的操作为 {@code null}或者操作执行后的返回值为{@code null} */ public T orElseThrow(Supplier exceptionSupplier) throws X { - if (value != null) { + if (isPresent()) { return value; } else { throw exceptionSupplier.get(); @@ -464,7 +501,7 @@ public class Opt { * @author VampireAchao */ public T orElseThrow(Function exceptionFunction, String message) throws X { - if (value != null) { + if (isPresent()) { return value; } else { throw exceptionFunction.apply(message); @@ -526,8 +563,6 @@ public class Opt { */ @Override public String toString() { - return value != null - ? value.toString() - : null; + return StrUtil.toStringOrNull(this.value); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java index f208ad2a1..e0d6dc119 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java @@ -272,6 +272,17 @@ public class StrUtil extends CharSequenceUtil implements StrPool { return String.valueOf(obj); } + /** + * 调用对象的toString方法,null会返回{@code null} + * + * @param obj 对象 + * @return 字符串 or {@code null} + * @since 5.7.17 + */ + public static String toStringOrNull(Object obj) { + return null == obj ? null : obj.toString(); + } + /** * 创建StringBuilder对象 * diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/OptTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/OptTest.java index 013e7897d..0bdab907d 100644 --- a/hutool-core/src/test/java/cn/hutool/core/lang/OptTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/OptTest.java @@ -177,12 +177,12 @@ public class OptTest { String indexOutSituation = Opt.ofEmptyAble(last).map(l -> l.get(0)).orElse("hutool"); // 现在代码整洁度降低,但可读性up,如果再人说看不懂这代码... - String npe = Opt.exec(() -> last.get(0)).orElse("hutool"); - String indexOut = Opt.exec(() -> { + String npe = Opt.ofTry(() -> last.get(0)).exceptionOrElse("hutool"); + String indexOut = Opt.ofTry(() -> { List list = new ArrayList<>(); // 你可以在里面写一长串调用链 list.get(0).getUser().getId() return list.get(0); - }).orElse("hutool"); + }).exceptionOrElse("hutool"); Assert.assertEquals(npe, npeSituation); Assert.assertEquals(indexOut, indexOutSituation); Assert.assertEquals("hutool", npe); @@ -197,6 +197,4 @@ public class OptTest { private String username; private String nickname; } - - } From d0a86d573408a605fd0c930fc189b34c11882402 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 21 Nov 2021 05:24:28 +0800 Subject: [PATCH 6/6] add methods --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0f10bfb8..be9effe61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ * 【core 】 CollStreamUtil增加是否并行的重载(pr#467@Gitee) * 【core 】 ResourceClassLoader增加缓存(pr#1959@Github) * 【crypto 】 增加CipherWrapper,增加setRandom(issue#1958@Github) +* 【core 】 Opt增加ofTry方法(pr#1956@Github) * ### 🐞Bug修复 * 【core 】 修复FileResource构造fileName参数无效问题(issue#1942@Github)