Merge remote-tracking branch 'origin/v5-dev' into v5-dev

This commit is contained in:
bob.guo 2021-11-23 15:25:14 +08:00
commit 7add03c7b3
12 changed files with 123 additions and 63 deletions

View File

@ -3,7 +3,7 @@
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.7.17 (2021-11-19) # 5.7.17 (2021-11-20)
### 🐣新特性 ### 🐣新特性
* 【core 】 增加AsyncUtilpr#457@Gitee * 【core 】 增加AsyncUtilpr#457@Gitee
@ -20,10 +20,12 @@
* 【core 】 CollStreamUtil增加是否并行的重载pr#467@Gitee * 【core 】 CollStreamUtil增加是否并行的重载pr#467@Gitee
* 【core 】 ResourceClassLoader增加缓存pr#1959@Github * 【core 】 ResourceClassLoader增加缓存pr#1959@Github
* 【crypto 】 增加CipherWrapper增加setRandomissue#1958@Github * 【crypto 】 增加CipherWrapper增加setRandomissue#1958@Github
* 【core 】 Opt增加ofTry方法pr#1956@Github
* *
### 🐞Bug修复 ### 🐞Bug修复
* 【core 】 修复FileResource构造fileName参数无效问题issue#1942@Github * 【core 】 修复FileResource构造fileName参数无效问题issue#1942@Github
* 【cache 】 修复WeakCache键值强关联导致的无法回收问题issue#1953@Github * 【cache 】 修复WeakCache键值强关联导致的无法回收问题issue#1953@Github
* 【core 】 修复ZipUtil相对路径父路径获取null问题issue#1961@Github
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------

View File

@ -25,6 +25,7 @@
package cn.hutool.core.lang; package cn.hutool.core.lang;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.lang.func.VoidFunc0; import cn.hutool.core.lang.func.VoidFunc0;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
@ -105,15 +106,33 @@ public class Opt<T> {
* @param value 传入需要包裹的元素 * @param value 传入需要包裹的元素
* @param <T> 包裹里元素的类型 * @param <T> 包裹里元素的类型
* @return 一个包裹里元素可能为空的 {@code Opt} * @return 一个包裹里元素可能为空的 {@code Opt}
* @since 5.7.17
*/ */
public static <T> Opt<List<T>> ofEmptyAble(List<T> value) { public static <T> Opt<List<T>> ofEmptyAble(List<T> value) {
return CollectionUtil.isEmpty(value) ? empty() : new Opt<>(value); return CollectionUtil.isEmpty(value) ? empty() : new Opt<>(value);
} }
/**
*
* @param supplier 操作
* @param <T> 类型
* @return 操作执行后的值
*/
public static <T> Opt<T> ofTry(Func0<T> supplier) {
try {
return Opt.ofNullable(supplier.call());
} catch (Exception e) {
final Opt<T> empty = Opt.empty();
empty.exception = e;
return empty;
}
}
/** /**
* 包裹里实际的元素 * 包裹里实际的元素
*/ */
private final T value; private final T value;
private Exception exception;
/** /**
* {@code Opt}的构造函数 * {@code Opt}的构造函数
@ -136,16 +155,7 @@ public class Opt<T> {
* @return 包裹里的元素有可能为{@code null} * @return 包裹里的元素有可能为{@code null}
*/ */
public T get() { public T get() {
return value; return this.value;
}
/**
* 判断包裹里元素的值是否存在存在为 {@code true}否则为{@code false}
*
* @return 包裹里元素的值存在为 {@code true}否则为{@code false}
*/
public boolean isPresent() {
return value != null;
} }
/** /**
@ -158,6 +168,37 @@ public class Opt<T> {
return value == null; return value == null;
} }
/**
* 获取异常<br>
* 当调用 {@link #ofTry(Func0)}异常信息不会抛出而是保存调用此方法获取抛出的异常
*
* @return 异常
* @since 5.7.17
*/
public Exception getException(){
return this.exception;
}
/**
* 是否失败<br>
* 当调用 {@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}) * 如果包裹里的值存在就执行传入的操作({@link Consumer#accept})
* *
@ -390,7 +431,18 @@ public class Opt<T> {
* @return 如果包裹里元素的值存在则返回该值否则返回传入的{@code other} * @return 如果包裹里元素的值存在则返回该值否则返回传入的{@code other}
*/ */
public T orElse(T 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;
} }
/** /**
@ -401,7 +453,7 @@ public class Opt<T> {
* @throws NullPointerException 如果之不存在并且传入的操作为空则抛出 {@code NPE} * @throws NullPointerException 如果之不存在并且传入的操作为空则抛出 {@code NPE}
*/ */
public T orElseGet(Supplier<? extends T> supplier) { public T orElseGet(Supplier<? extends T> supplier) {
return value != null ? value : supplier.get(); return isPresent() ? value : supplier.get();
} }
/** /**
@ -411,10 +463,7 @@ public class Opt<T> {
* @throws NoSuchElementException 如果包裹里的值不存在则抛出该异常 * @throws NoSuchElementException 如果包裹里的值不存在则抛出该异常
*/ */
public T orElseThrow() { public T orElseThrow() {
if (value == null) { return orElseThrow(NoSuchElementException::new, "No value present");
throw new NoSuchElementException("No value present");
}
return value;
} }
/** /**
@ -428,7 +477,7 @@ public class Opt<T> {
* @throws NullPointerException 如果值不存在并且 传入的操作为 {@code null}或者操作执行后的返回值为{@code null} * @throws NullPointerException 如果值不存在并且 传入的操作为 {@code null}或者操作执行后的返回值为{@code null}
*/ */
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) { if (isPresent()) {
return value; return value;
} else { } else {
throw exceptionSupplier.get(); throw exceptionSupplier.get();
@ -452,7 +501,7 @@ public class Opt<T> {
* @author VampireAchao * @author VampireAchao
*/ */
public <X extends Throwable> T orElseThrow(Function<String, ? extends X> exceptionFunction, String message) throws X { public <X extends Throwable> T orElseThrow(Function<String, ? extends X> exceptionFunction, String message) throws X {
if (value != null) { if (isPresent()) {
return value; return value;
} else { } else {
throw exceptionFunction.apply(message); throw exceptionFunction.apply(message);
@ -469,22 +518,6 @@ public class Opt<T> {
return Optional.ofNullable(this.value); return Optional.ofNullable(this.value);
} }
/**
* 执行一系列操作如果途中发生 {@code NPE} {@code IndexOutOfBoundsException}返回一个空的{@code Opt}
*
* @param supplier 操作
* @param <T> 类型
* @return 操作执行后的值
*/
public static <T> Opt<T> exec(Supplier<T> supplier) {
try {
return Opt.ofNullable(supplier.get());
} catch (NullPointerException | IndexOutOfBoundsException e) {
return empty();
}
}
/** /**
* 判断传入参数是否与 {@code Opt}相等 * 判断传入参数是否与 {@code Opt}相等
* 在以下情况下返回true * 在以下情况下返回true
@ -530,8 +563,6 @@ public class Opt<T> {
*/ */
@Override @Override
public String toString() { public String toString() {
return value != null return StrUtil.toStringOrNull(this.value);
? value.toString()
: null;
} }
} }

View File

@ -2471,21 +2471,22 @@ public class CharSequenceUtil {
* *
* @param str 被重复的字符串 * @param str 被重复的字符串
* @param count 数量 * @param count 数量
* @param conjunction 分界符 * @param delimiter 分界符
* @return 连接后的字符串 * @return 连接后的字符串
* @since 4.0.1 * @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) { if (count <= 0) {
return EMPTY; return EMPTY;
} }
final StrBuilder builder = StrBuilder.create(); final StringBuilder builder = new StringBuilder(str.length() * count);
boolean isFirst = true; builder.append(str);
count--;
final boolean isAppendDelimiter = isNotEmpty(delimiter);
while (count-- > 0) { while (count-- > 0) {
if (isFirst) { if (isAppendDelimiter) {
isFirst = false; builder.append(delimiter);
} else if (isNotEmpty(conjunction)) {
builder.append(conjunction);
} }
builder.append(str); builder.append(str);
} }
@ -3521,7 +3522,7 @@ public class CharSequenceUtil {
fromIndex = 0; fromIndex = 0;
} }
final StrBuilder result = StrBuilder.create(strLength + 16); final StringBuilder result = new StringBuilder(strLength - searchStrLength + replacement.length());
if (0 != fromIndex) { if (0 != fromIndex) {
result.append(str.subSequence(0, fromIndex)); result.append(str.subSequence(0, fromIndex));
} }
@ -4285,7 +4286,7 @@ public class CharSequenceUtil {
// 循环位移当越界时循环 // 循环位移当越界时循环
moveLength = moveLength % len; moveLength = moveLength % len;
} }
final StrBuilder strBuilder = StrBuilder.create(len); final StringBuilder strBuilder = new StringBuilder(len);
if (moveLength > 0) { if (moveLength > 0) {
int endAfterMove = Math.min(endExclude + moveLength, str.length()); int endAfterMove = Math.min(endExclude + moveLength, str.length());
strBuilder.append(str.subSequence(0, startInclude))// strBuilder.append(str.subSequence(0, startInclude))//

View File

@ -191,11 +191,10 @@ public class StrJoiner implements Appendable, Serializable {
/** /**
* 追加对象到拼接器中 * 追加对象到拼接器中
* *
* @param <T> 元素类型
* @param obj 对象支持数组集合等 * @param obj 对象支持数组集合等
* @return this * @return this
*/ */
public <T> StrJoiner append(Object obj) { public StrJoiner append(Object obj) {
if (null == obj) { if (null == obj) {
append((CharSequence) null); append((CharSequence) null);
} else if (ArrayUtil.isArray(obj)) { } else if (ArrayUtil.isArray(obj)) {

View File

@ -25,7 +25,7 @@ public class UnicodeUtil {
} }
final int len = unicode.length(); final int len = unicode.length();
StrBuilder sb = StrBuilder.create(len); StringBuilder sb = new StringBuilder(len);
int i; int i;
int pos = 0; int pos = 0;
while ((i = StrUtil.indexOfIgnoreCase(unicode, "\\u", pos)) != -1) { while ((i = StrUtil.indexOfIgnoreCase(unicode, "\\u", pos)) != -1) {
@ -101,7 +101,7 @@ public class UnicodeUtil {
} }
final int len = str.length(); final int len = str.length();
final StrBuilder unicode = StrBuilder.create(str.length() * 6); final StringBuilder unicode = new StringBuilder(str.length() * 6);
char c; char c;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
c = str.charAt(i); c = str.charAt(i);

View File

@ -716,6 +716,9 @@ public class NumberUtil {
* @since 3.1.0 * @since 3.1.0
*/ */
public static BigDecimal div(Number v1, Number v2, int scale, RoundingMode roundingMode) { 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); return div(v1.toString(), v2.toString(), scale, roundingMode);
} }

View File

@ -177,7 +177,7 @@ public class StrUtil extends CharSequenceUtil implements StrPool {
* @return 字符串 * @return 字符串
*/ */
public static String str(byte[] bytes, String charset) { 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 字符串 * @return 字符串
*/ */
public static String str(Byte[] bytes, String charset) { 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 null;
} }
return str(data, Charset.forName(charset)); return str(data, CharsetUtil.charset(charset));
} }
/** /**
@ -272,6 +272,17 @@ public class StrUtil extends CharSequenceUtil implements StrPool {
return String.valueOf(obj); 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对象 * 创建StringBuilder对象
* *

View File

@ -1002,8 +1002,17 @@ public class ZipUtil {
throw new UtilException(StrUtil.format("File [{}] not exist!", srcFile.getAbsolutePath())); 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()); throw new UtilException("Zip file path [{}] must not be the child directory of [{}] !", zipFile.getPath(), srcFile.getPath());
} }
} }

View File

@ -177,12 +177,12 @@ public class OptTest {
String indexOutSituation = Opt.ofEmptyAble(last).map(l -> l.get(0)).orElse("hutool"); String indexOutSituation = Opt.ofEmptyAble(last).map(l -> l.get(0)).orElse("hutool");
// 现在代码整洁度降低但可读性up如果再人说看不懂这代码... // 现在代码整洁度降低但可读性up如果再人说看不懂这代码...
String npe = Opt.exec(() -> last.get(0)).orElse("hutool"); String npe = Opt.ofTry(() -> last.get(0)).exceptionOrElse("hutool");
String indexOut = Opt.exec(() -> { String indexOut = Opt.ofTry(() -> {
List<String> list = new ArrayList<>(); List<String> list = new ArrayList<>();
// 你可以在里面写一长串调用链 list.get(0).getUser().getId() // 你可以在里面写一长串调用链 list.get(0).getUser().getId()
return list.get(0); return list.get(0);
}).orElse("hutool"); }).exceptionOrElse("hutool");
Assert.assertEquals(npe, npeSituation); Assert.assertEquals(npe, npeSituation);
Assert.assertEquals(indexOut, indexOutSituation); Assert.assertEquals(indexOut, indexOutSituation);
Assert.assertEquals("hutool", npe); Assert.assertEquals("hutool", npe);
@ -197,6 +197,4 @@ public class OptTest {
private String username; private String username;
private String nickname; private String nickname;
} }
} }

View File

@ -87,6 +87,12 @@ public class NumberUtilTest {
Assert.assertEquals(0.0, result, 0); 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 @Test
public void roundTest() { public void roundTest() {

View File

@ -25,7 +25,7 @@
<commons-logging.version>1.2</commons-logging.version> <commons-logging.version>1.2</commons-logging.version>
<tinylog.version>1.3.6</tinylog.version> <tinylog.version>1.3.6</tinylog.version>
<jboss-logging.version>3.4.2.Final</jboss-logging.version> <jboss-logging.version>3.4.2.Final</jboss-logging.version>
<logtube.version>0.39.2</logtube.version> <logtube.version>0.41.0</logtube.version>
</properties> </properties>
<dependencies> <dependencies>