mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-08-18 20:38:02 +08:00
Merge remote-tracking branch 'origin/v5-dev' into v5-dev
This commit is contained in:
18
CHANGELOG.md
18
CHANGELOG.md
@@ -2,12 +2,28 @@
|
|||||||
# 🚀Changelog
|
# 🚀Changelog
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
# 5.7.21 (2022-01-21)
|
# 5.7.21 (2022-02-07)
|
||||||
|
|
||||||
### 🐣新特性
|
### 🐣新特性
|
||||||
* 【extra 】 增加jetbrick模板支持
|
* 【extra 】 增加jetbrick模板支持
|
||||||
|
* 【extra 】 EmojiUtil增加方法(pr#519@Gitee)
|
||||||
|
* 【core 】 DateUtil 添加两个日期是否同一周方法(pr#516@Gitee)
|
||||||
|
* 【db 】 新增条件组,用于处理复杂的where条件(pr#514@Gitee)
|
||||||
|
* 【core 】 新增LocalDateTimeUtil.weekOfYear(issue#I4RWXC@Gitee)
|
||||||
|
* 【core 】 Month增加toJdkMonth、getValueBaseOne
|
||||||
|
* 【core 】 CsvWriter修改规则,去除末尾多余换行符(issue#I4RSQY@Gitee)
|
||||||
|
* 【core 】 DateUtil增加rangeFunc和rangeConsume(issue#I4RSQY@Gitee)
|
||||||
|
* 【core 】 DateTime增加setUseJdkToStringStyle方法
|
||||||
|
* 【core 】 CharSequenceUtil增加replace重载(issue#2122@Github)
|
||||||
|
* 【core 】 IntMap和LongMap使用位运算快速求解取余运算(pr#2123@Github)
|
||||||
|
* 【core 】 新增通用builder类:GenericBuilder(pr#526@Gitee)
|
||||||
|
* 【core 】 新增copySafely方法与mkdirsSafely方法(pr#527@Gitee)
|
||||||
|
|
||||||
### 🐞Bug修复
|
### 🐞Bug修复
|
||||||
* 【core 】 修复ChineseDate农历获取正月出现数组越界BUG(issue#2112@Github)
|
* 【core 】 修复ChineseDate农历获取正月出现数组越界BUG(issue#2112@Github)
|
||||||
|
* 【extra 】 修复EmojiUtil.toHtmlHex()方法(pr#519@Gitee)
|
||||||
|
* 【system 】 修复CpuInfo.getUsed()方法(issue#2116@Github)
|
||||||
|
* 【dfa 】 修复密集匹配和贪婪匹配冲突问题(issue#2126@Github)
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
# 5.7.20 (2022-01-20)
|
# 5.7.20 (2022-01-20)
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ echo ' / /_/ // / / // __// __ \ / __ \ / / '
|
|||||||
echo ' / __ // /_/ // /_ / /_/ // /_/ // / '
|
echo ' / __ // /_/ // /_ / /_/ // /_/ // / '
|
||||||
echo '/_/ /_/ \____/ \__/ \____/ \____//_/ '
|
echo '/_/ /_/ \____/ \__/ \____/ \____//_/ '
|
||||||
echo ''
|
echo ''
|
||||||
echo '-----------http://hutool.cn/------------'
|
echo '-----------https://hutool.cn/-----------'
|
||||||
echo '========================================'
|
echo '========================================'
|
||||||
|
|||||||
@@ -32,22 +32,22 @@ public class IntMap implements BitMap, Serializable {
|
|||||||
@Override
|
@Override
|
||||||
public void add(long i) {
|
public void add(long i) {
|
||||||
int r = (int) (i / BitMap.MACHINE32);
|
int r = (int) (i / BitMap.MACHINE32);
|
||||||
int c = (int) (i % BitMap.MACHINE32);
|
int c = (int) (i & (BitMap.MACHINE32 - 1));
|
||||||
ints[r] = ints[r] | (1 << c);
|
ints[r] = ints[r] | (1 << c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contains(long i) {
|
public boolean contains(long i) {
|
||||||
int r = (int) (i / BitMap.MACHINE32);
|
int r = (int) (i / BitMap.MACHINE32);
|
||||||
int c = (int) (i % BitMap.MACHINE32);
|
int c = (int) (i & (BitMap.MACHINE32 - 1));
|
||||||
return ((ints[r] >>> c) & 1) == 1;
|
return ((ints[r] >>> c) & 1) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(long i) {
|
public void remove(long i) {
|
||||||
int r = (int) (i / BitMap.MACHINE32);
|
int r = (int) (i / BitMap.MACHINE32);
|
||||||
int c = (int) (i % BitMap.MACHINE32);
|
int c = (int) (i & (BitMap.MACHINE32 - 1));
|
||||||
ints[r] &= ~(1 << c);
|
ints[r] &= ~(1 << c);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,22 +32,22 @@ public class LongMap implements BitMap, Serializable {
|
|||||||
@Override
|
@Override
|
||||||
public void add(long i) {
|
public void add(long i) {
|
||||||
int r = (int) (i / BitMap.MACHINE64);
|
int r = (int) (i / BitMap.MACHINE64);
|
||||||
long c = i % BitMap.MACHINE64;
|
long c = i & (BitMap.MACHINE64 - 1);
|
||||||
longs[r] = longs[r] | (1L << c);
|
longs[r] = longs[r] | (1L << c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contains(long i) {
|
public boolean contains(long i) {
|
||||||
int r = (int) (i / BitMap.MACHINE64);
|
int r = (int) (i / BitMap.MACHINE64);
|
||||||
long c = i % BitMap.MACHINE64;
|
long c = i & (BitMap.MACHINE64 - 1);
|
||||||
return ((longs[r] >>> c) & 1) == 1;
|
return ((longs[r] >>> c) & 1) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(long i) {
|
public void remove(long i) {
|
||||||
int r = (int) (i / BitMap.MACHINE64);
|
int r = (int) (i / BitMap.MACHINE64);
|
||||||
long c = i % BitMap.MACHINE64;
|
long c = i & (BitMap.MACHINE64 - 1);
|
||||||
longs[r] &= ~(1L << c);
|
longs[r] &= ~(1L << c);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import cn.hutool.core.lang.func.Func0;
|
|||||||
/**
|
/**
|
||||||
* Bean属性缓存<br>
|
* Bean属性缓存<br>
|
||||||
* 缓存用于防止多次反射造成的性能问题
|
* 缓存用于防止多次反射造成的性能问题
|
||||||
* @author Looly
|
|
||||||
*
|
*
|
||||||
|
* @author Looly
|
||||||
*/
|
*/
|
||||||
public enum BeanDescCache {
|
public enum BeanDescCache {
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
@@ -16,12 +16,22 @@ public enum BeanDescCache {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得属性名和{@link BeanDesc}Map映射
|
* 获得属性名和{@link BeanDesc}Map映射
|
||||||
|
*
|
||||||
* @param beanClass Bean的类
|
* @param beanClass Bean的类
|
||||||
* @param supplier 对象不存在时创建对象的函数
|
* @param supplier 对象不存在时创建对象的函数
|
||||||
* @return 属性名和{@link BeanDesc}映射
|
* @return 属性名和{@link BeanDesc}映射
|
||||||
* @since 5.4.2
|
* @since 5.4.2
|
||||||
*/
|
*/
|
||||||
public BeanDesc getBeanDesc(Class<?> beanClass, Func0<BeanDesc> supplier){
|
public BeanDesc getBeanDesc(Class<?> beanClass, Func0<BeanDesc> supplier) {
|
||||||
return bdCache.get(beanClass, supplier);
|
return bdCache.get(beanClass, supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空全局的Bean属性缓存
|
||||||
|
*
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
public void clear() {
|
||||||
|
this.bdCache.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,16 @@ public enum BeanInfoCache {
|
|||||||
getCache(ignoreCase).put(beanClass, fieldNamePropertyDescriptorMap);
|
getCache(ignoreCase).put(beanClass, fieldNamePropertyDescriptorMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空缓存
|
||||||
|
*
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
public void clear() {
|
||||||
|
this.pdCache.clear();
|
||||||
|
this.ignoreCasePdCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据是否忽略字段名的大小写,返回不用Cache对象
|
* 根据是否忽略字段名的大小写,返回不用Cache对象
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,208 @@
|
|||||||
|
package cn.hutool.core.builder;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.func.Supplier1;
|
||||||
|
import cn.hutool.core.lang.func.Supplier2;
|
||||||
|
import cn.hutool.core.lang.func.Supplier3;
|
||||||
|
import cn.hutool.core.lang.func.Supplier4;
|
||||||
|
import cn.hutool.core.lang.func.Supplier5;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>通用Builder</p>
|
||||||
|
* 参考: <a href="https://blog.csdn.net/weixin_43935907/article/details/105003719">一看就会的java8通用Builder</a>
|
||||||
|
* <p>使用方法如下:</p>
|
||||||
|
* <pre>
|
||||||
|
* Box box = GenericBuilder
|
||||||
|
* .of(Box::new)
|
||||||
|
* .with(Box::setId, 1024L)
|
||||||
|
* .with(Box::setTitle, "Hello World!")
|
||||||
|
* .with(Box::setLength, 9)
|
||||||
|
* .with(Box::setWidth, 8)
|
||||||
|
* .with(Box::setHeight, 7)
|
||||||
|
* .build();
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p> 我们也可以对已创建的对象进行修改:</p>
|
||||||
|
* <pre>
|
||||||
|
* Box boxModified = GenericBuilder
|
||||||
|
* .of(() -> box)
|
||||||
|
* .with(Box::setTitle, "Hello Friend!")
|
||||||
|
* .with(Box::setLength, 3)
|
||||||
|
* .with(Box::setWidth, 4)
|
||||||
|
* .with(Box::setHeight, 5)
|
||||||
|
* .build();
|
||||||
|
* </pre>
|
||||||
|
* <p> 我们还可以对这样调用有参构造,这对于创建一些在有参构造中包含初始化函数的对象是有意义的:</p>
|
||||||
|
* <pre>
|
||||||
|
* Box box1 = GenericBuilder
|
||||||
|
* .of(Box::new, 2048L, "Hello Partner!", 222, 333, 444)
|
||||||
|
* .with(Box::alis)
|
||||||
|
* .build();
|
||||||
|
* </pre>
|
||||||
|
* <p>注意:本工具类支持调用的方法的参数数量不超过1个,更多的参数不利于阅读和维护。</p>
|
||||||
|
*
|
||||||
|
* @author TomXin
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
public class GenericBuilder<T> implements Builder<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实例化器
|
||||||
|
*/
|
||||||
|
private final Supplier<T> instant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改器列表
|
||||||
|
*/
|
||||||
|
private final List<Consumer<T>> modifiers = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param instant 实例化器
|
||||||
|
*/
|
||||||
|
public GenericBuilder(Supplier<T> instant) {
|
||||||
|
this.instant = instant;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过无参数实例化器创建GenericBuilder
|
||||||
|
*
|
||||||
|
* @param instant 实例化器
|
||||||
|
* @param <T> 目标类型
|
||||||
|
* @return GenericBuilder对象
|
||||||
|
*/
|
||||||
|
public static <T> GenericBuilder<T> of(Supplier<T> instant) {
|
||||||
|
return new GenericBuilder<>(instant);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过1参数实例化器创建GenericBuilder
|
||||||
|
*
|
||||||
|
* @param instant 实例化器
|
||||||
|
* @param p1 参数一
|
||||||
|
* @param <T> 目标类型
|
||||||
|
* @param <P1> 参数一类型
|
||||||
|
* @return GenericBuilder对象
|
||||||
|
*/
|
||||||
|
public static <T, P1> GenericBuilder<T> of(Supplier1<T, P1> instant, P1 p1) {
|
||||||
|
return of(instant.toSupplier(p1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过2参数实例化器创建GenericBuilder
|
||||||
|
*
|
||||||
|
* @param instant 实例化器
|
||||||
|
* @param p1 参数一
|
||||||
|
* @param p2 参数二
|
||||||
|
* @param <T> 目标类型
|
||||||
|
* @param <P1> 参数一类型
|
||||||
|
* @param <P2> 参数二类型
|
||||||
|
* @return GenericBuilder对象
|
||||||
|
*/
|
||||||
|
public static <T, P1, P2> GenericBuilder<T> of(Supplier2<T, P1, P2> instant, P1 p1, P2 p2) {
|
||||||
|
return of(instant.toSupplier(p1, p2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过3参数实例化器创建GenericBuilder
|
||||||
|
*
|
||||||
|
* @param instant 实例化器
|
||||||
|
* @param p1 参数一
|
||||||
|
* @param p2 参数二
|
||||||
|
* @param p3 参数三
|
||||||
|
* @param <T> 目标类型
|
||||||
|
* @param <P1> 参数一类型
|
||||||
|
* @param <P2> 参数二类型
|
||||||
|
* @param <P3> 参数三类型
|
||||||
|
* @return GenericBuilder对象
|
||||||
|
*/
|
||||||
|
public static <T, P1, P2, P3> GenericBuilder<T> of(Supplier3<T, P1, P2, P3> instant, P1 p1, P2 p2, P3 p3) {
|
||||||
|
return of(instant.toSupplier(p1, p2, p3));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过4参数实例化器创建GenericBuilder
|
||||||
|
*
|
||||||
|
* @param instant 实例化器
|
||||||
|
* @param p1 参数一
|
||||||
|
* @param p2 参数二
|
||||||
|
* @param p3 参数三
|
||||||
|
* @param p4 参数四
|
||||||
|
* @param <T> 目标类型
|
||||||
|
* @param <P1> 参数一类型
|
||||||
|
* @param <P2> 参数二类型
|
||||||
|
* @param <P3> 参数三类型
|
||||||
|
* @param <P4> 参数四类型
|
||||||
|
* @return GenericBuilder对象
|
||||||
|
*/
|
||||||
|
public static <T, P1, P2, P3, P4> GenericBuilder<T> of(Supplier4<T, P1, P2, P3, P4> instant, P1 p1, P2 p2, P3 p3, P4 p4) {
|
||||||
|
return of(instant.toSupplier(p1, p2, p3, p4));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过5参数实例化器创建GenericBuilder
|
||||||
|
*
|
||||||
|
* @param instant 实例化器
|
||||||
|
* @param p1 参数一
|
||||||
|
* @param p2 参数二
|
||||||
|
* @param p3 参数三
|
||||||
|
* @param p4 参数四
|
||||||
|
* @param p5 参数五
|
||||||
|
* @param <T> 目标类型
|
||||||
|
* @param <P1> 参数一类型
|
||||||
|
* @param <P2> 参数二类型
|
||||||
|
* @param <P3> 参数三类型
|
||||||
|
* @param <P4> 参数四类型
|
||||||
|
* @param <P5> 参数五类型
|
||||||
|
* @return GenericBuilder对象
|
||||||
|
*/
|
||||||
|
public static <T, P1, P2, P3, P4, P5> GenericBuilder<T> of(Supplier5<T, P1, P2, P3, P4, P5> instant, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
|
||||||
|
return of(instant.toSupplier(p1, p2, p3, p4, p5));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用无参数方法
|
||||||
|
*
|
||||||
|
* @param consumer 无参数Consumer
|
||||||
|
* @return GenericBuilder对象
|
||||||
|
*/
|
||||||
|
public GenericBuilder<T> with(Consumer<T> consumer) {
|
||||||
|
modifiers.add(consumer);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用1参数方法
|
||||||
|
*
|
||||||
|
* @param <P1> 参数一类型
|
||||||
|
* @param consumer 1参数Consumer,一般为Setter方法引用
|
||||||
|
* @param p1 参数一
|
||||||
|
* @return GenericBuilder对象
|
||||||
|
*/
|
||||||
|
public <P1> GenericBuilder<T> with(BiConsumer<T, P1> consumer, P1 p1) {
|
||||||
|
modifiers.add(instant -> consumer.accept(instant, p1));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建
|
||||||
|
*
|
||||||
|
* @return 目标对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public T build() {
|
||||||
|
T value = instant.get();
|
||||||
|
modifiers.forEach(modifier -> modifier.accept(value));
|
||||||
|
modifiers.clear();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -132,7 +132,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取秒级别的开始时间,即忽略毫秒部分
|
* 修改秒级别的开始时间,即忽略毫秒部分
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -143,7 +143,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取秒级别的结束时间,即毫秒设置为999
|
* 修改秒级别的结束时间,即毫秒设置为999
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -154,7 +154,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某小时的开始时间
|
* 修改某小时的开始时间
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -164,7 +164,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某小时的结束时间
|
* 修改某小时的结束时间
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -174,7 +174,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某分钟的开始时间
|
* 修改某分钟的开始时间
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -184,7 +184,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某分钟的结束时间
|
* 修改某分钟的结束时间
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -194,7 +194,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某天的开始时间
|
* 修改某天的开始时间
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -204,7 +204,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某天的结束时间
|
* 修改某天的结束时间
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -214,7 +214,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取给定日期当前周的开始时间,周一定为一周的开始时间
|
* 修改给定日期当前周的开始时间,周一定为一周的开始时间
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -224,7 +224,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取给定日期当前周的开始时间
|
* 修改给定日期当前周的开始时间
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @param isMondayAsFirstDay 是否周一做为一周的第一天(false表示周日做为第一天)
|
* @param isMondayAsFirstDay 是否周一做为一周的第一天(false表示周日做为第一天)
|
||||||
@@ -238,7 +238,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某周的结束时间,周日定为一周的结束
|
* 修改某周的结束时间,周日定为一周的结束
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -248,7 +248,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某周的结束时间
|
* 修改某周的结束时间
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @param isSundayAsLastDay 是否周日做为一周的最后一天(false表示周六做为最后一天)
|
* @param isSundayAsLastDay 是否周日做为一周的最后一天(false表示周六做为最后一天)
|
||||||
@@ -261,7 +261,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某月的开始时间
|
* 修改某月的开始时间
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -271,7 +271,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某月的结束时间
|
* 修改某月的结束时间
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -281,7 +281,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某季度的开始时间
|
* 修改某季度的开始时间
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -313,7 +313,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某年的开始时间
|
* 修改某年的开始时间
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -323,7 +323,7 @@ public class CalendarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取某年的结束时间
|
* 修改某年的结束时间
|
||||||
*
|
*
|
||||||
* @param calendar 日期 {@link Calendar}
|
* @param calendar 日期 {@link Calendar}
|
||||||
* @return {@link Calendar}
|
* @return {@link Calendar}
|
||||||
@@ -348,6 +348,40 @@ public class CalendarUtil {
|
|||||||
cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA);
|
cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比较两个日期是否为同一周
|
||||||
|
*
|
||||||
|
* @param cal1 日期1
|
||||||
|
* @param cal2 日期2
|
||||||
|
* @param isMon 是否为周一。国内第一天为星期一,国外第一天为星期日
|
||||||
|
* @return 是否为同一周
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
public static boolean isSameWeek(Calendar cal1, Calendar cal2, boolean isMon) {
|
||||||
|
if (cal1 == null || cal2 == null) {
|
||||||
|
throw new IllegalArgumentException("The date must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防止比较前修改原始Calendar对象
|
||||||
|
cal1 = (Calendar) cal1.clone();
|
||||||
|
cal2 = (Calendar) cal2.clone();
|
||||||
|
|
||||||
|
// 把所传日期设置为其当前周的第一天
|
||||||
|
// 比较设置后的两个日期是否是同一天:true 代表同一周
|
||||||
|
if (isMon) {
|
||||||
|
cal1.setFirstDayOfWeek(Calendar.MONDAY);
|
||||||
|
cal1.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
|
||||||
|
cal2.setFirstDayOfWeek(Calendar.MONDAY);
|
||||||
|
cal2.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
|
||||||
|
} else {
|
||||||
|
cal1.setFirstDayOfWeek(Calendar.SUNDAY);
|
||||||
|
cal1.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
|
||||||
|
cal2.setFirstDayOfWeek(Calendar.SUNDAY);
|
||||||
|
cal2.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
|
||||||
|
}
|
||||||
|
return isSameDay(cal1, cal2);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 比较两个日期是否为同一月
|
* 比较两个日期是否为同一月
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -24,13 +24,30 @@ import java.util.Locale;
|
|||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 包装java.util.Date
|
* 包装{@link Date}<br>
|
||||||
|
* 此类继承了{@link Date},并提供扩展方法,如时区等。<br>
|
||||||
|
* 此类重写了父类的{@code toString()}方法,返回值为"yyyy-MM-dd HH:mm:ss"格式
|
||||||
*
|
*
|
||||||
* @author xiaoleilu
|
* @author xiaoleilu
|
||||||
*/
|
*/
|
||||||
public class DateTime extends Date {
|
public class DateTime extends Date {
|
||||||
private static final long serialVersionUID = -5395712593979185936L;
|
private static final long serialVersionUID = -5395712593979185936L;
|
||||||
|
|
||||||
|
private static boolean useJdkToStringStyle = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置全局的,是否使用{@link Date}默认的toString()格式<br>
|
||||||
|
* 如果为{@code true},则调用toString()时返回"EEE MMM dd HH:mm:ss zzz yyyy"格式,<br>
|
||||||
|
* 如果为{@code false},则返回"yyyy-MM-dd HH:mm:ss",<br>
|
||||||
|
* 默认为{@code false}
|
||||||
|
*
|
||||||
|
* @param customUseJdkToStringStyle 是否使用{@link Date}默认的toString()格式
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
public static void setUseJdkToStringStyle(boolean customUseJdkToStringStyle){
|
||||||
|
useJdkToStringStyle = customUseJdkToStringStyle;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否可变对象
|
* 是否可变对象
|
||||||
*/
|
*/
|
||||||
@@ -932,13 +949,18 @@ public class DateTime extends Date {
|
|||||||
// -------------------------------------------------------------------- toString start
|
// -------------------------------------------------------------------- toString start
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转为"yyyy-MM-dd HH:mm:ss" 格式字符串<br>
|
* 转为字符串,如果时区被设置,会转换为其时区对应的时间,否则转换为当前地点对应的时区<br>
|
||||||
* 如果时区被设置,会转换为其时区对应的时间,否则转换为当前地点对应的时区
|
* 可以调用{@link DateTime#setUseJdkToStringStyle(boolean)} 方法自定义默认的风格<br>
|
||||||
|
* 如果{@link #useJdkToStringStyle}为{@code true},返回"EEE MMM dd HH:mm:ss zzz yyyy"格式,<br>
|
||||||
|
* 如果为{@code false},则返回"yyyy-MM-dd HH:mm:ss"
|
||||||
*
|
*
|
||||||
* @return "yyyy-MM-dd HH:mm:ss" 格式字符串
|
* @return 格式字符串
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
if(useJdkToStringStyle){
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
return toString(this.timeZone);
|
return toString(this.timeZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ import java.time.LocalDateTime;
|
|||||||
import java.time.Year;
|
import java.time.Year;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
@@ -28,6 +30,8 @@ import java.util.List;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 时间工具类
|
* 时间工具类
|
||||||
@@ -1586,6 +1590,21 @@ public class DateUtil extends CalendarUtil {
|
|||||||
return CalendarUtil.isSameDay(calendar(date1), calendar(date2));
|
return CalendarUtil.isSameDay(calendar(date1), calendar(date2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比较两个日期是否为同一周
|
||||||
|
*
|
||||||
|
* @param date1 日期1
|
||||||
|
* @param date2 日期2
|
||||||
|
* @param isMon 是否为周一。国内第一天为星期一,国外第一天为星期日
|
||||||
|
* @return 是否为同一周
|
||||||
|
*/
|
||||||
|
public static boolean isSameWeek(final Date date1, final Date date2, boolean isMon) {
|
||||||
|
if (date1 == null || date2 == null) {
|
||||||
|
throw new IllegalArgumentException("The date must not be null");
|
||||||
|
}
|
||||||
|
return CalendarUtil.isSameWeek(calendar(date1), calendar(date2), isMon);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 比较两个日期是否为同一月
|
* 比较两个日期是否为同一月
|
||||||
*
|
*
|
||||||
@@ -1870,6 +1889,44 @@ public class DateUtil extends CalendarUtil {
|
|||||||
return new DateRange(start, end, unit);
|
return new DateRange(start, end, unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按日期范围遍历,执行 function
|
||||||
|
*
|
||||||
|
* @param start 起始日期时间(包括)
|
||||||
|
* @param end 结束日期时间
|
||||||
|
* @param unit 步进单位
|
||||||
|
* @param func 每次遍历要执行的 function
|
||||||
|
* @param <T> Date经过函数处理结果类型
|
||||||
|
* @return 结果列表
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
public static <T> List<T> rangeFunc(Date start, Date end, final DateField unit, Function<Date, T> func) {
|
||||||
|
if (start == null || end == null || start.after(end)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
ArrayList<T> list = new ArrayList<>();
|
||||||
|
for(DateTime date : range(start, end, unit)){
|
||||||
|
list.add(func.apply(date));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按日期范围遍历,执行 consumer
|
||||||
|
*
|
||||||
|
* @param start 起始日期时间(包括)
|
||||||
|
* @param end 结束日期时间
|
||||||
|
* @param unit 步进单位
|
||||||
|
* @param consumer 每次遍历要执行的 consumer
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
public static void rangeConsume(Date start, Date end, final DateField unit, Consumer<Date> consumer) {
|
||||||
|
if (start == null || end == null || start.after(end)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
range(start, end, unit).forEach(consumer);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建日期范围生成器
|
* 创建日期范围生成器
|
||||||
*
|
*
|
||||||
@@ -1878,7 +1935,7 @@ public class DateUtil extends CalendarUtil {
|
|||||||
* @param unit 步进单位
|
* @param unit 步进单位
|
||||||
* @return {@link DateRange}
|
* @return {@link DateRange}
|
||||||
*/
|
*/
|
||||||
public static List<DateTime> rangeToList(Date start, Date end, final DateField unit) {
|
public static List<DateTime> rangeToList(Date start, Date end, DateField unit) {
|
||||||
return CollUtil.newArrayList((Iterable<DateTime>) range(start, end, unit));
|
return CollUtil.newArrayList((Iterable<DateTime>) range(start, end, unit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.time.temporal.ChronoUnit;
|
|||||||
import java.time.temporal.Temporal;
|
import java.time.temporal.Temporal;
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
import java.time.temporal.TemporalUnit;
|
import java.time.temporal.TemporalUnit;
|
||||||
|
import java.time.temporal.WeekFields;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
@@ -562,4 +563,21 @@ public class LocalDateTimeUtil {
|
|||||||
return startTime.isAfter(realEndTime) || endTime.isBefore(realStartTime);
|
return startTime.isAfter(realEndTime) || endTime.isBefore(realStartTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得指定日期是所在年份的第几周,如:
|
||||||
|
* <ul>
|
||||||
|
* <li>如果一年的第一天是星期一,则第一周从第一天开始,没有零周</li>
|
||||||
|
* <li>如果一年的第二天是星期一,则第一周从第二天开始,而第一天在零周</li>
|
||||||
|
* <li>如果一年中的第4天是星期一,则第1周从第4周开始,第1至第3周在零周开始</li>
|
||||||
|
* <li>如果一年中的第5天是星期一,则第二周从第5周开始,第1至第4周在第1周</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param date 日期({@link LocalDate} 或者 {@link LocalDateTime}等)
|
||||||
|
* @return 所在年的第几周
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
public static int weekOfYear(TemporalAccessor date){
|
||||||
|
return TemporalAccessorUtil.get(date, WeekFields.ISO.weekOfYear());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package cn.hutool.core.date;
|
package cn.hutool.core.date;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,14 +95,27 @@ public enum Month {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取{@link Calendar}中的对应值
|
* 获取{@link Calendar}中的对应值<br>
|
||||||
|
* 此值从0开始,即0表示一月
|
||||||
*
|
*
|
||||||
* @return {@link Calendar}中的对应值
|
* @return {@link Calendar}中的对应月份值,从0开始计数
|
||||||
*/
|
*/
|
||||||
public int getValue() {
|
public int getValue() {
|
||||||
return this.value;
|
return this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取月份值,此值与{@link java.time.Month}对应<br>
|
||||||
|
* 此值从1开始,即1表示一月
|
||||||
|
*
|
||||||
|
* @return 月份值,对应{@link java.time.Month},从1开始计数
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
public int getValueBaseOne() {
|
||||||
|
Assert.isFalse(this == UNDECIMBER, "Unsupported UNDECIMBER Field");
|
||||||
|
return getValue() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取此月份最后一天的值,不支持的月份(例如UNDECIMBER)返回-1
|
* 获取此月份最后一天的值,不支持的月份(例如UNDECIMBER)返回-1
|
||||||
*
|
*
|
||||||
@@ -165,17 +180,28 @@ public enum Month {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得指定月的最后一天
|
* 获得指定月的最后一天
|
||||||
* @param month 月份,从0开始
|
*
|
||||||
|
* @param month 月份,从0开始
|
||||||
* @param isLeapYear 是否为闰年,闰年只对二月有影响
|
* @param isLeapYear 是否为闰年,闰年只对二月有影响
|
||||||
* @return 最后一天,可能为28,29,30,31
|
* @return 最后一天,可能为28,29,30,31
|
||||||
* @since 5.4.7
|
* @since 5.4.7
|
||||||
*/
|
*/
|
||||||
public static int getLastDay(int month, boolean isLeapYear){
|
public static int getLastDay(int month, boolean isLeapYear) {
|
||||||
int lastDay = DAYS_OF_MONTH[month];
|
int lastDay = DAYS_OF_MONTH[month];
|
||||||
if (isLeapYear && Calendar.FEBRUARY == month){
|
if (isLeapYear && Calendar.FEBRUARY == month) {
|
||||||
// 二月
|
// 二月
|
||||||
lastDay += 1;
|
lastDay += 1;
|
||||||
}
|
}
|
||||||
return lastDay;
|
return lastDay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换为{@link java.time.Month}
|
||||||
|
*
|
||||||
|
* @return {@link java.time.Month}
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
public java.time.Month toJdkMonth() {
|
||||||
|
return java.time.Month.of(getValueBaseOne());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class CheckedUtil {
|
|||||||
* @param expression Lambda表达式
|
* @param expression Lambda表达式
|
||||||
* @param <P> 运行时传入的参数类型
|
* @param <P> 运行时传入的参数类型
|
||||||
* @param <R> 最终返回的数据类型
|
* @param <R> 最终返回的数据类型
|
||||||
* @return cn.hutool.core.lang.func.Func
|
* @return {@link FuncRt}
|
||||||
*/
|
*/
|
||||||
public static <P, R> FuncRt<P, R> uncheck(Func<P, R> expression) {
|
public static <P, R> FuncRt<P, R> uncheck(Func<P, R> expression) {
|
||||||
return uncheck(expression, new RuntimeException());
|
return uncheck(expression, new RuntimeException());
|
||||||
@@ -63,7 +63,7 @@ public class CheckedUtil {
|
|||||||
*
|
*
|
||||||
* @param expression 运行时传入的参数类型
|
* @param expression 运行时传入的参数类型
|
||||||
* @param <R> 最终返回的数据类型
|
* @param <R> 最终返回的数据类型
|
||||||
* @return cn.hutool.core.lang.func.Func0
|
* @return {@link Func0Rt}
|
||||||
*/
|
*/
|
||||||
public static <R> Func0Rt<R> uncheck(Func0<R> expression) {
|
public static <R> Func0Rt<R> uncheck(Func0<R> expression) {
|
||||||
return uncheck(expression, new RuntimeException());
|
return uncheck(expression, new RuntimeException());
|
||||||
@@ -76,7 +76,7 @@ public class CheckedUtil {
|
|||||||
* @param expression 运行时传入的参数类型
|
* @param expression 运行时传入的参数类型
|
||||||
* @param <P> 运行时传入的参数类型
|
* @param <P> 运行时传入的参数类型
|
||||||
* @param <R> 最终返回的数据类型
|
* @param <R> 最终返回的数据类型
|
||||||
* @return cn.hutool.core.lang.func.Func1
|
* @return {@link Func1Rt}
|
||||||
*/
|
*/
|
||||||
public static <P, R> Func1Rt<P, R> uncheck(Func1<P, R> expression) {
|
public static <P, R> Func1Rt<P, R> uncheck(Func1<P, R> expression) {
|
||||||
return uncheck(expression, new RuntimeException());
|
return uncheck(expression, new RuntimeException());
|
||||||
@@ -89,7 +89,7 @@ public class CheckedUtil {
|
|||||||
*
|
*
|
||||||
* @param expression 运行时传入的参数类型
|
* @param expression 运行时传入的参数类型
|
||||||
* @param <P> 运行时传入的参数类型
|
* @param <P> 运行时传入的参数类型
|
||||||
* @return cn.hutool.core.lang.func.VoidFunc
|
* @return {@link VoidFuncRt}
|
||||||
*/
|
*/
|
||||||
public static <P> VoidFuncRt<P> uncheck(VoidFunc<P> expression) {
|
public static <P> VoidFuncRt<P> uncheck(VoidFunc<P> expression) {
|
||||||
return uncheck(expression, new RuntimeException());
|
return uncheck(expression, new RuntimeException());
|
||||||
@@ -100,7 +100,7 @@ public class CheckedUtil {
|
|||||||
* 如此一来,代码中就不用显示的try-catch转化成运行时异常
|
* 如此一来,代码中就不用显示的try-catch转化成运行时异常
|
||||||
*
|
*
|
||||||
* @param expression 运行时传入的参数类型
|
* @param expression 运行时传入的参数类型
|
||||||
* @return cn.hutool.core.lang.func.VoidFunc0
|
* @return {@link VoidFunc0Rt}
|
||||||
*/
|
*/
|
||||||
public static VoidFunc0Rt uncheck(VoidFunc0 expression) {
|
public static VoidFunc0Rt uncheck(VoidFunc0 expression) {
|
||||||
return uncheck(expression, new RuntimeException());
|
return uncheck(expression, new RuntimeException());
|
||||||
@@ -112,7 +112,7 @@ public class CheckedUtil {
|
|||||||
*
|
*
|
||||||
* @param expression 运行时传入的参数类型
|
* @param expression 运行时传入的参数类型
|
||||||
* @param <P> 运行时传入的参数类型
|
* @param <P> 运行时传入的参数类型
|
||||||
* @return cn.hutool.core.lang.func.VoidFunc1
|
* @return {@link VoidFunc1Rt}
|
||||||
*/
|
*/
|
||||||
public static <P> VoidFunc1Rt<P> uncheck(VoidFunc1<P> expression) {
|
public static <P> VoidFunc1Rt<P> uncheck(VoidFunc1<P> expression) {
|
||||||
return uncheck(expression, new RuntimeException());
|
return uncheck(expression, new RuntimeException());
|
||||||
@@ -127,7 +127,7 @@ public class CheckedUtil {
|
|||||||
* @param rte 期望抛出的运行时异常
|
* @param rte 期望抛出的运行时异常
|
||||||
* @param <P> 运行时传入的参数类型
|
* @param <P> 运行时传入的参数类型
|
||||||
* @param <R> 最终返回的数据类型
|
* @param <R> 最终返回的数据类型
|
||||||
* @return cn.hutool.core.lang.func.Func
|
* @return {@link FuncRt}
|
||||||
*/
|
*/
|
||||||
public static <P, R> FuncRt<P, R> uncheck(Func<P, R> expression, RuntimeException rte) {
|
public static <P, R> FuncRt<P, R> uncheck(Func<P, R> expression, RuntimeException rte) {
|
||||||
Objects.requireNonNull(expression, "expression can not be null");
|
Objects.requireNonNull(expression, "expression can not be null");
|
||||||
@@ -152,7 +152,7 @@ public class CheckedUtil {
|
|||||||
* @param expression Lambda表达式
|
* @param expression Lambda表达式
|
||||||
* @param rte 期望抛出的运行时异常
|
* @param rte 期望抛出的运行时异常
|
||||||
* @param <R> 最终返回的数据类型
|
* @param <R> 最终返回的数据类型
|
||||||
* @return cn.hutool.core.lang.func.Func0
|
* @return {@link Func0Rt}
|
||||||
*/
|
*/
|
||||||
public static <R> Func0Rt<R> uncheck(Func0<R> expression, RuntimeException rte) {
|
public static <R> Func0Rt<R> uncheck(Func0<R> expression, RuntimeException rte) {
|
||||||
Objects.requireNonNull(expression, "expression can not be null");
|
Objects.requireNonNull(expression, "expression can not be null");
|
||||||
@@ -178,7 +178,7 @@ public class CheckedUtil {
|
|||||||
* @param rte 期望抛出的运行时异常
|
* @param rte 期望抛出的运行时异常
|
||||||
* @param <P> 运行时传入的参数类型
|
* @param <P> 运行时传入的参数类型
|
||||||
* @param <R> 最终返回的数据类型
|
* @param <R> 最终返回的数据类型
|
||||||
* @return cn.hutool.core.lang.func.Func1
|
* @return {@link Func1Rt}
|
||||||
*/
|
*/
|
||||||
public static <P, R> Func1Rt<P, R> uncheck(Func1<P, R> expression, RuntimeException rte) {
|
public static <P, R> Func1Rt<P, R> uncheck(Func1<P, R> expression, RuntimeException rte) {
|
||||||
Objects.requireNonNull(expression, "expression can not be null");
|
Objects.requireNonNull(expression, "expression can not be null");
|
||||||
@@ -203,7 +203,7 @@ public class CheckedUtil {
|
|||||||
* @param expression Lambda表达式
|
* @param expression Lambda表达式
|
||||||
* @param rte 期望抛出的运行时异常
|
* @param rte 期望抛出的运行时异常
|
||||||
* @param <P> 运行时传入的参数类型
|
* @param <P> 运行时传入的参数类型
|
||||||
* @return cn.hutool.core.lang.func.VoidFunc
|
* @return {@link VoidFuncRt}
|
||||||
*/
|
*/
|
||||||
public static <P> VoidFuncRt<P> uncheck(VoidFunc<P> expression, RuntimeException rte) {
|
public static <P> VoidFuncRt<P> uncheck(VoidFunc<P> expression, RuntimeException rte) {
|
||||||
Objects.requireNonNull(expression, "expression can not be null");
|
Objects.requireNonNull(expression, "expression can not be null");
|
||||||
@@ -228,7 +228,7 @@ public class CheckedUtil {
|
|||||||
*
|
*
|
||||||
* @param expression Lambda表达式
|
* @param expression Lambda表达式
|
||||||
* @param rte 期望抛出的运行时异常
|
* @param rte 期望抛出的运行时异常
|
||||||
* @return cn.hutool.core.lang.func.VoidFunc0
|
* @return {@link VoidFunc0Rt}
|
||||||
*/
|
*/
|
||||||
public static VoidFunc0Rt uncheck(VoidFunc0 expression, RuntimeException rte) {
|
public static VoidFunc0Rt uncheck(VoidFunc0 expression, RuntimeException rte) {
|
||||||
Objects.requireNonNull(expression, "expression can not be null");
|
Objects.requireNonNull(expression, "expression can not be null");
|
||||||
@@ -254,7 +254,7 @@ public class CheckedUtil {
|
|||||||
* @param expression Lambda表达式
|
* @param expression Lambda表达式
|
||||||
* @param rte 期望抛出的运行时异常
|
* @param rte 期望抛出的运行时异常
|
||||||
* @param <P> 运行时传入的参数类型
|
* @param <P> 运行时传入的参数类型
|
||||||
* @return cn.hutool.core.lang.func.VoidFunc1
|
* @return {@link VoidFunc1Rt}
|
||||||
*/
|
*/
|
||||||
public static <P> VoidFunc1Rt<P> uncheck(VoidFunc1<P> expression, RuntimeException rte) {
|
public static <P> VoidFunc1Rt<P> uncheck(VoidFunc1<P> expression, RuntimeException rte) {
|
||||||
Objects.requireNonNull(expression, "expression can not be null");
|
Objects.requireNonNull(expression, "expression can not be null");
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import cn.hutool.core.io.file.Tailer;
|
|||||||
import cn.hutool.core.io.resource.ResourceUtil;
|
import cn.hutool.core.io.resource.ResourceUtil;
|
||||||
import cn.hutool.core.io.unit.DataSizeUtil;
|
import cn.hutool.core.io.unit.DataSizeUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.thread.ThreadUtil;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.CharUtil;
|
import cn.hutool.core.util.CharUtil;
|
||||||
import cn.hutool.core.util.CharsetUtil;
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
@@ -526,24 +527,39 @@ public class FileUtil extends PathUtil {
|
|||||||
/**
|
/**
|
||||||
* 计算目录或文件的总大小<br>
|
* 计算目录或文件的总大小<br>
|
||||||
* 当给定对象为文件时,直接调用 {@link File#length()}<br>
|
* 当给定对象为文件时,直接调用 {@link File#length()}<br>
|
||||||
* 当给定对象为目录时,遍历目录下的所有文件和目录,递归计算其大小,求和返回
|
* 当给定对象为目录时,遍历目录下的所有文件和目录,递归计算其大小,求和返回<br>
|
||||||
|
* 此方法不包括目录本身的占用空间大小。
|
||||||
*
|
*
|
||||||
* @param file 目录或文件,null或者文件不存在返回0
|
* @param file 目录或文件,null或者文件不存在返回0
|
||||||
* @return 总大小,bytes长度
|
* @return 总大小,bytes长度
|
||||||
*/
|
*/
|
||||||
public static long size(File file) {
|
public static long size(File file) {
|
||||||
|
return size(file, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算目录或文件的总大小<br>
|
||||||
|
* 当给定对象为文件时,直接调用 {@link File#length()}<br>
|
||||||
|
* 当给定对象为目录时,遍历目录下的所有文件和目录,递归计算其大小,求和返回
|
||||||
|
*
|
||||||
|
* @param file 目录或文件,null或者文件不存在返回0
|
||||||
|
* @param includeDirSize 是否包括每层目录本身的大小
|
||||||
|
* @return 总大小,bytes长度
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
public static long size(File file, boolean includeDirSize) {
|
||||||
if (null == file || false == file.exists() || isSymlink(file)) {
|
if (null == file || false == file.exists() || isSymlink(file)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.isDirectory()) {
|
if (file.isDirectory()) {
|
||||||
long size = 0L;
|
long size = includeDirSize ? file.length() : 0;
|
||||||
File[] subFiles = file.listFiles();
|
File[] subFiles = file.listFiles();
|
||||||
if (ArrayUtil.isEmpty(subFiles)) {
|
if (ArrayUtil.isEmpty(subFiles)) {
|
||||||
return 0L;// empty directory
|
return 0L;// empty directory
|
||||||
}
|
}
|
||||||
for (File subFile : subFiles) {
|
for (File subFile : subFiles) {
|
||||||
size += size(subFile);
|
size += size(subFile, includeDirSize);
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
} else {
|
} else {
|
||||||
@@ -811,7 +827,7 @@ public class FileUtil extends PathUtil {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建文件夹,会递归自动创建其不存在的父文件夹,如果存在直接返回此文件夹<br>
|
* 创建文件夹,会递归自动创建其不存在的父文件夹,如果存在直接返回此文件夹<br>
|
||||||
* 此方法不对File对象类型做判断,如果File不存在,无法判断其类型
|
* 此方法不对File对象类型做判断,如果File不存在,无法判断其类型<br>
|
||||||
*
|
*
|
||||||
* @param dir 目录
|
* @param dir 目录
|
||||||
* @return 创建的目录
|
* @return 创建的目录
|
||||||
@@ -821,12 +837,48 @@ public class FileUtil extends PathUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (false == dir.exists()) {
|
if (false == dir.exists()) {
|
||||||
//noinspection ResultOfMethodCallIgnored
|
mkdirsSafely(dir, 5, 1);
|
||||||
dir.mkdirs();
|
|
||||||
}
|
}
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全地级联创建目录 (确保并发环境下能创建成功)
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* 并发环境下,假设 test 目录不存在,如果线程A mkdirs "test/A" 目录,线程B mkdirs "test/B"目录,
|
||||||
|
* 其中一个线程可能会失败,进而导致以下代码抛出 FileNotFoundException 异常
|
||||||
|
*
|
||||||
|
* file.getParentFile().mkdirs(); // 父目录正在被另一个线程创建中,返回 false
|
||||||
|
* file.createNewFile(); // 抛出 IO 异常,因为该线程无法感知到父目录已被创建
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param dir 待创建的目录
|
||||||
|
* @param tryCount 最大尝试次数
|
||||||
|
* @param sleepMillis 线程等待的毫秒数
|
||||||
|
* @return true表示创建成功,false表示创建失败
|
||||||
|
* @since 5.7.21
|
||||||
|
* @author z8g
|
||||||
|
*/
|
||||||
|
public static boolean mkdirsSafely(File dir, int tryCount, long sleepMillis) {
|
||||||
|
if (dir == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (dir.isDirectory()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (int i = 1; i <= tryCount; i++) { // 高并发场景下,可以看到 i 处于 1 ~ 3 之间
|
||||||
|
// 如果文件已存在,也会返回 false,所以该值不能作为是否能创建的依据,因此不对其进行处理
|
||||||
|
//noinspection ResultOfMethodCallIgnored
|
||||||
|
dir.mkdirs();
|
||||||
|
if (dir.exists()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ThreadUtil.sleep(sleepMillis);
|
||||||
|
}
|
||||||
|
return dir.exists();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建临时文件<br>
|
* 创建临时文件<br>
|
||||||
* 创建后的文件名为 prefix[Randon].tmp
|
* 创建后的文件名为 prefix[Randon].tmp
|
||||||
|
|||||||
@@ -87,12 +87,49 @@ public class NioUtil {
|
|||||||
Assert.notNull(outChannel, "Out channel is null!");
|
Assert.notNull(outChannel, "Out channel is null!");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return inChannel.transferTo(0, inChannel.size(), outChannel);
|
return copySafely(inChannel, outChannel);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IORuntimeException(e);
|
throw new IORuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件拷贝实现
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* FileChannel#transferTo 或 FileChannel#transferFrom 的实现是平台相关的,需要确保低版本平台的兼容性
|
||||||
|
* 例如 android 7以下平台在使用 ZipInputStream 解压文件的过程中,
|
||||||
|
* 通过 FileChannel#transferFrom 传输到文件时,其返回值可能小于 totalBytes,不处理将导致文件内容缺失
|
||||||
|
*
|
||||||
|
* // 错误写法,dstChannel.transferFrom 返回值小于 zipEntry.getSize(),导致解压后文件内容缺失
|
||||||
|
* try (InputStream srcStream = zipFile.getInputStream(zipEntry);
|
||||||
|
* ReadableByteChannel srcChannel = Channels.newChannel(srcStream);
|
||||||
|
* FileOutputStream fos = new FileOutputStream(saveFile);
|
||||||
|
* FileChannel dstChannel = fos.getChannel()) {
|
||||||
|
* dstChannel.transferFrom(srcChannel, 0, zipEntry.getSize());
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param inChannel 输入通道
|
||||||
|
* @param outChannel 输出通道
|
||||||
|
* @return 输入通道的字节数
|
||||||
|
* @throws IOException 发生IO错误
|
||||||
|
* @link http://androidxref.com/6.0.1_r10/xref/libcore/luni/src/main/java/java/nio/FileChannelImpl.java
|
||||||
|
* @link http://androidxref.com/7.0.0_r1/xref/libcore/ojluni/src/main/java/sun/nio/ch/FileChannelImpl.java
|
||||||
|
* @link http://androidxref.com/7.0.0_r1/xref/libcore/ojluni/src/main/native/FileChannelImpl.c
|
||||||
|
* @author z8g
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
private static long copySafely(FileChannel inChannel, FileChannel outChannel) throws IOException {
|
||||||
|
final long totalBytes = inChannel.size();
|
||||||
|
for (long pos = 0, remaining = totalBytes; remaining > 0; ) { // 确保文件内容不会缺失
|
||||||
|
final long writeBytes = inChannel.transferTo(pos, remaining, outChannel); // 实际传输的字节数
|
||||||
|
pos += writeBytes;
|
||||||
|
remaining -= writeBytes;
|
||||||
|
}
|
||||||
|
return totalBytes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拷贝流,使用NIO,不会关闭channel
|
* 拷贝流,使用NIO,不会关闭channel
|
||||||
*
|
*
|
||||||
|
|||||||
32
hutool-core/src/main/java/cn/hutool/core/lang/func/Supplier1.java
Executable file
32
hutool-core/src/main/java/cn/hutool/core/lang/func/Supplier1.java
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
package cn.hutool.core.lang.func;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1参数Supplier
|
||||||
|
*
|
||||||
|
* @param <T> 目标 类型
|
||||||
|
* @param <P1> 参数一 类型
|
||||||
|
* @author TomXin
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Supplier1<T, P1> {
|
||||||
|
/**
|
||||||
|
* 生成实例的方法
|
||||||
|
*
|
||||||
|
* @param p1 参数一
|
||||||
|
* @return 目标对象
|
||||||
|
*/
|
||||||
|
T get(P1 p1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将带有参数的Supplier转换为无参{@link Supplier}
|
||||||
|
*
|
||||||
|
* @param p1 参数1
|
||||||
|
* @return {@link Supplier}
|
||||||
|
*/
|
||||||
|
default Supplier<T> toSupplier(P1 p1) {
|
||||||
|
return () -> get(p1);
|
||||||
|
}
|
||||||
|
}
|
||||||
36
hutool-core/src/main/java/cn/hutool/core/lang/func/Supplier2.java
Executable file
36
hutool-core/src/main/java/cn/hutool/core/lang/func/Supplier2.java
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
package cn.hutool.core.lang.func;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 两个参数的Supplier
|
||||||
|
*
|
||||||
|
* @param <T> 目标 类型
|
||||||
|
* @param <P1> 参数一 类型
|
||||||
|
* @param <P2> 参数二 类型
|
||||||
|
* @author TomXin
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Supplier2<T, P1, P2> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成实例的方法
|
||||||
|
*
|
||||||
|
* @param p1 参数一
|
||||||
|
* @param p2 参数二
|
||||||
|
* @return 目标对象
|
||||||
|
*/
|
||||||
|
T get(P1 p1, P2 p2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将带有参数的Supplier转换为无参{@link Supplier}
|
||||||
|
*
|
||||||
|
* @param p1 参数1
|
||||||
|
* @param p2 参数2
|
||||||
|
* @return {@link Supplier}
|
||||||
|
*/
|
||||||
|
default Supplier<T> toSupplier(P1 p1, P2 p2) {
|
||||||
|
return () -> get(p1, p2);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
hutool-core/src/main/java/cn/hutool/core/lang/func/Supplier3.java
Executable file
39
hutool-core/src/main/java/cn/hutool/core/lang/func/Supplier3.java
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
package cn.hutool.core.lang.func;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 3参数Supplier
|
||||||
|
*
|
||||||
|
* @param <T> 目标类型
|
||||||
|
* @param <P1> 参数一类型
|
||||||
|
* @param <P2> 参数二类型
|
||||||
|
* @param <P3> 参数三类型
|
||||||
|
* @author TomXin
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Supplier3<T, P1, P2, P3> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成实例的方法
|
||||||
|
*
|
||||||
|
* @param p1 参数一
|
||||||
|
* @param p2 参数二
|
||||||
|
* @param p3 参数三
|
||||||
|
* @return 目标对象
|
||||||
|
*/
|
||||||
|
T get(P1 p1, P2 p2, P3 p3);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将带有参数的Supplier转换为无参{@link Supplier}
|
||||||
|
*
|
||||||
|
* @param p1 参数1
|
||||||
|
* @param p2 参数2
|
||||||
|
* @param p3 参数3
|
||||||
|
* @return {@link Supplier}
|
||||||
|
*/
|
||||||
|
default Supplier<T> toSupplier(P1 p1, P2 p2, P3 p3) {
|
||||||
|
return () -> get(p1, p2, p3);
|
||||||
|
}
|
||||||
|
}
|
||||||
42
hutool-core/src/main/java/cn/hutool/core/lang/func/Supplier4.java
Executable file
42
hutool-core/src/main/java/cn/hutool/core/lang/func/Supplier4.java
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
package cn.hutool.core.lang.func;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 4参数Supplier
|
||||||
|
*
|
||||||
|
* @param <T> 目标 类型
|
||||||
|
* @param <P1> 参数一 类型
|
||||||
|
* @param <P2> 参数二 类型
|
||||||
|
* @param <P3> 参数三 类型
|
||||||
|
* @param <P4> 参数四 类型
|
||||||
|
* @author TomXin
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Supplier4<T, P1, P2, P3, P4> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成实例的方法
|
||||||
|
*
|
||||||
|
* @param p1 参数一
|
||||||
|
* @param p2 参数二
|
||||||
|
* @param p3 参数三
|
||||||
|
* @param p4 参数四
|
||||||
|
* @return 目标对象
|
||||||
|
*/
|
||||||
|
T get(P1 p1, P2 p2, P3 p3, P4 p4);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将带有参数的Supplier转换为无参{@link Supplier}
|
||||||
|
*
|
||||||
|
* @param p1 参数1
|
||||||
|
* @param p2 参数2
|
||||||
|
* @param p3 参数3
|
||||||
|
* @param p4 参数4
|
||||||
|
* @return {@link Supplier}
|
||||||
|
*/
|
||||||
|
default Supplier<T> toSupplier(P1 p1, P2 p2, P3 p3, P4 p4) {
|
||||||
|
return () -> get(p1, p2, p3, p4);
|
||||||
|
}
|
||||||
|
}
|
||||||
45
hutool-core/src/main/java/cn/hutool/core/lang/func/Supplier5.java
Executable file
45
hutool-core/src/main/java/cn/hutool/core/lang/func/Supplier5.java
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
package cn.hutool.core.lang.func;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 5参数Supplier
|
||||||
|
*
|
||||||
|
* @param <T> 目标 类型
|
||||||
|
* @param <P1> 参数一 类型
|
||||||
|
* @param <P2> 参数二 类型
|
||||||
|
* @param <P3> 参数三 类型
|
||||||
|
* @param <P4> 参数四 类型
|
||||||
|
* @param <P5> 参数五 类型
|
||||||
|
* @author TomXin
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Supplier5<T, P1, P2, P3, P4, P5> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成实例的方法
|
||||||
|
*
|
||||||
|
* @param p1 参数一
|
||||||
|
* @param p2 参数二
|
||||||
|
* @param p3 参数三
|
||||||
|
* @param p4 参数四
|
||||||
|
* @param p5 参数五
|
||||||
|
* @return 目标对象
|
||||||
|
*/
|
||||||
|
T get(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将带有参数的Supplier转换为无参{@link Supplier}
|
||||||
|
*
|
||||||
|
* @param p1 参数1
|
||||||
|
* @param p2 参数2
|
||||||
|
* @param p3 参数3
|
||||||
|
* @param p4 参数4
|
||||||
|
* @param p5 参数5
|
||||||
|
* @return {@link Supplier}
|
||||||
|
*/
|
||||||
|
default Supplier<T> toSupplier(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
|
||||||
|
return () -> get(p1, p2, p3, p4, p5);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3601,6 +3601,46 @@ public class CharSequenceUtil {
|
|||||||
return stringBuilder.toString();
|
return stringBuilder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换指定字符串的指定区间内字符为指定字符串,字符串只重复一次<br>
|
||||||
|
* 此方法使用{@link String#codePoints()}完成拆分替换
|
||||||
|
*
|
||||||
|
* @param str 字符串
|
||||||
|
* @param startInclude 开始位置(包含)
|
||||||
|
* @param endExclude 结束位置(不包含)
|
||||||
|
* @param replacedStr 被替换的字符串
|
||||||
|
* @return 替换后的字符串
|
||||||
|
* @since 3.2.1
|
||||||
|
*/
|
||||||
|
public static String replace(CharSequence str, int startInclude, int endExclude, CharSequence replacedStr) {
|
||||||
|
if (isEmpty(str)) {
|
||||||
|
return str(str);
|
||||||
|
}
|
||||||
|
final String originalStr = str(str);
|
||||||
|
int[] strCodePoints = originalStr.codePoints().toArray();
|
||||||
|
final int strLength = strCodePoints.length;
|
||||||
|
if (startInclude > strLength) {
|
||||||
|
return originalStr;
|
||||||
|
}
|
||||||
|
if (endExclude > strLength) {
|
||||||
|
endExclude = strLength;
|
||||||
|
}
|
||||||
|
if (startInclude > endExclude) {
|
||||||
|
// 如果起始位置大于结束位置,不替换
|
||||||
|
return originalStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
final StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
for (int i = 0; i < startInclude; i++) {
|
||||||
|
stringBuilder.append(new String(strCodePoints, i, 1));
|
||||||
|
}
|
||||||
|
stringBuilder.append(replacedStr);
|
||||||
|
for (int i = endExclude; i < strLength; i++) {
|
||||||
|
stringBuilder.append(new String(strCodePoints, i, 1));
|
||||||
|
}
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 替换所有正则匹配的文本,并使用自定义函数决定如何替换<br>
|
* 替换所有正则匹配的文本,并使用自定义函数决定如何替换<br>
|
||||||
* replaceFun可以通过{@link Matcher}提取出匹配到的内容的不同部分,然后经过重新处理、组装变成新的内容放回原位。
|
* replaceFun可以通过{@link Matcher}提取出匹配到的内容的不同部分,然后经过重新处理、组装变成新的内容放回原位。
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package cn.hutool.core.text.csv;
|
package cn.hutool.core.text.csv;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import cn.hutool.core.collection.ArrayIter;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
@@ -45,6 +46,10 @@ public final class CsvWriter implements Closeable, Flushable, Serializable {
|
|||||||
* 是否处于新行开始
|
* 是否处于新行开始
|
||||||
*/
|
*/
|
||||||
private boolean newline = true;
|
private boolean newline = true;
|
||||||
|
/**
|
||||||
|
* 是否首行,即CSV开始的位置,当初始化时默认为true,一旦写入内容,为false
|
||||||
|
*/
|
||||||
|
private boolean isFirstLine = true;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------- Constructor start
|
// --------------------------------------------------------------------------------------------------- Constructor start
|
||||||
|
|
||||||
@@ -183,13 +188,7 @@ public final class CsvWriter implements Closeable, Flushable, Serializable {
|
|||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
*/
|
*/
|
||||||
public CsvWriter write(String[]... lines) throws IORuntimeException {
|
public CsvWriter write(String[]... lines) throws IORuntimeException {
|
||||||
if (ArrayUtil.isNotEmpty(lines)) {
|
return write(new ArrayIter<>(lines));
|
||||||
for (final String[] values : lines) {
|
|
||||||
appendLine(values);
|
|
||||||
}
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -320,9 +319,14 @@ public final class CsvWriter implements Closeable, Flushable, Serializable {
|
|||||||
public CsvWriter writeComment(String comment) {
|
public CsvWriter writeComment(String comment) {
|
||||||
Assert.notNull(this.config.commentCharacter, "Comment is disable!");
|
Assert.notNull(this.config.commentCharacter, "Comment is disable!");
|
||||||
try {
|
try {
|
||||||
|
if(isFirstLine){
|
||||||
|
// 首行不补换行符
|
||||||
|
isFirstLine = false;
|
||||||
|
}else {
|
||||||
|
writer.write(config.lineDelimiter);
|
||||||
|
}
|
||||||
writer.write(this.config.commentCharacter);
|
writer.write(this.config.commentCharacter);
|
||||||
writer.write(comment);
|
writer.write(comment);
|
||||||
writer.write(config.lineDelimiter);
|
|
||||||
newline = true;
|
newline = true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IORuntimeException(e);
|
throw new IORuntimeException(e);
|
||||||
@@ -366,12 +370,17 @@ public final class CsvWriter implements Closeable, Flushable, Serializable {
|
|||||||
* @param fields 字段列表 ({@code null} 值会被做为空值追加)
|
* @param fields 字段列表 ({@code null} 值会被做为空值追加)
|
||||||
* @throws IOException IO异常
|
* @throws IOException IO异常
|
||||||
*/
|
*/
|
||||||
private void doAppendLine(final String... fields) throws IOException {
|
private void doAppendLine(String... fields) throws IOException {
|
||||||
if (null != fields) {
|
if (null != fields) {
|
||||||
|
if(isFirstLine){
|
||||||
|
// 首行不补换行符
|
||||||
|
isFirstLine = false;
|
||||||
|
}else {
|
||||||
|
writer.write(config.lineDelimiter);
|
||||||
|
}
|
||||||
for (String field : fields) {
|
for (String field : fields) {
|
||||||
appendField(field);
|
appendField(field);
|
||||||
}
|
}
|
||||||
writer.write(config.lineDelimiter);
|
|
||||||
newline = true;
|
newline = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package cn.hutool.core.builder;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link GenericBuilder} 单元测试类
|
||||||
|
*
|
||||||
|
* @author TomXin
|
||||||
|
*/
|
||||||
|
public class GenericBuilderTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
Box box = GenericBuilder
|
||||||
|
.of(Box::new)
|
||||||
|
.with(Box::setId, 1024L)
|
||||||
|
.with(Box::setTitle, "Hello World!")
|
||||||
|
.with(Box::setLength, 9)
|
||||||
|
.with(Box::setWidth, 8)
|
||||||
|
.with(Box::setHeight, 7)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Assert.assertEquals(1024L, box.getId().longValue());
|
||||||
|
Assert.assertEquals("Hello World!", box.getTitle());
|
||||||
|
Assert.assertEquals(9, box.getLength().intValue());
|
||||||
|
Assert.assertEquals(8, box.getWidth().intValue());
|
||||||
|
Assert.assertEquals(7, box.getHeight().intValue());
|
||||||
|
|
||||||
|
// 对象修改
|
||||||
|
Box boxModified = GenericBuilder
|
||||||
|
.of(() -> box)
|
||||||
|
.with(Box::setTitle, "Hello Friend!")
|
||||||
|
.with(Box::setLength, 3)
|
||||||
|
.with(Box::setWidth, 4)
|
||||||
|
.with(Box::setHeight, 5)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Assert.assertEquals(1024L, boxModified.getId().longValue());
|
||||||
|
Assert.assertEquals("Hello Friend!", box.getTitle());
|
||||||
|
Assert.assertEquals(3, boxModified.getLength().intValue());
|
||||||
|
Assert.assertEquals(4, boxModified.getWidth().intValue());
|
||||||
|
Assert.assertEquals(5, boxModified.getHeight().intValue());
|
||||||
|
|
||||||
|
// 多参数构造
|
||||||
|
Box box1 = GenericBuilder
|
||||||
|
.of(Box::new, 2048L, "Hello Partner!", 222, 333, 444)
|
||||||
|
.with(Box::alis)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Assert.assertEquals(2048L, box1.getId().longValue());
|
||||||
|
Assert.assertEquals("Hello Partner!", box1.getTitle());
|
||||||
|
Assert.assertEquals(222, box1.getLength().intValue());
|
||||||
|
Assert.assertEquals(333, box1.getWidth().intValue());
|
||||||
|
Assert.assertEquals(444, box1.getHeight().intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public static class Box {
|
||||||
|
private Long id;
|
||||||
|
private String title;
|
||||||
|
private Integer length;
|
||||||
|
private Integer width;
|
||||||
|
private Integer height;
|
||||||
|
private String titleAlias;
|
||||||
|
|
||||||
|
public Box() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Box(Long id, String title, Integer length, Integer width, Integer height) {
|
||||||
|
this.id = id;
|
||||||
|
this.title = title;
|
||||||
|
this.length = length;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void alis() {
|
||||||
|
if (StrUtil.isNotBlank(this.title)) {
|
||||||
|
this.titleAlias = "TomXin:\"" + title + "\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ import java.util.Map;
|
|||||||
public class ListUtilTest {
|
public class ListUtilTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void splitTest(){
|
public void splitTest() {
|
||||||
List<List<Object>> lists = ListUtil.split(null, 3);
|
List<List<Object>> lists = ListUtil.split(null, 3);
|
||||||
Assert.assertEquals(ListUtil.empty(), lists);
|
Assert.assertEquals(ListUtil.empty(), lists);
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ public class ListUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void splitAvgTest(){
|
public void splitAvgTest() {
|
||||||
List<List<Object>> lists = ListUtil.splitAvg(null, 3);
|
List<List<Object>> lists = ListUtil.splitAvg(null, 3);
|
||||||
Assert.assertEquals(ListUtil.empty(), lists);
|
Assert.assertEquals(ListUtil.empty(), lists);
|
||||||
|
|
||||||
@@ -80,13 +80,13 @@ public class ListUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void splitAvgNotZero(){
|
public void splitAvgNotZero() {
|
||||||
// limit不能小于等于0
|
// limit不能小于等于0
|
||||||
ListUtil.splitAvg(Arrays.asList(1, 2, 3, 4), 0);
|
ListUtil.splitAvg(Arrays.asList(1, 2, 3, 4), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void editTest(){
|
public void editTest() {
|
||||||
List<String> a = ListUtil.toLinkedList("1", "2", "3");
|
List<String> a = ListUtil.toLinkedList("1", "2", "3");
|
||||||
final List<String> filter = (List<String>) CollUtil.edit(a, str -> "edit" + str);
|
final List<String> filter = (List<String>) CollUtil.edit(a, str -> "edit" + str);
|
||||||
Assert.assertEquals("edit1", filter.get(0));
|
Assert.assertEquals("edit1", filter.get(0));
|
||||||
@@ -104,7 +104,7 @@ public class ListUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void pageTest(){
|
public void pageTest() {
|
||||||
List<Integer> a = ListUtil.toLinkedList(1, 2, 3,4,5);
|
List<Integer> a = ListUtil.toLinkedList(1, 2, 3,4,5);
|
||||||
|
|
||||||
PageUtil.setFirstPageNo(1);
|
PageUtil.setFirstPageNo(1);
|
||||||
@@ -167,10 +167,13 @@ public class ListUtilTest {
|
|||||||
Assert.assertArrayEquals(new int[]{}, pageListData.get(0).stream().mapToInt(Integer::valueOf).toArray());
|
Assert.assertArrayEquals(new int[]{}, pageListData.get(0).stream().mapToInt(Integer::valueOf).toArray());
|
||||||
Assert.assertArrayEquals(new int[]{3, 4}, pageListData.get(1).stream().mapToInt(Integer::valueOf).toArray());
|
Assert.assertArrayEquals(new int[]{3, 4}, pageListData.get(1).stream().mapToInt(Integer::valueOf).toArray());
|
||||||
Assert.assertArrayEquals(new int[]{5}, pageListData.get(2).stream().mapToInt(Integer::valueOf).toArray());
|
Assert.assertArrayEquals(new int[]{5}, pageListData.get(2).stream().mapToInt(Integer::valueOf).toArray());
|
||||||
|
|
||||||
|
// 恢复默认值,避免影响其他测试用例
|
||||||
|
PageUtil.setFirstPageNo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void subTest(){
|
public void subTest() {
|
||||||
final List<Integer> of = ListUtil.of(1, 2, 3, 4);
|
final List<Integer> of = ListUtil.of(1, 2, 3, 4);
|
||||||
final List<Integer> sub = ListUtil.sub(of, 2, 4);
|
final List<Integer> sub = ListUtil.sub(of, 2, 4);
|
||||||
sub.remove(0);
|
sub.remove(0);
|
||||||
@@ -181,10 +184,10 @@ public class ListUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sortByPropertyTest(){
|
public void sortByPropertyTest() {
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
class TestBean{
|
class TestBean {
|
||||||
private int order;
|
private int order;
|
||||||
private String name;
|
private String name;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
package cn.hutool.core.convert;
|
package cn.hutool.core.convert;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
|
||||||
|
|
||||||
public class DateConvertTest {
|
public class DateConvertTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -28,7 +27,7 @@ public class DateConvertTest {
|
|||||||
int dateLong = -1497600000;
|
int dateLong = -1497600000;
|
||||||
Date value = Convert.toDate(dateLong);
|
Date value = Convert.toDate(dateLong);
|
||||||
Assert.assertNotNull(value);
|
Assert.assertNotNull(value);
|
||||||
Assert.assertEquals("Mon Dec 15 00:00:00 CST 1969", value.toString());
|
Assert.assertEquals("Mon Dec 15 00:00:00 CST 1969", value.toString().replace("GMT+08:00", "CST"));
|
||||||
|
|
||||||
final java.sql.Date sqlDate = Convert.convert(java.sql.Date.class, dateLong);
|
final java.sql.Date sqlDate = Convert.convert(java.sql.Date.class, dateLong);
|
||||||
Assert.assertNotNull(sqlDate);
|
Assert.assertNotNull(sqlDate);
|
||||||
@@ -53,18 +52,18 @@ public class DateConvertTest {
|
|||||||
java.sql.Date value2 = Convert.convert(java.sql.Date.class, timeLong);
|
java.sql.Date value2 = Convert.convert(java.sql.Date.class, timeLong);
|
||||||
Assert.assertEquals(timeLong, value2.getTime());
|
Assert.assertEquals(timeLong, value2.getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void toLocalDateTimeTest() {
|
public void toLocalDateTimeTest() {
|
||||||
Date src = new Date();
|
Date src = new Date();
|
||||||
|
|
||||||
LocalDateTime ldt = Convert.toLocalDateTime(src);
|
LocalDateTime ldt = Convert.toLocalDateTime(src);
|
||||||
Assert.assertEquals(ldt, DateUtil.toLocalDateTime(src));
|
Assert.assertEquals(ldt, DateUtil.toLocalDateTime(src));
|
||||||
|
|
||||||
Timestamp ts = Timestamp.from(src.toInstant());
|
Timestamp ts = Timestamp.from(src.toInstant());
|
||||||
ldt = Convert.toLocalDateTime(ts);
|
ldt = Convert.toLocalDateTime(ts);
|
||||||
Assert.assertEquals(ldt, DateUtil.toLocalDateTime(src));
|
Assert.assertEquals(ldt, DateUtil.toLocalDateTime(src));
|
||||||
|
|
||||||
String str = "2020-12-12 12:12:12.0";
|
String str = "2020-12-12 12:12:12.0";
|
||||||
ldt = Convert.toLocalDateTime(str);
|
ldt = Convert.toLocalDateTime(str);
|
||||||
Assert.assertEquals(ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S")), str);
|
Assert.assertEquals(ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S")), str);
|
||||||
|
|||||||
@@ -692,8 +692,11 @@ public class DateUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void parseCSTTest() {
|
public void parseCSTTest() {
|
||||||
String dateStr = "Wed Sep 16 11:26:23 CST 2009";
|
String dateStr = "Wed Sep 16 11:26:23 CST 2009";
|
||||||
|
Console.log(TimeZone.getDefault().getDisplayName());
|
||||||
|
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat(DatePattern.JDK_DATETIME_PATTERN, Locale.US);
|
SimpleDateFormat sdf = new SimpleDateFormat(DatePattern.JDK_DATETIME_PATTERN, Locale.US);
|
||||||
|
// Asia/Shanghai是以地区命名的地区标准时,在中国叫CST,因此如果解析CST时不使用"Asia/Shanghai"而使用"GMT+08:00",会导致相差一个小时
|
||||||
|
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
|
||||||
final DateTime parse = DateUtil.parse(dateStr, sdf);
|
final DateTime parse = DateUtil.parse(dateStr, sdf);
|
||||||
|
|
||||||
DateTime dateTime = DateUtil.parseCST(dateStr);
|
DateTime dateTime = DateUtil.parseCST(dateStr);
|
||||||
@@ -1004,4 +1007,17 @@ public class DateUtilTest {
|
|||||||
final DateTime parse = DateUtil.parse("2021-12-01", DatePattern.NORM_DATE_FORMATTER);
|
final DateTime parse = DateUtil.parse("2021-12-01", DatePattern.NORM_DATE_FORMATTER);
|
||||||
Assert.assertEquals("2021-12-01 00:00:00", parse.toString());
|
Assert.assertEquals("2021-12-01 00:00:00", parse.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isSameWeekTest() {
|
||||||
|
// 周六与周日比较
|
||||||
|
final boolean isSameWeek = DateUtil.isSameWeek(DateTime.of("2022-01-01", "yyyy-MM-dd"), DateTime.of("2022-01-02", "yyyy-MM-dd"), true);
|
||||||
|
Assert.assertTrue(isSameWeek);
|
||||||
|
// 周日与周一比较
|
||||||
|
final boolean isSameWeek1 = DateUtil.isSameWeek(DateTime.of("2022-01-02", "yyyy-MM-dd"), DateTime.of("2022-01-03", "yyyy-MM-dd"), false);
|
||||||
|
Assert.assertTrue(isSameWeek1);
|
||||||
|
// 跨月比较
|
||||||
|
final boolean isSameWeek2 = DateUtil.isSameWeek(DateTime.of("2021-12-29", "yyyy-MM-dd"), DateTime.of("2022-01-01", "yyyy-MM-dd"), true);
|
||||||
|
Assert.assertTrue(isSameWeek2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,4 +197,24 @@ public class LocalDateTimeUtilTest {
|
|||||||
Assert.assertTrue(LocalDateTimeUtil.isOverlap(oneStartTime2,oneEndTime2,realStartTime,realEndTime));
|
Assert.assertTrue(LocalDateTimeUtil.isOverlap(oneStartTime2,oneEndTime2,realStartTime,realEndTime));
|
||||||
Assert.assertFalse(LocalDateTimeUtil.isOverlap(oneStartTime3,oneEndTime3,realStartTime,realEndTime));
|
Assert.assertFalse(LocalDateTimeUtil.isOverlap(oneStartTime3,oneEndTime3,realStartTime,realEndTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void weekOfYearTest(){
|
||||||
|
LocalDate date1 = LocalDate.of(2021, 12, 31);
|
||||||
|
final int weekOfYear1 = LocalDateTimeUtil.weekOfYear(date1);
|
||||||
|
Assert.assertEquals(52, weekOfYear1);
|
||||||
|
|
||||||
|
final int weekOfYear2 = LocalDateTimeUtil.weekOfYear(date1.atStartOfDay());
|
||||||
|
Assert.assertEquals(52, weekOfYear2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void weekOfYearTest2(){
|
||||||
|
LocalDate date1 = LocalDate.of(2022, 1, 31);
|
||||||
|
final int weekOfYear1 = LocalDateTimeUtil.weekOfYear(date1);
|
||||||
|
Assert.assertEquals(5, weekOfYear1);
|
||||||
|
|
||||||
|
final int weekOfYear2 = LocalDateTimeUtil.weekOfYear(date1.atStartOfDay());
|
||||||
|
Assert.assertEquals(5, weekOfYear2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,4 +37,15 @@ public class MonthTest {
|
|||||||
lastDay = Month.of(Calendar.DECEMBER).getLastDay(true);
|
lastDay = Month.of(Calendar.DECEMBER).getLastDay(true);
|
||||||
Assert.assertEquals(31, lastDay);
|
Assert.assertEquals(31, lastDay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toJdkMonthTest(){
|
||||||
|
final java.time.Month month = Month.AUGUST.toJdkMonth();
|
||||||
|
Assert.assertEquals(java.time.Month.AUGUST, month);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void toJdkMonthTest2(){
|
||||||
|
Month.UNDECIMBER.toJdkMonth();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,11 +21,8 @@ public class CheckedUtilTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sleepTest() {
|
public void sleepTest() {
|
||||||
|
|
||||||
VoidFunc0 func = () -> Thread.sleep(1000L);
|
VoidFunc0 func = () -> Thread.sleep(1000L);
|
||||||
func.callWithRuntimeException();
|
func.callWithRuntimeException();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -39,7 +36,6 @@ public class CheckedUtilTest {
|
|||||||
} catch (Exception re) {
|
} catch (Exception re) {
|
||||||
Assert.assertTrue(re instanceof RuntimeException);
|
Assert.assertTrue(re instanceof RuntimeException);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
|||||||
@@ -36,6 +36,32 @@ public class RangeTest {
|
|||||||
Assert.assertFalse(range.hasNext());
|
Assert.assertFalse(range.hasNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dateRangeFuncTest() {
|
||||||
|
DateTime start = DateUtil.parse("2021-01-01");
|
||||||
|
DateTime end = DateUtil.parse("2021-01-03");
|
||||||
|
|
||||||
|
List<Integer> dayOfMonthList = DateUtil.rangeFunc(start, end, DateField.DAY_OF_YEAR, a -> DateTime.of(a).dayOfMonth());
|
||||||
|
Assert.assertArrayEquals(dayOfMonthList.toArray(new Integer[]{}), new Integer[]{1, 2, 3});
|
||||||
|
|
||||||
|
List<Integer> dayOfMonthList2 = DateUtil.rangeFunc(null, null, DateField.DAY_OF_YEAR, a -> DateTime.of(a).dayOfMonth());
|
||||||
|
Assert.assertArrayEquals(dayOfMonthList2.toArray(new Integer[]{}), new Integer[]{});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dateRangeConsumeTest() {
|
||||||
|
DateTime start = DateUtil.parse("2021-01-01");
|
||||||
|
DateTime end = DateUtil.parse("2021-01-03");
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
DateUtil.rangeConsume(start, end, DateField.DAY_OF_YEAR, a -> sb.append(DateTime.of(a).dayOfMonth()).append("#"));
|
||||||
|
Assert.assertEquals(sb.toString(), "1#2#3#");
|
||||||
|
|
||||||
|
StringBuilder sb2 = new StringBuilder();
|
||||||
|
DateUtil.rangeConsume(null, null, DateField.DAY_OF_YEAR, a -> sb.append(DateTime.of(a).dayOfMonth()).append("#"));
|
||||||
|
Assert.assertEquals(sb2.toString(), "");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void dateRangeTest2() {
|
public void dateRangeTest2() {
|
||||||
DateTime start = DateUtil.parse("2021-01-31");
|
DateTime start = DateUtil.parse("2021-01-31");
|
||||||
|
|||||||
@@ -22,6 +22,13 @@ public class CharSequenceUtilTest {
|
|||||||
Assert.assertEquals(replace, result);
|
Assert.assertEquals(replace, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void replaceByStrTest(){
|
||||||
|
String replace = "SSM15930297701BeryAllen";
|
||||||
|
String result = CharSequenceUtil.replace(replace, 5, 12, "***");
|
||||||
|
Assert.assertEquals("SSM15***01BeryAllen", result);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void addPrefixIfNotTest(){
|
public void addPrefixIfNotTest(){
|
||||||
String str = "hutool";
|
String str = "hutool";
|
||||||
|
|||||||
@@ -12,4 +12,10 @@ public class NamingCaseTest {
|
|||||||
.set("customerNickV2", "customer_nick_v2")
|
.set("customerNickV2", "customer_nick_v2")
|
||||||
.forEach((key, value) -> Assert.assertEquals(value, NamingCase.toUnderlineCase(key)));
|
.forEach((key, value) -> Assert.assertEquals(value, NamingCase.toUnderlineCase(key)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toUnderLineCaseTest2(){
|
||||||
|
final String wPRunOZTime = NamingCase.toUnderlineCase("wPRunOZTime");
|
||||||
|
Assert.assertEquals("w_P_run_OZ_time", wPRunOZTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ public class CsvWriterTest {
|
|||||||
CharsetUtil.CHARSET_GBK, false, csvWriteConfig);
|
CharsetUtil.CHARSET_GBK, false, csvWriteConfig);
|
||||||
|
|
||||||
writer.writeHeaderLine("name", "gender", "address");
|
writer.writeHeaderLine("name", "gender", "address");
|
||||||
|
writer.writeLine("张三", "男", "XX市XX区");
|
||||||
|
writer.writeLine("李四", "男", "XX市XX区,01号");
|
||||||
writer.close();
|
writer.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,32 +5,31 @@ import org.junit.Test;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页单元测试
|
* 分页单元测试
|
||||||
* @author Looly
|
|
||||||
*
|
*
|
||||||
|
* @author Looly
|
||||||
*/
|
*/
|
||||||
public class PageUtilTest {
|
public class PageUtilTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transToStartEndTest(){
|
public void transToStartEndTest() {
|
||||||
PageUtil.setFirstPageNo(0);
|
|
||||||
int[] startEnd1 = PageUtil.transToStartEnd(0, 10);
|
int[] startEnd1 = PageUtil.transToStartEnd(0, 10);
|
||||||
Assert.assertEquals(0, startEnd1[0]);
|
Assert.assertEquals(0, startEnd1[0]);
|
||||||
Assert.assertEquals(10, startEnd1[1]);
|
Assert.assertEquals(10, startEnd1[1]);
|
||||||
|
|
||||||
int[] startEnd2 = PageUtil.transToStartEnd(1, 10);
|
int[] startEnd2 = PageUtil.transToStartEnd(1, 10);
|
||||||
Assert.assertEquals(10, startEnd2[0]);
|
Assert.assertEquals(10, startEnd2[0]);
|
||||||
Assert.assertEquals(20, startEnd2[1]);
|
Assert.assertEquals(20, startEnd2[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void totalPage(){
|
public void totalPage() {
|
||||||
int totalPage = PageUtil.totalPage(20, 3);
|
int totalPage = PageUtil.totalPage(20, 3);
|
||||||
Assert.assertEquals(7, totalPage);
|
Assert.assertEquals(7, totalPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void rainbowTest() {
|
public void rainbowTest() {
|
||||||
int[] rainbow = PageUtil.rainbow(5, 20, 6);
|
int[] rainbow = PageUtil.rainbow(5, 20, 6);
|
||||||
Assert.assertArrayEquals(new int[] {3, 4, 5, 6, 7, 8}, rainbow);
|
Assert.assertArrayEquals(new int[]{3, 4, 5, 6, 7, 8}, rainbow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<sqlite.version>3.36.0.3</sqlite.version>
|
<sqlite.version>3.36.0.3</sqlite.version>
|
||||||
<!-- 此处固定2.5.x,支持到JDK8 -->
|
<!-- 此处固定2.5.x,支持到JDK8 -->
|
||||||
<hsqldb.version>2.5.2</hsqldb.version>
|
<hsqldb.version>2.5.2</hsqldb.version>
|
||||||
<jedis.version>4.0.0</jedis.version>
|
<jedis.version>4.1.1</jedis.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.chris2018998</groupId>
|
<groupId>com.github.chris2018998</groupId>
|
||||||
<artifactId>beecp</artifactId>
|
<artifactId>beecp</artifactId>
|
||||||
<version>3.3.0</version>
|
<version>3.3.1</version>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
@@ -143,13 +143,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>mysql</groupId>
|
<groupId>mysql</groupId>
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
<version>8.0.27</version>
|
<version>8.0.28</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.postgresql</groupId>
|
<groupId>org.postgresql</groupId>
|
||||||
<artifactId>postgresql</artifactId>
|
<artifactId>postgresql</artifactId>
|
||||||
<version>42.3.1</version>
|
<version>42.3.2</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -167,13 +167,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>h2</artifactId>
|
<artifactId>h2</artifactId>
|
||||||
<version>2.0.206</version>
|
<version>2.1.210</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ru.yandex.clickhouse</groupId>
|
<groupId>ru.yandex.clickhouse</groupId>
|
||||||
<artifactId>clickhouse-jdbc</artifactId>
|
<artifactId>clickhouse-jdbc</artifactId>
|
||||||
<version>0.3.1</version>
|
<version>0.3.2</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
54
hutool-db/src/main/java/cn/hutool/db/sql/ConditionGroup.java
Normal file
54
hutool-db/src/main/java/cn/hutool/db/sql/ConditionGroup.java
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package cn.hutool.db.sql;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 条件组<br>
|
||||||
|
* 用于构建复杂where条件
|
||||||
|
*
|
||||||
|
* @author tjh
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
public class ConditionGroup extends Condition {
|
||||||
|
/**
|
||||||
|
* 条件列表
|
||||||
|
*/
|
||||||
|
private Condition[] conditions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 追加条件
|
||||||
|
*
|
||||||
|
* @param conditions 条件列表
|
||||||
|
*/
|
||||||
|
public void addConditions(Condition... conditions) {
|
||||||
|
if (null == this.conditions) {
|
||||||
|
this.conditions = conditions;
|
||||||
|
} else {
|
||||||
|
this.conditions = ArrayUtil.addAll(this.conditions, conditions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将条件组转换为条件字符串,使用括号包裹,并回填占位符对应的参数值
|
||||||
|
*
|
||||||
|
* @param paramValues 参数列表,用于回填占位符对应参数值
|
||||||
|
* @return 条件字符串
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString(List<Object> paramValues) {
|
||||||
|
if (ArrayUtil.isEmpty(conditions)) {
|
||||||
|
return StrUtil.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
final StringBuilder conditionStrBuilder = StrUtil.builder();
|
||||||
|
conditionStrBuilder.append("(");
|
||||||
|
// 将组内的条件构造为SQL,因为toString,会进行递归,处理所有的条件组
|
||||||
|
conditionStrBuilder.append(ConditionBuilder.of(this.conditions).build(paramValues));
|
||||||
|
conditionStrBuilder.append(")");
|
||||||
|
|
||||||
|
return conditionStrBuilder.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package cn.hutool.db.sql;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.ListUtil;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class ConditionGroupTest {
|
||||||
|
@Test
|
||||||
|
public void ConditionGroupToStringTest() {
|
||||||
|
Condition condition1 = new Condition("a", "A");
|
||||||
|
Condition condition2 = new Condition("b", "B");
|
||||||
|
condition2.setLinkOperator(LogicalOperator.OR);
|
||||||
|
Condition condition3 = new Condition("c", "C");
|
||||||
|
Condition condition4 = new Condition("d", "D");
|
||||||
|
|
||||||
|
ConditionGroup cg = new ConditionGroup();
|
||||||
|
cg.addConditions(condition1, condition2);
|
||||||
|
|
||||||
|
// 条件组嵌套情况
|
||||||
|
ConditionGroup cg2 = new ConditionGroup();
|
||||||
|
cg2.addConditions(cg, condition3);
|
||||||
|
|
||||||
|
final ConditionBuilder conditionBuilder = ConditionBuilder.of(cg2, condition4);
|
||||||
|
|
||||||
|
Assert.assertEquals("((a = ? OR b = ?) AND c = ?) AND d = ?", conditionBuilder.build());
|
||||||
|
Assert.assertEquals(ListUtil.of("A", "B", "C", "D"), conditionBuilder.getParamValues());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,11 +17,6 @@
|
|||||||
<description>Hutool 基于DFA的关键词查找</description>
|
<description>Hutool 基于DFA的关键词查找</description>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>cn.hutool</groupId>
|
|
||||||
<artifactId>hutool-core</artifactId>
|
|
||||||
<version>${project.parent.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.hutool</groupId>
|
<groupId>cn.hutool</groupId>
|
||||||
<artifactId>hutool-json</artifactId>
|
<artifactId>hutool-json</artifactId>
|
||||||
|
|||||||
@@ -195,11 +195,21 @@ public final class SensitiveUtil {
|
|||||||
*/
|
*/
|
||||||
public static <T> T sensitiveFilter(T bean, boolean isGreedMatch, SensitiveProcessor sensitiveProcessor) {
|
public static <T> T sensitiveFilter(T bean, boolean isGreedMatch, SensitiveProcessor sensitiveProcessor) {
|
||||||
String jsonText = JSONUtil.toJsonStr(bean);
|
String jsonText = JSONUtil.toJsonStr(bean);
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked") final Class<T> c = (Class<T>) bean.getClass();
|
||||||
final Class<T> c = (Class<T>) bean.getClass();
|
|
||||||
return JSONUtil.toBean(sensitiveFilter(jsonText, isGreedMatch, sensitiveProcessor), c);
|
return JSONUtil.toBean(sensitiveFilter(jsonText, isGreedMatch, sensitiveProcessor), c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理过滤文本中的敏感词,默认替换成*
|
||||||
|
*
|
||||||
|
* @param text 文本
|
||||||
|
* @return 敏感词过滤处理后的文本
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
public static String sensitiveFilter(String text) {
|
||||||
|
return sensitiveFilter(text, true, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理过滤文本中的敏感词,默认替换成*
|
* 处理过滤文本中的敏感词,默认替换成*
|
||||||
*
|
*
|
||||||
@@ -214,13 +224,14 @@ public final class SensitiveUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//敏感词过滤场景下,不需要密集匹配
|
//敏感词过滤场景下,不需要密集匹配
|
||||||
List<FoundWord> foundWordList = getFoundAllSensitive(text, false, isGreedMatch);
|
List<FoundWord> foundWordList = getFoundAllSensitive(text, true, isGreedMatch);
|
||||||
if (CollUtil.isEmpty(foundWordList)) {
|
if (CollUtil.isEmpty(foundWordList)) {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
sensitiveProcessor = sensitiveProcessor == null ? new SensitiveProcessor() {
|
sensitiveProcessor = sensitiveProcessor == null ? new SensitiveProcessor() {
|
||||||
} : sensitiveProcessor;
|
} : sensitiveProcessor;
|
||||||
Map<Integer, FoundWord> foundWordMap = new HashMap<>(foundWordList.size());
|
|
||||||
|
final Map<Integer, FoundWord> foundWordMap = new HashMap<>(foundWordList.size(), 1);
|
||||||
foundWordList.forEach(foundWord -> foundWordMap.put(foundWord.getStartIndex(), foundWord));
|
foundWordList.forEach(foundWord -> foundWordMap.put(foundWord.getStartIndex(), foundWord));
|
||||||
int length = text.length();
|
int length = text.length();
|
||||||
StringBuilder textStringBuilder = new StringBuilder();
|
StringBuilder textStringBuilder = new StringBuilder();
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package cn.hutool.dfa;
|
|||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import cn.hutool.core.lang.Filter;
|
import cn.hutool.core.lang.Filter;
|
||||||
import cn.hutool.core.text.StrBuilder;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -247,15 +246,15 @@ public class WordTree extends HashMap<Character, WordTree> {
|
|||||||
|
|
||||||
List<FoundWord> foundWords = new ArrayList<>();
|
List<FoundWord> foundWords = new ArrayList<>();
|
||||||
WordTree current = this;
|
WordTree current = this;
|
||||||
int length = text.length();
|
final int length = text.length();
|
||||||
final Filter<Character> charFilter = this.charFilter;
|
final Filter<Character> charFilter = this.charFilter;
|
||||||
//存放查找到的字符缓存。完整出现一个词时加到findedWords中,否则清空
|
//存放查找到的字符缓存。完整出现一个词时加到findedWords中,否则清空
|
||||||
final StrBuilder wordBuffer = StrUtil.strBuilder();
|
final StringBuilder wordBuffer = StrUtil.builder();
|
||||||
final StrBuilder keyBuffer = StrUtil.strBuilder();
|
final StringBuilder keyBuffer = StrUtil.builder();
|
||||||
char currentChar;
|
char currentChar;
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
wordBuffer.reset();
|
wordBuffer.setLength(0);
|
||||||
keyBuffer.reset();
|
keyBuffer.setLength(0);
|
||||||
for (int j = i; j < length; j++) {
|
for (int j = i; j < length; j++) {
|
||||||
currentChar = text.charAt(j);
|
currentChar = text.charAt(j);
|
||||||
// Console.log("i: {}, j: {}, currentChar: {}", i, j, currentChar);
|
// Console.log("i: {}, j: {}, currentChar: {}", i, j, currentChar);
|
||||||
@@ -284,6 +283,7 @@ public class WordTree extends HashMap<Character, WordTree> {
|
|||||||
if (false == isDensityMatch) {
|
if (false == isDensityMatch) {
|
||||||
//如果非密度匹配,跳过匹配到的词
|
//如果非密度匹配,跳过匹配到的词
|
||||||
i = j;
|
i = j;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (false == isGreedMatch) {
|
if (false == isGreedMatch) {
|
||||||
//如果懒惰匹配(非贪婪匹配)。当遇到第一个结尾标记就结束本轮匹配
|
//如果懒惰匹配(非贪婪匹配)。当遇到第一个结尾标记就结束本轮匹配
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public class DfaTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 贪婪匹配原则测试
|
* 贪婪非密集匹配原则测试
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void greedMatchTest() {
|
public void greedMatchTest() {
|
||||||
@@ -56,15 +56,15 @@ public class DfaTest {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------------------------------
|
||||||
// 情况三:匹配到最长关键词,跳过已经匹配的关键词
|
// 情况三:匹配到最长关键词,跳过已经匹配的关键词
|
||||||
// 匹配到【大】,由于到最长匹配,因此【大土豆】接着被匹配
|
// 匹配到【大】,由于非密集匹配,因此从下一个字符开始查找,匹配到【土豆】接着被匹配
|
||||||
// 由于【大土豆】被匹配,【土豆】被跳过,由于【刚出锅】被匹配,【出锅】被跳过
|
// 由于【刚出锅】被匹配,由于非密集匹配,【出锅】被跳过
|
||||||
List<String> matchAll = tree.matchAll(text, -1, false, true);
|
List<String> matchAll = tree.matchAll(text, -1, false, true);
|
||||||
Assert.assertEquals(matchAll, CollUtil.newArrayList("大", "大土^豆", "刚出锅"));
|
Assert.assertEquals(matchAll, CollUtil.newArrayList("大", "土^豆", "刚出锅"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 密集匹配原则(最短匹配)和贪婪匹配原则测试
|
* 密集匹配原则(最长匹配)和贪婪匹配原则测试
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void densityAndGreedMatchTest() {
|
public void densityAndGreedMatchTest() {
|
||||||
@@ -80,6 +80,29 @@ public class DfaTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void densityAndGreedMatchTest2(){
|
||||||
|
WordTree tree = new WordTree();
|
||||||
|
tree.addWord("赵");
|
||||||
|
tree.addWord("赵阿");
|
||||||
|
tree.addWord("赵阿三");
|
||||||
|
|
||||||
|
final List<FoundWord> result = tree.matchAllWords("赵阿三在做什么", -1, true, true);
|
||||||
|
Assert.assertEquals(3, result.size());
|
||||||
|
|
||||||
|
Assert.assertEquals("赵", result.get(0).getWord());
|
||||||
|
Assert.assertEquals(0, result.get(0).getStartIndex().intValue());
|
||||||
|
Assert.assertEquals(0, result.get(0).getEndIndex().intValue());
|
||||||
|
|
||||||
|
Assert.assertEquals("赵阿", result.get(1).getWord());
|
||||||
|
Assert.assertEquals(0, result.get(1).getStartIndex().intValue());
|
||||||
|
Assert.assertEquals(1, result.get(1).getEndIndex().intValue());
|
||||||
|
|
||||||
|
Assert.assertEquals("赵阿三", result.get(2).getWord());
|
||||||
|
Assert.assertEquals(0, result.get(2).getStartIndex().intValue());
|
||||||
|
Assert.assertEquals(2, result.get(2).getEndIndex().intValue());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 停顿词测试
|
* 停顿词测试
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package cn.hutool.dfa;
|
package cn.hutool.dfa;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.ListUtil;
|
||||||
|
import lombok.Data;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -24,25 +26,17 @@ public class SensitiveUtilTest {
|
|||||||
Assert.assertEquals(bean.getStr(), "我有一颗$****,***的");
|
Assert.assertEquals(bean.getStr(), "我有一颗$****,***的");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
public static class TestBean {
|
public static class TestBean {
|
||||||
private String str;
|
private String str;
|
||||||
private Integer num;
|
private Integer num;
|
||||||
|
|
||||||
public String getStr() {
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStr(String str) {
|
|
||||||
this.str = str;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getNum() {
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNum(Integer num) {
|
|
||||||
this.num = num;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void issue2126(){
|
||||||
|
SensitiveUtil.init(ListUtil.of("赵", "赵阿", "赵阿三"));
|
||||||
|
|
||||||
|
String result = SensitiveUtil.sensitiveFilter("赵阿三在做什么。", true, null);
|
||||||
|
Assert.assertEquals("***在做什么。", result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<rythm.version>1.4.1</rythm.version>
|
<rythm.version>1.4.1</rythm.version>
|
||||||
<freemarker.version>2.3.31</freemarker.version>
|
<freemarker.version>2.3.31</freemarker.version>
|
||||||
<enjoy.version>4.9.16</enjoy.version>
|
<enjoy.version>4.9.16</enjoy.version>
|
||||||
<thymeleaf.version>3.0.14.RELEASE</thymeleaf.version>
|
<thymeleaf.version>3.0.15.RELEASE</thymeleaf.version>
|
||||||
<mail.version>1.6.2</mail.version>
|
<mail.version>1.6.2</mail.version>
|
||||||
<jsch.version>0.1.55</jsch.version>
|
<jsch.version>0.1.55</jsch.version>
|
||||||
<sshj.version>0.32.0</sshj.version>
|
<sshj.version>0.32.0</sshj.version>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
<net.version>3.8.0</net.version>
|
<net.version>3.8.0</net.version>
|
||||||
<emoji-java.version>5.1.1</emoji-java.version>
|
<emoji-java.version>5.1.1</emoji-java.version>
|
||||||
<servlet-api.version>4.0.1</servlet-api.version>
|
<servlet-api.version>4.0.1</servlet-api.version>
|
||||||
<spring-boot.version>2.6.2</spring-boot.version>
|
<spring-boot.version>2.6.3</spring-boot.version>
|
||||||
<cglib.version>3.3.0</cglib.version>
|
<cglib.version>3.3.0</cglib.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
@@ -340,7 +340,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.houbb</groupId>
|
<groupId>com.github.houbb</groupId>
|
||||||
<artifactId>pinyin</artifactId>
|
<artifactId>pinyin</artifactId>
|
||||||
<version>0.2.2</version>
|
<version>0.3.1</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -446,7 +446,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-expression</artifactId>
|
<artifactId>spring-expression</artifactId>
|
||||||
<version>5.3.14</version>
|
<version>5.3.15</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|||||||
@@ -126,11 +126,11 @@ public class EmojiUtil {
|
|||||||
* @return 替换后的字符串
|
* @return 替换后的字符串
|
||||||
*/
|
*/
|
||||||
public static String toHtmlHex(String str) {
|
public static String toHtmlHex(String str) {
|
||||||
return EmojiParser.parseToHtmlHexadecimal(str);
|
return toHtml(str, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将字符串中的Unicode Emoji字符转换为HTML表现形式
|
* 将字符串中的Unicode Emoji字符转换为HTML表现形式(Hex方式)
|
||||||
* <p>
|
* <p>
|
||||||
* 例如:<code>👦🏿</code> 转换为 <code>&#128102;</code>
|
* 例如:<code>👦🏿</code> 转换为 <code>&#128102;</code>
|
||||||
*
|
*
|
||||||
@@ -138,7 +138,24 @@ public class EmojiUtil {
|
|||||||
* @return 替换后的字符串
|
* @return 替换后的字符串
|
||||||
*/
|
*/
|
||||||
public static String toHtml(String str) {
|
public static String toHtml(String str) {
|
||||||
return EmojiParser.parseToHtmlHexadecimal(str);
|
return toHtml(str, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字符串中的Unicode Emoji字符转换为HTML表现形式,例如:
|
||||||
|
* <pre>
|
||||||
|
* 如果为hex形式,<code>👦🏿</code> 转换为 <code>&#x1f466;</code>
|
||||||
|
* 否则,<code>👦🏿</code> 转换为 <code>&#128102;</code>
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param str 包含Emoji Unicode字符的字符串
|
||||||
|
* @param isHex 是否hex形式
|
||||||
|
* @return 替换后的字符串
|
||||||
|
* @since 5.7.21
|
||||||
|
*/
|
||||||
|
public static String toHtml(String str, boolean isHex) {
|
||||||
|
return isHex ? EmojiParser.parseToHtmlHexadecimal(str) :
|
||||||
|
EmojiParser.parseToHtmlDecimal(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -94,4 +94,6 @@ public class QrCodeUtilTest {
|
|||||||
final BufferedImage image = QrCodeUtil.generate("content111", BarcodeFormat.PDF_417, QrConfig.create());
|
final BufferedImage image = QrCodeUtil.generate("content111", BarcodeFormat.PDF_417, QrConfig.create());
|
||||||
Assert.assertNotNull(image);
|
Assert.assertNotNull(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,22 +249,20 @@ public class JSONWriter extends Writer {
|
|||||||
* 此方法输出的值不包装引号。
|
* 此方法输出的值不包装引号。
|
||||||
*
|
*
|
||||||
* @param number 数字
|
* @param number 数字
|
||||||
* @return this
|
|
||||||
*/
|
*/
|
||||||
private JSONWriter writeNumberValue(Number number) {
|
private void writeNumberValue(Number number) {
|
||||||
// since 5.6.2可配置是否去除末尾多余0,例如如果为true,5.0返回5
|
// since 5.6.2可配置是否去除末尾多余0,例如如果为true,5.0返回5
|
||||||
final boolean isStripTrailingZeros = null == config || config.isStripTrailingZeros();
|
final boolean isStripTrailingZeros = null == config || config.isStripTrailingZeros();
|
||||||
return writeRaw(NumberUtil.toStr(number, isStripTrailingZeros));
|
writeRaw(NumberUtil.toStr(number, isStripTrailingZeros));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 写出Boolean值,直接写出true或false,不适用引号包装
|
* 写出Boolean值,直接写出true或false,不适用引号包装
|
||||||
*
|
*
|
||||||
* @param value Boolean值
|
* @param value Boolean值
|
||||||
* @return this
|
|
||||||
*/
|
*/
|
||||||
private JSONWriter writeBooleanValue(Boolean value) {
|
private void writeBooleanValue(Boolean value) {
|
||||||
return writeRaw(value.toString());
|
writeRaw(value.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -273,9 +271,8 @@ public class JSONWriter extends Writer {
|
|||||||
* 如果toJSONString()返回null,调用toString()方法并使用双引号包装。
|
* 如果toJSONString()返回null,调用toString()方法并使用双引号包装。
|
||||||
*
|
*
|
||||||
* @param jsonString {@link JSONString}
|
* @param jsonString {@link JSONString}
|
||||||
* @return this
|
|
||||||
*/
|
*/
|
||||||
private JSONWriter writeJSONStringValue(JSONString jsonString) {
|
private void writeJSONStringValue(JSONString jsonString) {
|
||||||
String valueStr;
|
String valueStr;
|
||||||
try {
|
try {
|
||||||
valueStr = jsonString.toJSONString();
|
valueStr = jsonString.toJSONString();
|
||||||
@@ -287,7 +284,6 @@ public class JSONWriter extends Writer {
|
|||||||
} else {
|
} else {
|
||||||
writeStrValue(jsonString.toString());
|
writeStrValue(jsonString.toString());
|
||||||
}
|
}
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -297,30 +293,26 @@ public class JSONWriter extends Writer {
|
|||||||
* JSON字符串中不能包含控制字符和未经转义的引号和反斜杠
|
* JSON字符串中不能包含控制字符和未经转义的引号和反斜杠
|
||||||
*
|
*
|
||||||
* @param csq 字符串
|
* @param csq 字符串
|
||||||
* @return this
|
|
||||||
*/
|
*/
|
||||||
private JSONWriter writeStrValue(String csq) {
|
private void writeStrValue(String csq) {
|
||||||
try {
|
try {
|
||||||
JSONUtil.quote(csq, writer);
|
JSONUtil.quote(csq, writer);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IORuntimeException(e);
|
throw new IORuntimeException(e);
|
||||||
}
|
}
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 写出空格
|
* 写出空格
|
||||||
*
|
*
|
||||||
* @param count 空格数
|
* @param count 空格数
|
||||||
* @return this
|
|
||||||
*/
|
*/
|
||||||
private JSONWriter writeSpace(int count) {
|
private void writeSpace(int count) {
|
||||||
if (indentFactor > 0) {
|
if (indentFactor > 0) {
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
writeRaw(CharUtil.SPACE);
|
writeRaw(CharUtil.SPACE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public class Issue677Test {
|
|||||||
|
|
||||||
final String jsonStr = JSONUtil.toJsonStr(dto);
|
final String jsonStr = JSONUtil.toJsonStr(dto);
|
||||||
final AuditResultDto auditResultDto = JSONUtil.toBean(jsonStr, AuditResultDto.class);
|
final AuditResultDto auditResultDto = JSONUtil.toBean(jsonStr, AuditResultDto.class);
|
||||||
Assert.assertEquals("Mon Dec 15 00:00:00 CST 1969", auditResultDto.getDate().toString());
|
Assert.assertEquals("Mon Dec 15 00:00:00 CST 1969", auditResultDto.getDate().toString().replace("GMT+08:00", "CST"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
<log4j2.version>2.17.1</log4j2.version>
|
<log4j2.version>2.17.1</log4j2.version>
|
||||||
<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.3.Final</jboss-logging.version>
|
||||||
<logtube.version>0.43.0</logtube.version>
|
<logtube.version>0.43.0</logtube.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Hutool-log只是一个日志的通用门面,功能类似于Slf4j。<br>
|
* Hutool-log只是一个日志的通用门面,功能类似于Slf4j。<br>
|
||||||
* 根据加入ClassPath中的jar包动态检测日志实现的方式,使日志使用个更加便利灵活。
|
* 根据加入ClassPath中的jar包动态检测日志实现的方式,使日志使用更加便利灵活。
|
||||||
*
|
*
|
||||||
* @author looly
|
* @author looly
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package cn.hutool.log;
|
package cn.hutool.log;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.ofdrw</groupId>
|
<groupId>org.ofdrw</groupId>
|
||||||
<artifactId>ofdrw-full</artifactId>
|
<artifactId>ofdrw-full</artifactId>
|
||||||
<version>1.17.6</version>
|
<version>1.17.8</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.oshi</groupId>
|
<groupId>com.github.oshi</groupId>
|
||||||
<artifactId>oshi-core</artifactId>
|
<artifactId>oshi-core</artifactId>
|
||||||
<version>6.0.0</version>
|
<version>6.1.0</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package cn.hutool.system.oshi;
|
package cn.hutool.system.oshi;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.NumberUtil;
|
||||||
import oshi.hardware.CentralProcessor;
|
import oshi.hardware.CentralProcessor;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
@@ -31,7 +32,7 @@ public class CpuInfo {
|
|||||||
/**
|
/**
|
||||||
* CPU用户使用率
|
* CPU用户使用率
|
||||||
*/
|
*/
|
||||||
private double used;
|
private double user;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CPU当前等待率
|
* CPU当前等待率
|
||||||
@@ -75,16 +76,16 @@ public class CpuInfo {
|
|||||||
* @param cpuNum CPU核心数
|
* @param cpuNum CPU核心数
|
||||||
* @param toTal CPU总的使用率
|
* @param toTal CPU总的使用率
|
||||||
* @param sys CPU系统使用率
|
* @param sys CPU系统使用率
|
||||||
* @param used CPU用户使用率
|
* @param user CPU用户使用率
|
||||||
* @param wait CPU当前等待率
|
* @param wait CPU当前等待率
|
||||||
* @param free CPU当前空闲率
|
* @param free CPU当前空闲率
|
||||||
* @param cpuModel CPU型号信息
|
* @param cpuModel CPU型号信息
|
||||||
*/
|
*/
|
||||||
public CpuInfo(Integer cpuNum, double toTal, double sys, double used, double wait, double free, String cpuModel) {
|
public CpuInfo(Integer cpuNum, double toTal, double sys, double user, double wait, double free, String cpuModel) {
|
||||||
this.cpuNum = cpuNum;
|
this.cpuNum = cpuNum;
|
||||||
this.toTal = toTal;
|
this.toTal = toTal;
|
||||||
this.sys = sys;
|
this.sys = sys;
|
||||||
this.used = used;
|
this.user = user;
|
||||||
this.wait = wait;
|
this.wait = wait;
|
||||||
this.free = free;
|
this.free = free;
|
||||||
this.cpuModel = cpuModel;
|
this.cpuModel = cpuModel;
|
||||||
@@ -114,12 +115,12 @@ public class CpuInfo {
|
|||||||
this.sys = sys;
|
this.sys = sys;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getUsed() {
|
public double getUser() {
|
||||||
return used;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUsed(double used) {
|
public void setUser(double user) {
|
||||||
this.used = used;
|
this.user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getWait() {
|
public double getWait() {
|
||||||
@@ -154,16 +155,25 @@ public class CpuInfo {
|
|||||||
this.ticks = ticks;
|
this.ticks = ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户+系统的总的CPU使用率
|
||||||
|
*
|
||||||
|
* @return 总CPU使用率
|
||||||
|
*/
|
||||||
|
public double getUsed() {
|
||||||
|
return NumberUtil.sub(100, this.free);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "CpuInfo{" +
|
return "CpuInfo{" +
|
||||||
"CPU核心数=" + cpuNum +
|
"CPU核心数=" + cpuNum +
|
||||||
", CPU总的使用率=" + toTal +
|
", CPU总的使用率=" + toTal +
|
||||||
", CPU系统使用率=" + sys +
|
", CPU系统使用率=" + sys +
|
||||||
", CPU用户使用率=" + used +
|
", CPU用户使用率=" + user +
|
||||||
", CPU当前等待率=" + wait +
|
", CPU当前等待率=" + wait +
|
||||||
", CPU当前空闲率=" + free +
|
", CPU当前空闲率=" + free +
|
||||||
", CPU利用率=" + LOAD_FORMAT.format(100 - free) +
|
", CPU利用率=" + getUsed() +
|
||||||
", CPU型号信息='" + cpuModel + '\'' +
|
", CPU型号信息='" + cpuModel + '\'' +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
@@ -185,7 +195,7 @@ public class CpuInfo {
|
|||||||
final long totalCpu = ticks.totalCpu();
|
final long totalCpu = ticks.totalCpu();
|
||||||
this.toTal = totalCpu;
|
this.toTal = totalCpu;
|
||||||
this.sys = formatDouble(ticks.cSys, totalCpu);
|
this.sys = formatDouble(ticks.cSys, totalCpu);
|
||||||
this.used = formatDouble(ticks.user, totalCpu);
|
this.user = formatDouble(ticks.user, totalCpu);
|
||||||
this.wait = formatDouble(ticks.ioWait, totalCpu);
|
this.wait = formatDouble(ticks.ioWait, totalCpu);
|
||||||
this.free = formatDouble(ticks.idle, totalCpu);
|
this.free = formatDouble(ticks.idle, totalCpu);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package cn.hutool.system;
|
package cn.hutool.system;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Console;
|
||||||
import cn.hutool.system.oshi.CpuInfo;
|
import cn.hutool.system.oshi.CpuInfo;
|
||||||
import cn.hutool.system.oshi.OshiUtil;
|
import cn.hutool.system.oshi.OshiUtil;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import oshi.software.os.OSProcess;
|
import oshi.software.os.OSProcess;
|
||||||
|
|
||||||
@@ -28,4 +30,12 @@ public class OshiTest {
|
|||||||
final OSProcess currentProcess = OshiUtil.getCurrentProcess();
|
final OSProcess currentProcess = OshiUtil.getCurrentProcess();
|
||||||
Assert.assertEquals("java", currentProcess.getName());
|
Assert.assertEquals("java", currentProcess.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void getUsedTest(){
|
||||||
|
while (true){
|
||||||
|
Console.log(OshiUtil.getCpuInfo().getUsed());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user