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:
@@ -6,8 +6,8 @@ import cn.hutool.core.lang.func.Func0;
|
||||
/**
|
||||
* Bean属性缓存<br>
|
||||
* 缓存用于防止多次反射造成的性能问题
|
||||
* @author Looly
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public enum BeanDescCache {
|
||||
INSTANCE;
|
||||
@@ -16,12 +16,22 @@ public enum BeanDescCache {
|
||||
|
||||
/**
|
||||
* 获得属性名和{@link BeanDesc}Map映射
|
||||
*
|
||||
* @param beanClass Bean的类
|
||||
* @param supplier 对象不存在时创建对象的函数
|
||||
* @param supplier 对象不存在时创建对象的函数
|
||||
* @return 属性名和{@link BeanDesc}映射
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空全局的Bean属性缓存
|
||||
*
|
||||
* @since 5.7.21
|
||||
*/
|
||||
public void clear() {
|
||||
this.bdCache.clear();
|
||||
}
|
||||
}
|
||||
|
@@ -56,6 +56,16 @@ public enum BeanInfoCache {
|
||||
getCache(ignoreCase).put(beanClass, fieldNamePropertyDescriptorMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空缓存
|
||||
*
|
||||
* @since 5.7.21
|
||||
*/
|
||||
public void clear() {
|
||||
this.pdCache.clear();
|
||||
this.ignoreCasePdCache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据是否忽略字段名的大小写,返回不用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}
|
||||
* @return {@link Calendar}
|
||||
@@ -143,7 +143,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取秒级别的结束时间,即毫秒设置为999
|
||||
* 修改秒级别的结束时间,即毫秒设置为999
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @return {@link Calendar}
|
||||
@@ -154,7 +154,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某小时的开始时间
|
||||
* 修改某小时的开始时间
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @return {@link Calendar}
|
||||
@@ -164,7 +164,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某小时的结束时间
|
||||
* 修改某小时的结束时间
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @return {@link Calendar}
|
||||
@@ -174,7 +174,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某分钟的开始时间
|
||||
* 修改某分钟的开始时间
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @return {@link Calendar}
|
||||
@@ -184,7 +184,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某分钟的结束时间
|
||||
* 修改某分钟的结束时间
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @return {@link Calendar}
|
||||
@@ -194,7 +194,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某天的开始时间
|
||||
* 修改某天的开始时间
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @return {@link Calendar}
|
||||
@@ -204,7 +204,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某天的结束时间
|
||||
* 修改某天的结束时间
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @return {@link Calendar}
|
||||
@@ -214,7 +214,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取给定日期当前周的开始时间,周一定为一周的开始时间
|
||||
* 修改给定日期当前周的开始时间,周一定为一周的开始时间
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @return {@link Calendar}
|
||||
@@ -224,7 +224,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取给定日期当前周的开始时间
|
||||
* 修改给定日期当前周的开始时间
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @param isMondayAsFirstDay 是否周一做为一周的第一天(false表示周日做为第一天)
|
||||
@@ -238,7 +238,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某周的结束时间,周日定为一周的结束
|
||||
* 修改某周的结束时间,周日定为一周的结束
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @return {@link Calendar}
|
||||
@@ -248,7 +248,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某周的结束时间
|
||||
* 修改某周的结束时间
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @param isSundayAsLastDay 是否周日做为一周的最后一天(false表示周六做为最后一天)
|
||||
@@ -261,7 +261,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某月的开始时间
|
||||
* 修改某月的开始时间
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @return {@link Calendar}
|
||||
@@ -271,7 +271,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某月的结束时间
|
||||
* 修改某月的结束时间
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @return {@link Calendar}
|
||||
@@ -281,7 +281,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某季度的开始时间
|
||||
* 修改某季度的开始时间
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @return {@link Calendar}
|
||||
@@ -313,7 +313,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某年的开始时间
|
||||
* 修改某年的开始时间
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @return {@link Calendar}
|
||||
@@ -323,7 +323,7 @@ public class CalendarUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某年的结束时间
|
||||
* 修改某年的结束时间
|
||||
*
|
||||
* @param calendar 日期 {@link Calendar}
|
||||
* @return {@link Calendar}
|
||||
@@ -348,6 +348,40 @@ public class CalendarUtil {
|
||||
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;
|
||||
|
||||
/**
|
||||
* 包装java.util.Date
|
||||
* 包装{@link Date}<br>
|
||||
* 此类继承了{@link Date},并提供扩展方法,如时区等。<br>
|
||||
* 此类重写了父类的{@code toString()}方法,返回值为"yyyy-MM-dd HH:mm:ss"格式
|
||||
*
|
||||
* @author xiaoleilu
|
||||
*/
|
||||
public class DateTime extends Date {
|
||||
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
|
||||
|
||||
/**
|
||||
* 转为"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
|
||||
public String toString() {
|
||||
if(useJdkToStringStyle){
|
||||
return super.toString();
|
||||
}
|
||||
return toString(this.timeZone);
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,9 @@ import java.time.LocalDateTime;
|
||||
import java.time.Year;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -28,6 +30,8 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个日期是否为同一周
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按日期范围遍历,执行 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 步进单位
|
||||
* @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));
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,7 @@ import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.WeekFields;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
@@ -562,4 +563,21 @@ public class LocalDateTimeUtil {
|
||||
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;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
|
||||
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() {
|
||||
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
|
||||
*
|
||||
@@ -165,17 +180,28 @@ public enum Month {
|
||||
|
||||
/**
|
||||
* 获得指定月的最后一天
|
||||
* @param month 月份,从0开始
|
||||
*
|
||||
* @param month 月份,从0开始
|
||||
* @param isLeapYear 是否为闰年,闰年只对二月有影响
|
||||
* @return 最后一天,可能为28,29,30,31
|
||||
* @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];
|
||||
if (isLeapYear && Calendar.FEBRUARY == month){
|
||||
if (isLeapYear && Calendar.FEBRUARY == month) {
|
||||
// 二月
|
||||
lastDay += 1;
|
||||
}
|
||||
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 <P> 运行时传入的参数类型
|
||||
* @param <R> 最终返回的数据类型
|
||||
* @return cn.hutool.core.lang.func.Func
|
||||
* @return {@link FuncRt}
|
||||
*/
|
||||
public static <P, R> FuncRt<P, R> uncheck(Func<P, R> expression) {
|
||||
return uncheck(expression, new RuntimeException());
|
||||
@@ -63,7 +63,7 @@ public class CheckedUtil {
|
||||
*
|
||||
* @param expression 运行时传入的参数类型
|
||||
* @param <R> 最终返回的数据类型
|
||||
* @return cn.hutool.core.lang.func.Func0
|
||||
* @return {@link Func0Rt}
|
||||
*/
|
||||
public static <R> Func0Rt<R> uncheck(Func0<R> expression) {
|
||||
return uncheck(expression, new RuntimeException());
|
||||
@@ -76,7 +76,7 @@ public class CheckedUtil {
|
||||
* @param expression 运行时传入的参数类型
|
||||
* @param <P> 运行时传入的参数类型
|
||||
* @param <R> 最终返回的数据类型
|
||||
* @return cn.hutool.core.lang.func.Func1
|
||||
* @return {@link Func1Rt}
|
||||
*/
|
||||
public static <P, R> Func1Rt<P, R> uncheck(Func1<P, R> expression) {
|
||||
return uncheck(expression, new RuntimeException());
|
||||
@@ -89,7 +89,7 @@ public class CheckedUtil {
|
||||
*
|
||||
* @param expression 运行时传入的参数类型
|
||||
* @param <P> 运行时传入的参数类型
|
||||
* @return cn.hutool.core.lang.func.VoidFunc
|
||||
* @return {@link VoidFuncRt}
|
||||
*/
|
||||
public static <P> VoidFuncRt<P> uncheck(VoidFunc<P> expression) {
|
||||
return uncheck(expression, new RuntimeException());
|
||||
@@ -100,7 +100,7 @@ public class CheckedUtil {
|
||||
* 如此一来,代码中就不用显示的try-catch转化成运行时异常
|
||||
*
|
||||
* @param expression 运行时传入的参数类型
|
||||
* @return cn.hutool.core.lang.func.VoidFunc0
|
||||
* @return {@link VoidFunc0Rt}
|
||||
*/
|
||||
public static VoidFunc0Rt uncheck(VoidFunc0 expression) {
|
||||
return uncheck(expression, new RuntimeException());
|
||||
@@ -112,7 +112,7 @@ public class CheckedUtil {
|
||||
*
|
||||
* @param expression 运行时传入的参数类型
|
||||
* @param <P> 运行时传入的参数类型
|
||||
* @return cn.hutool.core.lang.func.VoidFunc1
|
||||
* @return {@link VoidFunc1Rt}
|
||||
*/
|
||||
public static <P> VoidFunc1Rt<P> uncheck(VoidFunc1<P> expression) {
|
||||
return uncheck(expression, new RuntimeException());
|
||||
@@ -127,7 +127,7 @@ public class CheckedUtil {
|
||||
* @param rte 期望抛出的运行时异常
|
||||
* @param <P> 运行时传入的参数类型
|
||||
* @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) {
|
||||
Objects.requireNonNull(expression, "expression can not be null");
|
||||
@@ -152,7 +152,7 @@ public class CheckedUtil {
|
||||
* @param expression Lambda表达式
|
||||
* @param rte 期望抛出的运行时异常
|
||||
* @param <R> 最终返回的数据类型
|
||||
* @return cn.hutool.core.lang.func.Func0
|
||||
* @return {@link Func0Rt}
|
||||
*/
|
||||
public static <R> Func0Rt<R> uncheck(Func0<R> expression, RuntimeException rte) {
|
||||
Objects.requireNonNull(expression, "expression can not be null");
|
||||
@@ -178,7 +178,7 @@ public class CheckedUtil {
|
||||
* @param rte 期望抛出的运行时异常
|
||||
* @param <P> 运行时传入的参数类型
|
||||
* @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) {
|
||||
Objects.requireNonNull(expression, "expression can not be null");
|
||||
@@ -203,7 +203,7 @@ public class CheckedUtil {
|
||||
* @param expression Lambda表达式
|
||||
* @param rte 期望抛出的运行时异常
|
||||
* @param <P> 运行时传入的参数类型
|
||||
* @return cn.hutool.core.lang.func.VoidFunc
|
||||
* @return {@link VoidFuncRt}
|
||||
*/
|
||||
public static <P> VoidFuncRt<P> uncheck(VoidFunc<P> expression, RuntimeException rte) {
|
||||
Objects.requireNonNull(expression, "expression can not be null");
|
||||
@@ -228,7 +228,7 @@ public class CheckedUtil {
|
||||
*
|
||||
* @param expression Lambda表达式
|
||||
* @param rte 期望抛出的运行时异常
|
||||
* @return cn.hutool.core.lang.func.VoidFunc0
|
||||
* @return {@link VoidFunc0Rt}
|
||||
*/
|
||||
public static VoidFunc0Rt uncheck(VoidFunc0 expression, RuntimeException rte) {
|
||||
Objects.requireNonNull(expression, "expression can not be null");
|
||||
@@ -254,7 +254,7 @@ public class CheckedUtil {
|
||||
* @param expression Lambda表达式
|
||||
* @param rte 期望抛出的运行时异常
|
||||
* @param <P> 运行时传入的参数类型
|
||||
* @return cn.hutool.core.lang.func.VoidFunc1
|
||||
* @return {@link VoidFunc1Rt}
|
||||
*/
|
||||
public static <P> VoidFunc1Rt<P> uncheck(VoidFunc1<P> expression, RuntimeException rte) {
|
||||
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.unit.DataSizeUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
@@ -526,24 +527,39 @@ public class FileUtil extends PathUtil {
|
||||
/**
|
||||
* 计算目录或文件的总大小<br>
|
||||
* 当给定对象为文件时,直接调用 {@link File#length()}<br>
|
||||
* 当给定对象为目录时,遍历目录下的所有文件和目录,递归计算其大小,求和返回
|
||||
* 当给定对象为目录时,遍历目录下的所有文件和目录,递归计算其大小,求和返回<br>
|
||||
* 此方法不包括目录本身的占用空间大小。
|
||||
*
|
||||
* @param file 目录或文件,null或者文件不存在返回0
|
||||
* @return 总大小,bytes长度
|
||||
*/
|
||||
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)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (file.isDirectory()) {
|
||||
long size = 0L;
|
||||
long size = includeDirSize ? file.length() : 0;
|
||||
File[] subFiles = file.listFiles();
|
||||
if (ArrayUtil.isEmpty(subFiles)) {
|
||||
return 0L;// empty directory
|
||||
}
|
||||
for (File subFile : subFiles) {
|
||||
size += size(subFile);
|
||||
size += size(subFile, includeDirSize);
|
||||
}
|
||||
return size;
|
||||
} else {
|
||||
@@ -811,7 +827,7 @@ public class FileUtil extends PathUtil {
|
||||
|
||||
/**
|
||||
* 创建文件夹,会递归自动创建其不存在的父文件夹,如果存在直接返回此文件夹<br>
|
||||
* 此方法不对File对象类型做判断,如果File不存在,无法判断其类型
|
||||
* 此方法不对File对象类型做判断,如果File不存在,无法判断其类型<br>
|
||||
*
|
||||
* @param dir 目录
|
||||
* @return 创建的目录
|
||||
@@ -821,12 +837,48 @@ public class FileUtil extends PathUtil {
|
||||
return null;
|
||||
}
|
||||
if (false == dir.exists()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
dir.mkdirs();
|
||||
mkdirsSafely(dir, 5, 1);
|
||||
}
|
||||
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>
|
||||
* 创建后的文件名为 prefix[Randon].tmp
|
||||
|
@@ -87,12 +87,49 @@ public class NioUtil {
|
||||
Assert.notNull(outChannel, "Out channel is null!");
|
||||
|
||||
try {
|
||||
return inChannel.transferTo(0, inChannel.size(), outChannel);
|
||||
return copySafely(inChannel, outChannel);
|
||||
} catch (IOException 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
|
||||
*
|
||||
|
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换指定字符串的指定区间内字符为指定字符串,字符串只重复一次<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>
|
||||
* replaceFun可以通过{@link Matcher}提取出匹配到的内容的不同部分,然后经过重新处理、组装变成新的内容放回原位。
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package cn.hutool.core.text.csv;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.ArrayIter;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
@@ -45,6 +46,10 @@ public final class CsvWriter implements Closeable, Flushable, Serializable {
|
||||
* 是否处于新行开始
|
||||
*/
|
||||
private boolean newline = true;
|
||||
/**
|
||||
* 是否首行,即CSV开始的位置,当初始化时默认为true,一旦写入内容,为false
|
||||
*/
|
||||
private boolean isFirstLine = true;
|
||||
|
||||
// --------------------------------------------------------------------------------------------------- Constructor start
|
||||
|
||||
@@ -183,13 +188,7 @@ public final class CsvWriter implements Closeable, Flushable, Serializable {
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public CsvWriter write(String[]... lines) throws IORuntimeException {
|
||||
if (ArrayUtil.isNotEmpty(lines)) {
|
||||
for (final String[] values : lines) {
|
||||
appendLine(values);
|
||||
}
|
||||
flush();
|
||||
}
|
||||
return this;
|
||||
return write(new ArrayIter<>(lines));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -320,9 +319,14 @@ public final class CsvWriter implements Closeable, Flushable, Serializable {
|
||||
public CsvWriter writeComment(String comment) {
|
||||
Assert.notNull(this.config.commentCharacter, "Comment is disable!");
|
||||
try {
|
||||
if(isFirstLine){
|
||||
// 首行不补换行符
|
||||
isFirstLine = false;
|
||||
}else {
|
||||
writer.write(config.lineDelimiter);
|
||||
}
|
||||
writer.write(this.config.commentCharacter);
|
||||
writer.write(comment);
|
||||
writer.write(config.lineDelimiter);
|
||||
newline = true;
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
@@ -366,12 +370,17 @@ public final class CsvWriter implements Closeable, Flushable, Serializable {
|
||||
* @param fields 字段列表 ({@code null} 值会被做为空值追加)
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
private void doAppendLine(final String... fields) throws IOException {
|
||||
private void doAppendLine(String... fields) throws IOException {
|
||||
if (null != fields) {
|
||||
if(isFirstLine){
|
||||
// 首行不补换行符
|
||||
isFirstLine = false;
|
||||
}else {
|
||||
writer.write(config.lineDelimiter);
|
||||
}
|
||||
for (String field : fields) {
|
||||
appendField(field);
|
||||
}
|
||||
writer.write(config.lineDelimiter);
|
||||
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 {
|
||||
|
||||
@Test
|
||||
public void splitTest(){
|
||||
public void splitTest() {
|
||||
List<List<Object>> lists = ListUtil.split(null, 3);
|
||||
Assert.assertEquals(ListUtil.empty(), lists);
|
||||
|
||||
@@ -60,7 +60,7 @@ public class ListUtilTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void splitAvgTest(){
|
||||
public void splitAvgTest() {
|
||||
List<List<Object>> lists = ListUtil.splitAvg(null, 3);
|
||||
Assert.assertEquals(ListUtil.empty(), lists);
|
||||
|
||||
@@ -80,13 +80,13 @@ public class ListUtilTest {
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void splitAvgNotZero(){
|
||||
public void splitAvgNotZero() {
|
||||
// limit不能小于等于0
|
||||
ListUtil.splitAvg(Arrays.asList(1, 2, 3, 4), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void editTest(){
|
||||
public void editTest() {
|
||||
List<String> a = ListUtil.toLinkedList("1", "2", "3");
|
||||
final List<String> filter = (List<String>) CollUtil.edit(a, str -> "edit" + str);
|
||||
Assert.assertEquals("edit1", filter.get(0));
|
||||
@@ -104,7 +104,7 @@ public class ListUtilTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pageTest(){
|
||||
public void pageTest() {
|
||||
List<Integer> a = ListUtil.toLinkedList(1, 2, 3,4,5);
|
||||
|
||||
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[]{3, 4}, pageListData.get(1).stream().mapToInt(Integer::valueOf).toArray());
|
||||
Assert.assertArrayEquals(new int[]{5}, pageListData.get(2).stream().mapToInt(Integer::valueOf).toArray());
|
||||
|
||||
// 恢复默认值,避免影响其他测试用例
|
||||
PageUtil.setFirstPageNo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subTest(){
|
||||
public void subTest() {
|
||||
final List<Integer> of = ListUtil.of(1, 2, 3, 4);
|
||||
final List<Integer> sub = ListUtil.sub(of, 2, 4);
|
||||
sub.remove(0);
|
||||
@@ -181,10 +184,10 @@ public class ListUtilTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sortByPropertyTest(){
|
||||
public void sortByPropertyTest() {
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
class TestBean{
|
||||
class TestBean {
|
||||
private int order;
|
||||
private String name;
|
||||
}
|
||||
|
@@ -1,15 +1,14 @@
|
||||
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.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
|
||||
public class DateConvertTest {
|
||||
|
||||
@Test
|
||||
@@ -28,7 +27,7 @@ public class DateConvertTest {
|
||||
int dateLong = -1497600000;
|
||||
Date value = Convert.toDate(dateLong);
|
||||
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);
|
||||
Assert.assertNotNull(sqlDate);
|
||||
@@ -53,18 +52,18 @@ public class DateConvertTest {
|
||||
java.sql.Date value2 = Convert.convert(java.sql.Date.class, timeLong);
|
||||
Assert.assertEquals(timeLong, value2.getTime());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void toLocalDateTimeTest() {
|
||||
Date src = new Date();
|
||||
|
||||
|
||||
LocalDateTime ldt = Convert.toLocalDateTime(src);
|
||||
Assert.assertEquals(ldt, DateUtil.toLocalDateTime(src));
|
||||
|
||||
|
||||
Timestamp ts = Timestamp.from(src.toInstant());
|
||||
ldt = Convert.toLocalDateTime(ts);
|
||||
Assert.assertEquals(ldt, DateUtil.toLocalDateTime(src));
|
||||
|
||||
|
||||
String str = "2020-12-12 12:12:12.0";
|
||||
ldt = Convert.toLocalDateTime(str);
|
||||
Assert.assertEquals(ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S")), str);
|
||||
|
@@ -692,8 +692,11 @@ public class DateUtilTest {
|
||||
@Test
|
||||
public void parseCSTTest() {
|
||||
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);
|
||||
// Asia/Shanghai是以地区命名的地区标准时,在中国叫CST,因此如果解析CST时不使用"Asia/Shanghai"而使用"GMT+08:00",会导致相差一个小时
|
||||
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
|
||||
final DateTime parse = DateUtil.parse(dateStr, sdf);
|
||||
|
||||
DateTime dateTime = DateUtil.parseCST(dateStr);
|
||||
@@ -1004,4 +1007,17 @@ public class DateUtilTest {
|
||||
final DateTime parse = DateUtil.parse("2021-12-01", DatePattern.NORM_DATE_FORMATTER);
|
||||
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.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);
|
||||
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
|
||||
public void sleepTest() {
|
||||
|
||||
VoidFunc0 func = () -> Thread.sleep(1000L);
|
||||
func.callWithRuntimeException();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +36,6 @@ public class CheckedUtilTest {
|
||||
} catch (Exception re) {
|
||||
Assert.assertTrue(re instanceof RuntimeException);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
|
@@ -36,6 +36,32 @@ public class RangeTest {
|
||||
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
|
||||
public void dateRangeTest2() {
|
||||
DateTime start = DateUtil.parse("2021-01-31");
|
||||
|
@@ -22,6 +22,13 @@ public class CharSequenceUtilTest {
|
||||
Assert.assertEquals(replace, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void replaceByStrTest(){
|
||||
String replace = "SSM15930297701BeryAllen";
|
||||
String result = CharSequenceUtil.replace(replace, 5, 12, "***");
|
||||
Assert.assertEquals("SSM15***01BeryAllen", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addPrefixIfNotTest(){
|
||||
String str = "hutool";
|
||||
|
@@ -12,4 +12,10 @@ public class NamingCaseTest {
|
||||
.set("customerNickV2", "customer_nick_v2")
|
||||
.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);
|
||||
|
||||
writer.writeHeaderLine("name", "gender", "address");
|
||||
writer.writeLine("张三", "男", "XX市XX区");
|
||||
writer.writeLine("李四", "男", "XX市XX区,01号");
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
|
@@ -5,32 +5,31 @@ import org.junit.Test;
|
||||
|
||||
/**
|
||||
* 分页单元测试
|
||||
* @author Looly
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class PageUtilTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void transToStartEndTest(){
|
||||
PageUtil.setFirstPageNo(0);
|
||||
public void transToStartEndTest() {
|
||||
int[] startEnd1 = PageUtil.transToStartEnd(0, 10);
|
||||
Assert.assertEquals(0, startEnd1[0]);
|
||||
Assert.assertEquals(10, startEnd1[1]);
|
||||
|
||||
|
||||
int[] startEnd2 = PageUtil.transToStartEnd(1, 10);
|
||||
Assert.assertEquals(10, startEnd2[0]);
|
||||
Assert.assertEquals(20, startEnd2[1]);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void totalPage(){
|
||||
public void totalPage() {
|
||||
int totalPage = PageUtil.totalPage(20, 3);
|
||||
Assert.assertEquals(7, totalPage);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void rainbowTest() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user