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

This commit is contained in:
totalo 2020-10-10 23:04:42 +08:00
commit 20d1e8984b
72 changed files with 1805 additions and 838 deletions

View File

@ -3,7 +3,7 @@
-------------------------------------------------------------------------------------------------------------
# 5.4.4 (2020-09-23)
# 5.4.4 (2020-09-28)
### 新特性
* 【core 】 ServiceLoaderUtil改为使用contextClassLoaderpr#183@Gitee
@ -19,12 +19,26 @@
* 【core 】 优化PageUtil彩虹算法issue#1110@Github
* 【core 】 IoUtil增加readUtf8方法
* 【core 】 优化全局邮箱账户初始化逻辑pr#1114@Github
* 【http 】 SoapClient增加addSOAPHeader方法
* 【http 】 完善StrUtil的注释pr#186@Gitee
* 【aop 】 去除调试日志issue#1116@Github
* 【core 】 增加'反转义pr#1121@Github
* 【poi 】 增加SheetReader和XXXRowHandlerissue#I1WHJP@Gitee
* 【dfa 】 增加过滤符号pr#1122@Github
* 【dfa 】 SensitiveUtil增加setCharFilter方法pr#1123@Github
* 【all 】 优化常量大小写规范pr#188@Gitee
* 【core 】 优化NumberUtil中针对BigDecimal的一些处理逻辑pr#1127@Github
* 【core 】 NumberUtil.factorial注释明确pr#1126@Github
* 【core 】 NumberUtil增加isPowerOfTwo方法pr#1132@Github
* 【core 】 优化BooleanUtil的校验逻辑pr#1137@Github
### Bug修复
* 【crypto 】 修复SM2验签后无法解密问题issue#I1W0VP@Gitee
* 【core 】 修复新建默认TreeSet没有默认比较器导致的问题issue#1101@Github
* 【core 】 修复Linux下使用Windows路径分隔符导致的解压错误issue#I1MW0E@Gitee
* 【core 】 修复Word07Writer写出map问题issue#I1W49R@Gitee
* 【script 】 修复函数库脚本执行问题
* 【core 】 修复RGB随机颜色的上限值不对且API重复pr#1136@Gihub
-------------------------------------------------------------------------------------------------------------

View File

@ -1,7 +1,6 @@
package cn.hutool.aop.interceptor;
import cn.hutool.aop.aspects.Aspect;
import cn.hutool.core.lang.Console;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
@ -43,7 +42,6 @@ public class CglibInterceptor implements MethodInterceptor, Serializable {
if (aspect.before(target, method, args)) {
try {
// result = proxy.invokeSuper(obj, args);
Console.log(target);
result = proxy.invoke(target, args);
} catch (InvocationTargetException e) {
// 异常回调只捕获业务代码导致的异常而非反射导致的异常

View File

@ -41,9 +41,9 @@ public class BeanPath implements Serializable{
private static final long serialVersionUID = 1L;
/** 表达式边界符号数组 */
private static final char[] expChars = { CharUtil.DOT, CharUtil.BRACKET_START, CharUtil.BRACKET_END };
private static final char[] EXP_CHARS = { CharUtil.DOT, CharUtil.BRACKET_START, CharUtil.BRACKET_END };
private boolean isStartWith$ = false;
private boolean isStartWith = false;
protected List<String> patternParts;
/**
@ -154,7 +154,7 @@ public class BeanPath implements Serializable{
subBean = getFieldValue(subBean, patternPart);
if (null == subBean) {
// 支持表达式的第一个对象为Bean本身若用户定义表达式$开头则不做此操作
if (isFirst && false == this.isStartWith$ && BeanUtil.isMatchName(bean, patternPart, true)) {
if (isFirst && false == this.isStartWith && BeanUtil.isMatchName(bean, patternPart, true)) {
subBean = bean;
isFirst = false;
} else {
@ -229,11 +229,11 @@ public class BeanPath implements Serializable{
c = expression.charAt(i);
if (0 == i && '$' == c) {
// 忽略开头的$符表示当前对象
isStartWith$ = true;
isStartWith = true;
continue;
}
if (ArrayUtil.contains(expChars, c)) {
if (ArrayUtil.contains(EXP_CHARS, c)) {
// 处理边界符号
if (CharUtil.BRACKET_END == c) {
// 中括号数字下标结束

View File

@ -17,8 +17,8 @@ public class Base32 {
private Base32() {}
private static final String base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
private static final int[] base32Lookup = {//
private static final String BASE32_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
private static final int[] BASE32_LOOKUP = {//
0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // '0', '1', '2', '3', '4', '5', '6', '7'
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // '8', '9', ':', ';', '<', '=', '>', '?'
0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G'
@ -68,7 +68,7 @@ public class Base32 {
i++;
}
}
base32.append(base32Chars.charAt(digit));
base32.append(BASE32_CHARS.charAt(digit));
}
return base32.toString();
@ -120,11 +120,11 @@ public class Base32 {
lookup = base32.charAt(i) - '0';
/* Skip chars outside the lookup table */
if (lookup < 0 || lookup >= base32Lookup.length) {
if (lookup < 0 || lookup >= BASE32_LOOKUP.length) {
continue;
}
digit = base32Lookup[lookup];
digit = BASE32_LOOKUP[lookup];
/* If this digit is not in the table, ignore it */
if (digit == 0xFF) {

View File

@ -19,7 +19,7 @@ import cn.hutool.core.util.StrUtil;
public class Base62 {
private static final Charset DEFAULT_CHARSET = CharsetUtil.CHARSET_UTF_8;
private static final Base62Codec codec = Base62Codec.createGmp();
private static final Base62Codec CODEC = Base62Codec.createGmp();
// -------------------------------------------------------------------- encode
/**
@ -50,7 +50,7 @@ public class Base62 {
* @return 被加密后的字符串
*/
public static String encode(byte[] source) {
return new String(codec.encode(source));
return new String(CODEC.encode(source));
}
/**
@ -144,6 +144,6 @@ public class Base62 {
* @return 解码后的bytes
*/
public static byte[] decode(byte[] base62bytes) {
return codec.decode(base62bytes);
return CODEC.decode(base62bytes);
}
}

View File

@ -9,7 +9,7 @@ package cn.hutool.core.codec;
public class Caesar {
// 26个字母表
public static final String table = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
public static final String TABLE = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
/**
* 传入明文加密得到密文
@ -63,8 +63,8 @@ public class Caesar {
* @return 加密后的字符
*/
private static char encodeChar(char c, int offset) {
int position = (table.indexOf(c) + offset) % 52;
return table.charAt(position);
int position = (TABLE.indexOf(c) + offset) % 52;
return TABLE.charAt(position);
}
@ -75,11 +75,11 @@ public class Caesar {
* @return 解密后的字符
*/
private static char decodeChar(char c, int offset) {
int position = (table.indexOf(c) - offset) % 52;
int position = (TABLE.indexOf(c) - offset) % 52;
if (position < 0) {
position += 52;
}
return table.charAt(position);
return TABLE.charAt(position);
}
// ----------------------------------------------------------------------------------------- Private method end
}

View File

@ -17,8 +17,8 @@ import cn.hutool.core.util.StrUtil;
*/
public class Morse {
private static final Map<Integer, String> alphabets = new HashMap<>(); // code point -> morse
private static final Map<String, Integer> dictionaries = new HashMap<>(); // morse -> code point
private static final Map<Integer, String> ALPHABETS = new HashMap<>(); // code point -> morse
private static final Map<String, Integer> DICTIONARIES = new HashMap<>(); // morse -> code point
/**
* 注册莫尔斯电码表
@ -27,8 +27,8 @@ public class Morse {
* @param dict 二进制
*/
private static void registerMorse(Character abc, String dict) {
alphabets.put(Integer.valueOf(abc), dict);
dictionaries.put(dict, Integer.valueOf(abc));
ALPHABETS.put(Integer.valueOf(abc), dict);
DICTIONARIES.put(dict, Integer.valueOf(abc));
}
static {
@ -129,7 +129,7 @@ public class Morse {
final int len = text.codePointCount(0, text.length());
for (int i = 0; i < len; i++) {
int codePoint = text.codePointAt(i);
String word = alphabets.get(codePoint);
String word = ALPHABETS.get(codePoint);
if (word == null) {
word = Integer.toBinaryString(codePoint);
}
@ -161,7 +161,7 @@ public class Morse {
continue;
}
word = word.replace(dit, '0').replace(dah, '1');
codePoint = dictionaries.get(word);
codePoint = DICTIONARIES.get(word);
if (codePoint == null) {
codePoint = Integer.valueOf(word, 2);
}

View File

@ -12,22 +12,22 @@ public enum BasicType {
BYTE, SHORT, INT, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, CHAR, CHARACTER, STRING;
/** 包装类型为Key原始类型为Value例如 Integer.class =》 int.class. */
public static final Map<Class<?>, Class<?>> wrapperPrimitiveMap = new ConcurrentHashMap<>(8);
public static final Map<Class<?>, Class<?>> WRAPPER_PRIMITIVE_MAP = new ConcurrentHashMap<>(8);
/** 原始类型为Key包装类型为Value例如 int.class =》 Integer.class. */
public static final Map<Class<?>, Class<?>> primitiveWrapperMap = new ConcurrentHashMap<>(8);
public static final Map<Class<?>, Class<?>> PRIMITIVE_WRAPPER_MAP = new ConcurrentHashMap<>(8);
static {
wrapperPrimitiveMap.put(Boolean.class, boolean.class);
wrapperPrimitiveMap.put(Byte.class, byte.class);
wrapperPrimitiveMap.put(Character.class, char.class);
wrapperPrimitiveMap.put(Double.class, double.class);
wrapperPrimitiveMap.put(Float.class, float.class);
wrapperPrimitiveMap.put(Integer.class, int.class);
wrapperPrimitiveMap.put(Long.class, long.class);
wrapperPrimitiveMap.put(Short.class, short.class);
WRAPPER_PRIMITIVE_MAP.put(Boolean.class, boolean.class);
WRAPPER_PRIMITIVE_MAP.put(Byte.class, byte.class);
WRAPPER_PRIMITIVE_MAP.put(Character.class, char.class);
WRAPPER_PRIMITIVE_MAP.put(Double.class, double.class);
WRAPPER_PRIMITIVE_MAP.put(Float.class, float.class);
WRAPPER_PRIMITIVE_MAP.put(Integer.class, int.class);
WRAPPER_PRIMITIVE_MAP.put(Long.class, long.class);
WRAPPER_PRIMITIVE_MAP.put(Short.class, short.class);
for (Map.Entry<Class<?>, Class<?>> entry : wrapperPrimitiveMap.entrySet()) {
primitiveWrapperMap.put(entry.getValue(), entry.getKey());
for (Map.Entry<Class<?>, Class<?>> entry : WRAPPER_PRIMITIVE_MAP.entrySet()) {
PRIMITIVE_WRAPPER_MAP.put(entry.getValue(), entry.getKey());
}
}
@ -40,7 +40,7 @@ public enum BasicType {
if(null == clazz || false == clazz.isPrimitive()){
return clazz;
}
Class<?> result = primitiveWrapperMap.get(clazz);
Class<?> result = PRIMITIVE_WRAPPER_MAP.get(clazz);
return (null == result) ? clazz : result;
}
@ -53,7 +53,7 @@ public enum BasicType {
if(null == clazz || clazz.isPrimitive()){
return clazz;
}
Class<?> result = wrapperPrimitiveMap.get(clazz);
Class<?> result = WRAPPER_PRIMITIVE_MAP.get(clazz);
return (null == result) ? clazz : result;
}
}

View File

@ -18,20 +18,20 @@ public class NumberChineseFormatter {
/**
* 简体中文形式
**/
private static final String[] simpleDigits = {"", "", "", "", "", "", "", "", "", ""};
private static final String[] SIMPLE_DIGITS = {"", "", "", "", "", "", "", "", "", ""};
/**
* 繁体中文形式
**/
private static final String[] traditionalDigits = {"", "", "", "", "", "", "", "", "", ""};
private static final String[] TRADITIONAL_DIGITS = {"", "", "", "", "", "", "", "", "", ""};
/**
* 简体中文单位
**/
private static final String[] simpleUnits = {"", "", "", ""};
private static final String[] SIMPLE_UNITS = {"", "", "", ""};
/**
* 繁体中文单位
**/
private static final String[] traditionalUnits = {"", "", "", ""};
private static final String[] TRADITIONAL_UNITS = {"", "", "", ""};
/**
* 阿拉伯数字转换成中文,小数点后四舍五入保留两位. 使用于整数小数的转换.
@ -53,7 +53,7 @@ public class NumberChineseFormatter {
* @return 中文
*/
public static String format(double amount, boolean isUseTraditional, boolean isMoneyMode) {
final String[] numArray = isUseTraditional ? traditionalDigits : simpleDigits;
final String[] numArray = isUseTraditional ? TRADITIONAL_DIGITS : SIMPLE_DIGITS;
if (amount > 99999999999999.99 || amount < -99999999999999.99) {
throw new IllegalArgumentException("Number support only: (-99999999999999.99 99999999999999.99)");
@ -150,7 +150,7 @@ public class NumberChineseFormatter {
* @since 5.3.9
*/
public static String numberCharToChinese(char c, boolean isUseTraditional) {
String[] numArray = isUseTraditional ? traditionalDigits : simpleDigits;
String[] numArray = isUseTraditional ? TRADITIONAL_DIGITS : SIMPLE_DIGITS;
int index = c - 48;
if (index < 0 || index >= numArray.length) {
return String.valueOf(c);
@ -170,8 +170,8 @@ public class NumberChineseFormatter {
// throw new IllegalArgumentException("Number must 0 < num < 10000");
// }
String[] numArray = isUseTraditional ? traditionalDigits : simpleDigits;
String[] units = isUseTraditional ? traditionalUnits : simpleUnits;
String[] numArray = isUseTraditional ? TRADITIONAL_DIGITS : SIMPLE_DIGITS;
String[] units = isUseTraditional ? TRADITIONAL_UNITS : SIMPLE_UNITS;
int temp = amountPart;

View File

@ -21,7 +21,7 @@ public class ChineseDate {
/**
* 1900-01-31
*/
private static final long baseDate = -2206425943000L;
private static final long BASE_DATE = -2206425943000L;
//农历年
private final int year;
//农历月
@ -46,7 +46,7 @@ public class ChineseDate {
*/
public ChineseDate(Date date) {
// 求出和1900年1月31日相差的天数
int offset = (int) ((date.getTime() - baseDate) / DateUnit.DAY.getMillis());
int offset = (int) ((date.getTime() - BASE_DATE) / DateUnit.DAY.getMillis());
// 计算农历年份
// 用offset减去每农历年的天数计算当天是农历第几天offset是当年的第几天
int daysOfYear;
@ -299,7 +299,7 @@ public class ChineseDate {
if (D >= firstNode) {
gzM = GanZhi.cyclicalm((Y - LunarInfo.BASE_YEAR) * 12 + M + 12);
}
int dayCyclical = (int) ((DateUtil.parseDate(Y + "-" + M + "-" + "1").getTime() - baseDate + 2592000000L) / DateUnit.DAY.getMillis()) + 10;
int dayCyclical = (int) ((DateUtil.parseDate(Y + "-" + M + "-" + "1").getTime() - BASE_DATE + 2592000000L) / DateUnit.DAY.getMillis()) + 10;
String gzD = GanZhi.cyclicalm(dayCyclical + D - 1);
return gzyear + "" + gzM + "" + gzD + "";
}

View File

@ -20,7 +20,7 @@ import cn.hutool.core.util.ArrayUtil;
public class DateModifier {
/** 忽略的计算的字段 */
private static final int[] ignoreFields = new int[] { //
private static final int[] IGNORE_FIELDS = new int[] { //
Calendar.HOUR_OF_DAY, // 与HOUR同名
Calendar.AM_PM, // 此字段单独处理不参与计算起始和结束
Calendar.DAY_OF_WEEK_IN_MONTH, // 不参与计算
@ -62,7 +62,7 @@ public class DateModifier {
// 循环处理各级字段精确到毫秒字段
for (int i = dateField + 1; i <= Calendar.MILLISECOND; i++) {
if (ArrayUtil.contains(ignoreFields, i)) {
if (ArrayUtil.contains(IGNORE_FIELDS, i)) {
// 忽略无关字段WEEK_OF_MONTH始终不做修改
continue;
}

View File

@ -12,7 +12,7 @@ import java.util.Date;
public class Zodiac {
/** 星座分隔时间日 */
private static final int[] dayArr = new int[] { 20, 19, 21, 20, 21, 22, 23, 23, 23, 24, 23, 22 };
private static final int[] DAY_ARR = new int[] { 20, 19, 21, 20, 21, 22, 23, 23, 23, 24, 23, 22 };
/** 星座 */
private static final String[] ZODIACS = new String[] { "摩羯座", "水瓶座", "双鱼座", "白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "摩羯座" };
private static final String[] CHINESE_ZODIACS = new String[] { "", "", "", "", "", "", "", "", "", "", "", "" };
@ -61,7 +61,7 @@ public class Zodiac {
*/
public static String getZodiac(int month, int day) {
// 在分隔日前为前一个星座否则为后一个星座
return day < dayArr[month] ? ZODIACS[month] : ZODIACS[month + 1];
return day < DAY_ARR[month] ? ZODIACS[month] : ZODIACS[month + 1];
}
// ----------------------------------------------------------------------------------------------------------- 生肖

View File

@ -15,71 +15,71 @@ public class LunarFestival {
//农历节日 *表示放假日
// 来自https://baike.baidu.com/item/%E4%B8%AD%E5%9B%BD%E4%BC%A0%E7%BB%9F%E8%8A%82%E6%97%A5/396100
private static final TableMap<Pair<Integer, Integer>, String> lFtv = new TableMap<>(16);
private static final TableMap<Pair<Integer, Integer>, String> L_FTV = new TableMap<>(16);
static{
lFtv.put(new Pair<>(1, 1), "春节");
lFtv.put(new Pair<>(1, 2), "犬日");
lFtv.put(new Pair<>(1, 3), "猪日");
lFtv.put(new Pair<>(1, 4), "羊日");
lFtv.put(new Pair<>(1, 5), "牛日 破五日");
lFtv.put(new Pair<>(1, 6), "马日 送穷日");
lFtv.put(new Pair<>(1, 7), "人日 人胜节");
lFtv.put(new Pair<>(1, 8), "谷日 八仙日");
lFtv.put(new Pair<>(1, 9), "天日 九皇会");
lFtv.put(new Pair<>(1, 10), "地日 石头生日");
lFtv.put(new Pair<>(1, 12), "火日 老鼠娶媳妇日");
lFtv.put(new Pair<>(1, 13), "上(试)灯日 关公升天日");
lFtv.put(new Pair<>(1, 15), "元宵节");
lFtv.put(new Pair<>(1, 18), "落灯日");
L_FTV.put(new Pair<>(1, 1), "春节");
L_FTV.put(new Pair<>(1, 2), "犬日");
L_FTV.put(new Pair<>(1, 3), "猪日");
L_FTV.put(new Pair<>(1, 4), "羊日");
L_FTV.put(new Pair<>(1, 5), "牛日 破五日");
L_FTV.put(new Pair<>(1, 6), "马日 送穷日");
L_FTV.put(new Pair<>(1, 7), "人日 人胜节");
L_FTV.put(new Pair<>(1, 8), "谷日 八仙日");
L_FTV.put(new Pair<>(1, 9), "天日 九皇会");
L_FTV.put(new Pair<>(1, 10), "地日 石头生日");
L_FTV.put(new Pair<>(1, 12), "火日 老鼠娶媳妇日");
L_FTV.put(new Pair<>(1, 13), "上(试)灯日 关公升天日");
L_FTV.put(new Pair<>(1, 15), "元宵节");
L_FTV.put(new Pair<>(1, 18), "落灯日");
// 二月
lFtv.put(new Pair<>(2, 1), "中和节 太阳生日");
lFtv.put(new Pair<>(2, 2), "龙抬头");
lFtv.put(new Pair<>(2, 12), "花朝节");
lFtv.put(new Pair<>(2, 19), "观世音圣诞");
L_FTV.put(new Pair<>(2, 1), "中和节 太阳生日");
L_FTV.put(new Pair<>(2, 2), "龙抬头");
L_FTV.put(new Pair<>(2, 12), "花朝节");
L_FTV.put(new Pair<>(2, 19), "观世音圣诞");
// 三月
lFtv.put(new Pair<>(3, 3), "上巳节");
L_FTV.put(new Pair<>(3, 3), "上巳节");
// 四月
lFtv.put(new Pair<>(4, 1), "祭雹神");
lFtv.put(new Pair<>(4, 4), "文殊菩萨诞辰");
lFtv.put(new Pair<>(4, 8), "佛诞节");
L_FTV.put(new Pair<>(4, 1), "祭雹神");
L_FTV.put(new Pair<>(4, 4), "文殊菩萨诞辰");
L_FTV.put(new Pair<>(4, 8), "佛诞节");
// 五月
lFtv.put(new Pair<>(5, 5), "端午节");
L_FTV.put(new Pair<>(5, 5), "端午节");
// 六月
lFtv.put(new Pair<>(6, 6), "晒衣节 姑姑节");
lFtv.put(new Pair<>(6, 6), "天贶节");
lFtv.put(new Pair<>(6, 24), "彝族火把节");
L_FTV.put(new Pair<>(6, 6), "晒衣节 姑姑节");
L_FTV.put(new Pair<>(6, 6), "天贶节");
L_FTV.put(new Pair<>(6, 24), "彝族火把节");
// 七月
lFtv.put(new Pair<>(7, 7), "七夕");
lFtv.put(new Pair<>(7, 14), "鬼节(南方)");
lFtv.put(new Pair<>(7, 15), "中元节");
lFtv.put(new Pair<>(7, 15), "盂兰盆节");
lFtv.put(new Pair<>(7, 30), "地藏节");
L_FTV.put(new Pair<>(7, 7), "七夕");
L_FTV.put(new Pair<>(7, 14), "鬼节(南方)");
L_FTV.put(new Pair<>(7, 15), "中元节");
L_FTV.put(new Pair<>(7, 15), "盂兰盆节");
L_FTV.put(new Pair<>(7, 30), "地藏节");
// 八月
lFtv.put(new Pair<>(8, 15), "中秋节");
L_FTV.put(new Pair<>(8, 15), "中秋节");
// 九月
lFtv.put(new Pair<>(9, 9), "重阳节");
L_FTV.put(new Pair<>(9, 9), "重阳节");
// 十月
lFtv.put(new Pair<>(10, 1), "祭祖节");
lFtv.put(new Pair<>(10, 15), "下元节");
L_FTV.put(new Pair<>(10, 1), "祭祖节");
L_FTV.put(new Pair<>(10, 15), "下元节");
// 十一月
lFtv.put(new Pair<>(11, 17), "阿弥陀佛圣诞");
L_FTV.put(new Pair<>(11, 17), "阿弥陀佛圣诞");
// 腊月
lFtv.put(new Pair<>(12, 8), "腊八节");
lFtv.put(new Pair<>(12, 16), "尾牙");
lFtv.put(new Pair<>(12, 23), "小年");
lFtv.put(new Pair<>(12, 29), "除夕");
lFtv.put(new Pair<>(12, 30), "除夕");
L_FTV.put(new Pair<>(12, 8), "腊八节");
L_FTV.put(new Pair<>(12, 16), "尾牙");
L_FTV.put(new Pair<>(12, 23), "小年");
L_FTV.put(new Pair<>(12, 29), "除夕");
L_FTV.put(new Pair<>(12, 30), "除夕");
}
/**
@ -90,6 +90,6 @@ public class LunarFestival {
* @return 获得农历节日
*/
public static List<String> getFestivals(int month, int day) {
return lFtv.getValues(new Pair<>(month, day));
return L_FTV.getValues(new Pair<>(month, day));
}
}

View File

@ -25,7 +25,7 @@ public class SolarTerms {
return -1;
}
String _table = sTermInfo[y - 1900];
String _table = S_TERM_INFO[y - 1900];
Integer[] _info = new Integer[6];
for (int i = 0; i < 6; i++) {
_info[i] = NumberUtil.parseInt("0x" + _table.substring(i * 5, 5 * (i + 1)));
@ -44,7 +44,7 @@ public class SolarTerms {
* 1900-2100各年的24节气日期速查表
* 此表来自https://github.com/jjonline/calendar.js/blob/master/calendar.js
*/
private static final String[] sTermInfo = new String[]{
private static final String[] S_TERM_INFO = new String[]{
"9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c3598082c95f8c965cc920f",
"97bd0b06bdb0722c965ce1cfcc920f", "b027097bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e",
"97bcf97c359801ec95f8c965cc920f", "97bd0b06bdb0722c965ce1cfcc920f", "b027097bd097c36b0b6fc9274c91aa",

View File

@ -38,7 +38,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
/** SHORT locale dependent date or time style. */
public static final int SHORT = DateFormat.SHORT;
private static final FormatCache<FastDateFormat> cache = new FormatCache<FastDateFormat>(){
private static final FormatCache<FastDateFormat> CACHE = new FormatCache<FastDateFormat>(){
@Override
protected FastDateFormat createInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
return new FastDateFormat(pattern, timeZone, locale);
@ -55,7 +55,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @return {@link FastDateFormat}
*/
public static FastDateFormat getInstance() {
return cache.getInstance();
return CACHE.getInstance();
}
/**
@ -67,7 +67,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @throws IllegalArgumentException 日期格式问题
*/
public static FastDateFormat getInstance(final String pattern) {
return cache.getInstance(pattern, null, null);
return CACHE.getInstance(pattern, null, null);
}
/**
@ -80,7 +80,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @throws IllegalArgumentException 日期格式问题
*/
public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone) {
return cache.getInstance(pattern, timeZone, null);
return CACHE.getInstance(pattern, timeZone, null);
}
/**
@ -93,7 +93,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @throws IllegalArgumentException 日期格式问题
*/
public static FastDateFormat getInstance(final String pattern, final Locale locale) {
return cache.getInstance(pattern, null, locale);
return CACHE.getInstance(pattern, null, locale);
}
/**
@ -107,7 +107,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @throws IllegalArgumentException 日期格式问题
*/
public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
return cache.getInstance(pattern, timeZone, locale);
return CACHE.getInstance(pattern, timeZone, locale);
}
// -----------------------------------------------------------------------
@ -119,7 +119,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @return 本地化 {@link FastDateFormat}
*/
public static FastDateFormat getDateInstance(final int style) {
return cache.getDateInstance(style, null, null);
return CACHE.getDateInstance(style, null, null);
}
/**
@ -131,7 +131,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @return 本地化 {@link FastDateFormat}
*/
public static FastDateFormat getDateInstance(final int style, final Locale locale) {
return cache.getDateInstance(style, null, locale);
return CACHE.getDateInstance(style, null, locale);
}
/**
@ -143,7 +143,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @return 本地化 {@link FastDateFormat}
*/
public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone) {
return cache.getDateInstance(style, timeZone, null);
return CACHE.getDateInstance(style, timeZone, null);
}
/**
@ -156,7 +156,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @return 本地化 {@link FastDateFormat}
*/
public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone, final Locale locale) {
return cache.getDateInstance(style, timeZone, locale);
return CACHE.getDateInstance(style, timeZone, locale);
}
// -----------------------------------------------------------------------
@ -168,7 +168,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @return 本地化 {@link FastDateFormat}
*/
public static FastDateFormat getTimeInstance(final int style) {
return cache.getTimeInstance(style, null, null);
return CACHE.getTimeInstance(style, null, null);
}
/**
@ -180,7 +180,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @return 本地化 {@link FastDateFormat}
*/
public static FastDateFormat getTimeInstance(final int style, final Locale locale) {
return cache.getTimeInstance(style, null, locale);
return CACHE.getTimeInstance(style, null, locale);
}
/**
@ -192,7 +192,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @return 本地化 {@link FastDateFormat}
*/
public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone) {
return cache.getTimeInstance(style, timeZone, null);
return CACHE.getTimeInstance(style, timeZone, null);
}
/**
@ -205,7 +205,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @return 本地化 {@link FastDateFormat}
*/
public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone, final Locale locale) {
return cache.getTimeInstance(style, timeZone, locale);
return CACHE.getTimeInstance(style, timeZone, locale);
}
// -----------------------------------------------------------------------
@ -218,7 +218,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @return 本地化 {@link FastDateFormat}
*/
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle) {
return cache.getDateTimeInstance(dateStyle, timeStyle, null, null);
return CACHE.getDateTimeInstance(dateStyle, timeStyle, null, null);
}
/**
@ -231,7 +231,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @return 本地化 {@link FastDateFormat}
*/
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final Locale locale) {
return cache.getDateTimeInstance(dateStyle, timeStyle, null, locale);
return CACHE.getDateTimeInstance(dateStyle, timeStyle, null, locale);
}
/**
@ -258,7 +258,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @return 本地化 {@link FastDateFormat}
*/
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) {
return cache.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale);
return CACHE.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale);
}
// ----------------------------------------------------------------------- Constructor start

View File

@ -447,7 +447,7 @@ public class FastDateParser extends AbstractDateBasic implements DateParser {
}
@SuppressWarnings("unchecked") // OK because we are creating an array with no entries
private static final ConcurrentMap<Locale, Strategy>[] caches = new ConcurrentMap[Calendar.FIELD_COUNT];
private static final ConcurrentMap<Locale, Strategy>[] CACHES = new ConcurrentMap[Calendar.FIELD_COUNT];
/**
* Get a cache of Strategies for a particular field
@ -456,11 +456,11 @@ public class FastDateParser extends AbstractDateBasic implements DateParser {
* @return a cache of Locale to Strategy
*/
private static ConcurrentMap<Locale, Strategy> getCache(final int field) {
synchronized (caches) {
if (caches[field] == null) {
caches[field] = new ConcurrentHashMap<>(3);
synchronized (CACHES) {
if (CACHES[field] == null) {
CACHES[field] = new ConcurrentHashMap<>(3);
}
return caches[field];
return CACHES[field];
}
}

View File

@ -1052,7 +1052,7 @@ public class FastDatePrinter extends AbstractDateBasic implements DatePrinter {
// -----------------------------------------------------------------------
private static final ConcurrentMap<TimeZoneDisplayKey, String> cTimeZoneDisplayCache = new ConcurrentHashMap<>(7);
private static final ConcurrentMap<TimeZoneDisplayKey, String> C_TIME_ZONE_DISPLAY_CACHE = new ConcurrentHashMap<>(7);
/**
* <p>
@ -1067,11 +1067,11 @@ public class FastDatePrinter extends AbstractDateBasic implements DatePrinter {
*/
static String getTimeZoneDisplay(final TimeZone tz, final boolean daylight, final int style, final Locale locale) {
final TimeZoneDisplayKey key = new TimeZoneDisplayKey(tz, daylight, style, locale);
String value = cTimeZoneDisplayCache.get(key);
String value = C_TIME_ZONE_DISPLAY_CACHE.get(key);
if (value == null) {
// This is a very slow call, so cache the results.
value = tz.getDisplayName(daylight, style, locale);
final String prior = cTimeZoneDisplayCache.putIfAbsent(key, value);
final String prior = C_TIME_ZONE_DISPLAY_CACHE.putIfAbsent(key, value);
if (prior != null) {
value = prior;
}

View File

@ -26,7 +26,7 @@ abstract class FormatCache<F extends Format> {
private final ConcurrentMap<Tuple, F> cInstanceCache = new ConcurrentHashMap<>(7);
private static final ConcurrentMap<Tuple, String> cDateTimeInstanceCache = new ConcurrentHashMap<>(7);
private static final ConcurrentMap<Tuple, String> C_DATE_TIME_INSTANCE_CACHE = new ConcurrentHashMap<>(7);
/**
* 使用默认的patterntimezone和locale获得缓存中的实例
@ -163,7 +163,7 @@ abstract class FormatCache<F extends Format> {
static String getPatternForStyle(final Integer dateStyle, final Integer timeStyle, final Locale locale) {
final Tuple key = new Tuple(dateStyle, timeStyle, locale);
String pattern = cDateTimeInstanceCache.get(key);
String pattern = C_DATE_TIME_INSTANCE_CACHE.get(key);
if (pattern == null) {
try {
DateFormat formatter;
@ -175,7 +175,7 @@ abstract class FormatCache<F extends Format> {
formatter = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
}
pattern = ((SimpleDateFormat) formatter).toPattern();
final String previous = cDateTimeInstanceCache.putIfAbsent(key, pattern);
final String previous = C_DATE_TIME_INSTANCE_CACHE.putIfAbsent(key, pattern);
if (previous != null) {
// even though it doesn't matter if another thread put the pattern
// it's still good practice to return the String instance that is

View File

@ -61,6 +61,12 @@ public class ImgUtil {
public static final String IMAGE_TYPE_BMP = "bmp";// 英文Bitmap位图的简写它是Windows操作系统中的标准图像文件格式
public static final String IMAGE_TYPE_PNG = "png";// 可移植网络图形
public static final String IMAGE_TYPE_PSD = "psd";// Photoshop的专用格式Photoshop
/**
* RGB颜色范围上限
*/
private static final int RGB_COLOR_BOUND = 256;
// ---------------------------------------------------------------------------------------------------------------------- scale
@ -1952,7 +1958,7 @@ public class ImgUtil {
if (null == random) {
random = RandomUtil.getRandom();
}
return new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255));
return new Color(random.nextInt(RGB_COLOR_BOUND), random.nextInt(RGB_COLOR_BOUND), random.nextInt(RGB_COLOR_BOUND));
}
/**

View File

@ -95,7 +95,7 @@ public class GifDecoder {
protected int delay = 0; // delay in milliseconds
protected int transIndex; // transparent color index
protected static final int MaxStackSize = 4096;
protected static final int MAX_STACK_SIZE = 4096;
// max decoder pixel stack size
// LZW decoder working arrays
@ -378,9 +378,9 @@ public class GifDecoder {
if ((pixels == null) || (pixels.length < npix)) {
pixels = new byte[npix]; // allocate new pixel array
}
if (prefix == null) prefix = new short[MaxStackSize];
if (suffix == null) suffix = new byte[MaxStackSize];
if (pixelStack == null) pixelStack = new byte[MaxStackSize + 1];
if (prefix == null) prefix = new short[MAX_STACK_SIZE];
if (suffix == null) suffix = new byte[MAX_STACK_SIZE];
if (pixelStack == null) pixelStack = new byte[MAX_STACK_SIZE + 1];
// Initialize GIF data stream decoder.
@ -455,7 +455,7 @@ public class GifDecoder {
// Add a new string to the string table,
if (available >= MaxStackSize) {
if (available >= MAX_STACK_SIZE) {
pixelStack[top++] = (byte) first;
continue;
}
@ -464,7 +464,7 @@ public class GifDecoder {
suffix[available] = (byte) first;
available++;
if (((available & code_mask) == 0)
&& (available < MaxStackSize)) {
&& (available < MAX_STACK_SIZE)) {
code_size++;
code_mask += available;
}
@ -606,10 +606,11 @@ public class GifDecoder {
for (int i = 0; i < 11; i++) {
app.append((char) block[i]);
}
if (app.toString().equals("NETSCAPE2.0")) {
if ("NETSCAPE2.0".equals(app.toString())) {
readNetscapeExt();
} else
} else {
skip(); // don't care
}
break;
default: // uninteresting extension

View File

@ -29,16 +29,16 @@ package cn.hutool.core.img.gif;
*/
public class NeuQuant {
protected static final int netsize = 256; /* number of colours used */
protected static final int NETSIZE = 256; /* number of colours used */
/* four primes near 500 - assume no image has a length so large */
/* that it is divisible by all four primes */
protected static final int prime1 = 499;
protected static final int prime2 = 491;
protected static final int prime3 = 487;
protected static final int prime4 = 503;
protected static final int PRIME1 = 499;
protected static final int PRIME2 = 491;
protected static final int PRIME3 = 487;
protected static final int PRIME4 = 503;
protected static final int minpicturebytes = (3 * prime4);
protected static final int MINPICTUREBYTES = (3 * PRIME4);
/* minimum size for input image */
/* Program Skeleton
@ -56,38 +56,38 @@ public class NeuQuant {
/* Network Definitions
------------------- */
protected static final int maxnetpos = (netsize - 1);
protected static final int netbiasshift = 4; /* bias for colour values */
protected static final int ncycles = 100; /* no. of learning cycles */
protected static final int MAXNETPOS = (NETSIZE - 1);
protected static final int NETBIASSHIFT = 4; /* bias for colour values */
protected static final int NCYCLES = 100; /* no. of learning cycles */
/* defs for freq and bias */
protected static final int intbiasshift = 16; /* bias for fractions */
protected static final int intbias = (1 << intbiasshift);
protected static final int gammashift = 10; /* gamma = 1024 */
protected static final int gamma = (1 << gammashift);
protected static final int betashift = 10;
protected static final int beta = (intbias >> betashift); /* beta = 1/1024 */
protected static final int betagamma =
(intbias << (gammashift - betashift));
protected static final int INTBIASSHIFT = 16; /* bias for fractions */
protected static final int INTBIAS = (1 << INTBIASSHIFT);
protected static final int GAMMASHIFT = 10; /* gamma = 1024 */
protected static final int GAMMA = (1 << GAMMASHIFT);
protected static final int BETASHIFT = 10;
protected static final int BETA = (INTBIAS >> BETASHIFT); /* beta = 1/1024 */
protected static final int BETAGAMMA =
(INTBIAS << (GAMMASHIFT - BETASHIFT));
/* defs for decreasing radius factor */
protected static final int initrad = (netsize >> 3); /* for 256 cols, radius starts */
protected static final int radiusbiasshift = 6; /* at 32.0 biased by 6 bits */
protected static final int radiusbias = (1 << radiusbiasshift);
protected static final int initradius = (initrad * radiusbias); /* and decreases by a */
protected static final int radiusdec = 30; /* factor of 1/30 each cycle */
protected static final int INITRAD = (NETSIZE >> 3); /* for 256 cols, radius starts */
protected static final int RADIUSBIASSHIFT = 6; /* at 32.0 biased by 6 bits */
protected static final int RADIUSBIAS = (1 << RADIUSBIASSHIFT);
protected static final int INITRADIUS = (INITRAD * RADIUSBIAS); /* and decreases by a */
protected static final int RADIUSDEC = 30; /* factor of 1/30 each cycle */
/* defs for decreasing alpha factor */
protected static final int alphabiasshift = 10; /* alpha starts at 1.0 */
protected static final int initalpha = (1 << alphabiasshift);
protected static final int ALPHABIASSHIFT = 10; /* alpha starts at 1.0 */
protected static final int INITALPHA = (1 << ALPHABIASSHIFT);
protected int alphadec; /* biased by 10 bits */
/* radbias and alpharadbias used for radpower calculation */
protected static final int radbiasshift = 8;
protected static final int radbias = (1 << radbiasshift);
protected static final int alpharadbshift = (alphabiasshift + radbiasshift);
protected static final int alpharadbias = (1 << alpharadbshift);
protected static final int RADBIASSHIFT = 8;
protected static final int RADBIAS = (1 << RADBIASSHIFT);
protected static final int ALPHARADBSHIFT = (ALPHABIASSHIFT + RADBIASSHIFT);
protected static final int ALPHARADBIAS = (1 << ALPHARADBSHIFT);
/* Types and Global Variables
-------------------------- */
@ -103,10 +103,10 @@ public class NeuQuant {
protected int[] netindex = new int[256];
/* for network lookup - really 256 */
protected int[] bias = new int[netsize];
protected int[] bias = new int[NETSIZE];
/* bias and freq arrays for learning */
protected int[] freq = new int[netsize];
protected int[] radpower = new int[initrad];
protected int[] freq = new int[NETSIZE];
protected int[] radpower = new int[INITRAD];
/* radpower for precomputation */
/* Initialise network in range (0,0,0) to (255,255,255) and set parameters
@ -120,23 +120,23 @@ public class NeuQuant {
lengthcount = len;
samplefac = sample;
network = new int[netsize][];
for (i = 0; i < netsize; i++) {
network = new int[NETSIZE][];
for (i = 0; i < NETSIZE; i++) {
network[i] = new int[4];
p = network[i];
p[0] = p[1] = p[2] = (i << (netbiasshift + 8)) / netsize;
freq[i] = intbias / netsize; /* 1/netsize */
p[0] = p[1] = p[2] = (i << (NETBIASSHIFT + 8)) / NETSIZE;
freq[i] = INTBIAS / NETSIZE; /* 1/netsize */
bias[i] = 0;
}
}
public byte[] colorMap() {
byte[] map = new byte[3 * netsize];
int[] index = new int[netsize];
for (int i = 0; i < netsize; i++)
byte[] map = new byte[3 * NETSIZE];
int[] index = new int[NETSIZE];
for (int i = 0; i < NETSIZE; i++)
index[network[i][3]] = i;
int k = 0;
for (int i = 0; i < netsize; i++) {
for (int i = 0; i < NETSIZE; i++) {
int j = index[i];
map[k++] = (byte) (network[j][0]);
map[k++] = (byte) (network[j][1]);
@ -156,12 +156,12 @@ public class NeuQuant {
previouscol = 0;
startpos = 0;
for (i = 0; i < netsize; i++) {
for (i = 0; i < NETSIZE; i++) {
p = network[i];
smallpos = i;
smallval = p[1]; /* index on g */
/* find smallest in i..netsize-1 */
for (j = i + 1; j < netsize; j++) {
for (j = i + 1; j < NETSIZE; j++) {
q = network[j];
if (q[1] < smallval) { /* index on g */
smallpos = j;
@ -193,9 +193,9 @@ public class NeuQuant {
startpos = i;
}
}
netindex[previouscol] = (startpos + maxnetpos) >> 1;
netindex[previouscol] = (startpos + MAXNETPOS) >> 1;
for (j = previouscol + 1; j < 256; j++)
netindex[j] = maxnetpos; /* really 256 */
netindex[j] = MAXNETPOS; /* really 256 */
}
/* Main Learning Loop
@ -207,44 +207,44 @@ public class NeuQuant {
byte[] p;
int pix, lim;
if (lengthcount < minpicturebytes)
if (lengthcount < MINPICTUREBYTES)
samplefac = 1;
alphadec = 30 + ((samplefac - 1) / 3);
p = thepicture;
pix = 0;
lim = lengthcount;
samplepixels = lengthcount / (3 * samplefac);
delta = samplepixels / ncycles;
alpha = initalpha;
radius = initradius;
delta = samplepixels / NCYCLES;
alpha = INITALPHA;
radius = INITRADIUS;
rad = radius >> radiusbiasshift;
rad = radius >> RADIUSBIASSHIFT;
for (i = 0; i < rad; i++)
radpower[i] =
alpha * (((rad * rad - i * i) * radbias) / (rad * rad));
alpha * (((rad * rad - i * i) * RADBIAS) / (rad * rad));
//fprintf(stderr,"beginning 1D learning: initial radius=%d\n", rad);
if (lengthcount < minpicturebytes)
if (lengthcount < MINPICTUREBYTES)
step = 3;
else if ((lengthcount % prime1) != 0)
step = 3 * prime1;
else if ((lengthcount % PRIME1) != 0)
step = 3 * PRIME1;
else {
if ((lengthcount % prime2) != 0)
step = 3 * prime2;
if ((lengthcount % PRIME2) != 0)
step = 3 * PRIME2;
else {
if ((lengthcount % prime3) != 0)
step = 3 * prime3;
if ((lengthcount % PRIME3) != 0)
step = 3 * PRIME3;
else
step = 3 * prime4;
step = 3 * PRIME4;
}
}
i = 0;
while (i < samplepixels) {
b = (p[pix] & 0xff) << netbiasshift;
g = (p[pix + 1] & 0xff) << netbiasshift;
r = (p[pix + 2] & 0xff) << netbiasshift;
b = (p[pix] & 0xff) << NETBIASSHIFT;
g = (p[pix + 1] & 0xff) << NETBIASSHIFT;
r = (p[pix + 2] & 0xff) << NETBIASSHIFT;
j = contest(b, g, r);
altersingle(alpha, j, b, g, r);
@ -260,13 +260,13 @@ public class NeuQuant {
delta = 1;
if (i % delta == 0) {
alpha -= alpha / alphadec;
radius -= radius / radiusdec;
rad = radius >> radiusbiasshift;
radius -= radius / RADIUSDEC;
rad = radius >> RADIUSBIASSHIFT;
if (rad <= 1)
rad = 0;
for (j = 0; j < rad; j++)
radpower[j] =
alpha * (((rad * rad - j * j) * radbias) / (rad * rad));
alpha * (((rad * rad - j * j) * RADBIAS) / (rad * rad));
}
}
//fprintf(stderr,"finished 1D learning: final alpha=%f !\n",((float)alpha)/initalpha);
@ -285,12 +285,12 @@ public class NeuQuant {
i = netindex[g]; /* index on g */
j = i - 1; /* start at netindex[g] and work outwards */
while ((i < netsize) || (j >= 0)) {
if (i < netsize) {
while ((i < NETSIZE) || (j >= 0)) {
if (i < NETSIZE) {
p = network[i];
dist = p[1] - g; /* inx key */
if (dist >= bestd)
i = netsize; /* stop iter */
i = NETSIZE; /* stop iter */
else {
i++;
if (dist < 0)
@ -353,10 +353,10 @@ public class NeuQuant {
int i, j;
for (i = 0; i < netsize; i++) {
network[i][0] >>= netbiasshift;
network[i][1] >>= netbiasshift;
network[i][2] >>= netbiasshift;
for (i = 0; i < NETSIZE; i++) {
network[i][0] >>= NETBIASSHIFT;
network[i][1] >>= NETBIASSHIFT;
network[i][2] >>= NETBIASSHIFT;
network[i][3] = i; /* record colour no */
}
}
@ -372,8 +372,8 @@ public class NeuQuant {
if (lo < -1)
lo = -1;
hi = i + rad;
if (hi > netsize)
hi = netsize;
if (hi > NETSIZE)
hi = NETSIZE;
j = i + 1;
k = i - 1;
@ -383,18 +383,18 @@ public class NeuQuant {
if (j < hi) {
p = network[j++];
try {
p[0] -= (a * (p[0] - b)) / alpharadbias;
p[1] -= (a * (p[1] - g)) / alpharadbias;
p[2] -= (a * (p[2] - r)) / alpharadbias;
p[0] -= (a * (p[0] - b)) / ALPHARADBIAS;
p[1] -= (a * (p[1] - g)) / ALPHARADBIAS;
p[2] -= (a * (p[2] - r)) / ALPHARADBIAS;
} catch (Exception ignored) {
} // prevents 1.3 miscompilation
}
if (k > lo) {
p = network[k--];
try {
p[0] -= (a * (p[0] - b)) / alpharadbias;
p[1] -= (a * (p[1] - g)) / alpharadbias;
p[2] -= (a * (p[2] - r)) / alpharadbias;
p[0] -= (a * (p[0] - b)) / ALPHARADBIAS;
p[1] -= (a * (p[1] - g)) / ALPHARADBIAS;
p[2] -= (a * (p[2] - r)) / ALPHARADBIAS;
} catch (Exception ignored) {
}
}
@ -407,9 +407,9 @@ public class NeuQuant {
/* alter hit neuron */
int[] n = network[i];
n[0] -= (alpha * (n[0] - b)) / initalpha;
n[1] -= (alpha * (n[1] - g)) / initalpha;
n[2] -= (alpha * (n[2] - r)) / initalpha;
n[0] -= (alpha * (n[0] - b)) / INITALPHA;
n[1] -= (alpha * (n[1] - g)) / INITALPHA;
n[2] -= (alpha * (n[2] - r)) / INITALPHA;
}
/* Search for biased BGR values
@ -430,7 +430,7 @@ public class NeuQuant {
bestpos = -1;
bestbiaspos = bestpos;
for (i = 0; i < netsize; i++) {
for (i = 0; i < NETSIZE; i++) {
n = network[i];
dist = n[0] - b;
if (dist < 0)
@ -447,17 +447,17 @@ public class NeuQuant {
bestd = dist;
bestpos = i;
}
biasdist = dist - ((bias[i]) >> (intbiasshift - netbiasshift));
biasdist = dist - ((bias[i]) >> (INTBIASSHIFT - NETBIASSHIFT));
if (biasdist < bestbiasd) {
bestbiasd = biasdist;
bestbiaspos = i;
}
betafreq = (freq[i] >> betashift);
betafreq = (freq[i] >> BETASHIFT);
freq[i] -= betafreq;
bias[i] += (betafreq << gammashift);
bias[i] += (betafreq << GAMMASHIFT);
}
freq[bestpos] += beta;
bias[bestpos] -= betagamma;
freq[bestpos] += BETA;
bias[bestpos] -= BETAGAMMA;
return (bestbiaspos);
}
}

View File

@ -20,60 +20,60 @@ import cn.hutool.core.util.StrUtil;
*/
public class FileTypeUtil {
private static final Map<String, String> fileTypeMap;
private static final Map<String, String> FILE_TYPE_MAP;
static {
fileTypeMap = new ConcurrentHashMap<>();
FILE_TYPE_MAP = new ConcurrentHashMap<>();
fileTypeMap.put("ffd8ff", "jpg"); // JPEG (jpg)
fileTypeMap.put("89504e47", "png"); // PNG (png)
fileTypeMap.put("4749463837", "gif"); // GIF (gif)
fileTypeMap.put("4749463839", "gif"); // GIF (gif)
fileTypeMap.put("49492a00227105008037", "tif"); // TIFF (tif)
fileTypeMap.put("424d228c010000000000", "bmp"); // 16色位图(bmp)
fileTypeMap.put("424d8240090000000000", "bmp"); // 24位位图(bmp)
fileTypeMap.put("424d8e1b030000000000", "bmp"); // 256色位图(bmp)
fileTypeMap.put("41433130313500000000", "dwg"); // CAD (dwg)
fileTypeMap.put("7b5c727466315c616e73", "rtf"); // Rich Text Format (rtf)
fileTypeMap.put("38425053000100000000", "psd"); // Photoshop (psd)
fileTypeMap.put("46726f6d3a203d3f6762", "eml"); // Email [Outlook Express 6] (eml)
fileTypeMap.put("5374616E64617264204A", "mdb"); // MS Access (mdb)
fileTypeMap.put("252150532D41646F6265", "ps");
fileTypeMap.put("255044462d312e", "pdf"); // Adobe Acrobat (pdf)
fileTypeMap.put("2e524d46000000120001", "rmvb"); // rmvb/rm相同
fileTypeMap.put("464c5601050000000900", "flv"); // flv与f4v相同
fileTypeMap.put("00000020667479706", "mp4");
fileTypeMap.put("00000018667479706D70", "mp4");
fileTypeMap.put("49443303000000002176", "mp3");
fileTypeMap.put("000001ba210001000180", "mpg"); //
fileTypeMap.put("3026b2758e66cf11a6d9", "wmv"); // wmv与asf相同
fileTypeMap.put("52494646e27807005741", "wav"); // Wave (wav)
fileTypeMap.put("52494646d07d60074156", "avi");
fileTypeMap.put("4d546864000000060001", "mid"); // MIDI (mid)
fileTypeMap.put("526172211a0700cf9073", "rar");// WinRAR
fileTypeMap.put("235468697320636f6e66", "ini");
fileTypeMap.put("504B03040a0000000000", "jar");
fileTypeMap.put("504B0304140008000800", "jar");
FILE_TYPE_MAP.put("ffd8ff", "jpg"); // JPEG (jpg)
FILE_TYPE_MAP.put("89504e47", "png"); // PNG (png)
FILE_TYPE_MAP.put("4749463837", "gif"); // GIF (gif)
FILE_TYPE_MAP.put("4749463839", "gif"); // GIF (gif)
FILE_TYPE_MAP.put("49492a00227105008037", "tif"); // TIFF (tif)
FILE_TYPE_MAP.put("424d228c010000000000", "bmp"); // 16色位图(bmp)
FILE_TYPE_MAP.put("424d8240090000000000", "bmp"); // 24位位图(bmp)
FILE_TYPE_MAP.put("424d8e1b030000000000", "bmp"); // 256色位图(bmp)
FILE_TYPE_MAP.put("41433130313500000000", "dwg"); // CAD (dwg)
FILE_TYPE_MAP.put("7b5c727466315c616e73", "rtf"); // Rich Text Format (rtf)
FILE_TYPE_MAP.put("38425053000100000000", "psd"); // Photoshop (psd)
FILE_TYPE_MAP.put("46726f6d3a203d3f6762", "eml"); // Email [Outlook Express 6] (eml)
FILE_TYPE_MAP.put("5374616E64617264204A", "mdb"); // MS Access (mdb)
FILE_TYPE_MAP.put("252150532D41646F6265", "ps");
FILE_TYPE_MAP.put("255044462d312e", "pdf"); // Adobe Acrobat (pdf)
FILE_TYPE_MAP.put("2e524d46000000120001", "rmvb"); // rmvb/rm相同
FILE_TYPE_MAP.put("464c5601050000000900", "flv"); // flv与f4v相同
FILE_TYPE_MAP.put("00000020667479706", "mp4");
FILE_TYPE_MAP.put("00000018667479706D70", "mp4");
FILE_TYPE_MAP.put("49443303000000002176", "mp3");
FILE_TYPE_MAP.put("000001ba210001000180", "mpg"); //
FILE_TYPE_MAP.put("3026b2758e66cf11a6d9", "wmv"); // wmv与asf相同
FILE_TYPE_MAP.put("52494646e27807005741", "wav"); // Wave (wav)
FILE_TYPE_MAP.put("52494646d07d60074156", "avi");
FILE_TYPE_MAP.put("4d546864000000060001", "mid"); // MIDI (mid)
FILE_TYPE_MAP.put("526172211a0700cf9073", "rar");// WinRAR
FILE_TYPE_MAP.put("235468697320636f6e66", "ini");
FILE_TYPE_MAP.put("504B03040a0000000000", "jar");
FILE_TYPE_MAP.put("504B0304140008000800", "jar");
// MS Excel 注意wordmsi excel的文件头一样
fileTypeMap.put("d0cf11e0a1b11ae10", "xls");
fileTypeMap.put("504B0304", "zip");
fileTypeMap.put("4d5a9000030000000400", "exe");// 可执行文件
fileTypeMap.put("3c25402070616765206c", "jsp");// jsp文件
fileTypeMap.put("4d616e69666573742d56", "mf");// MF文件
fileTypeMap.put("7061636b616765207765", "java");// java文件
fileTypeMap.put("406563686f206f66660d", "bat");// bat文件
fileTypeMap.put("1f8b0800000000000000", "gz");// gz文件
fileTypeMap.put("cafebabe0000002e0041", "class");// bat文件
fileTypeMap.put("49545346030000006000", "chm");// bat文件
fileTypeMap.put("04000000010000001300", "mxp");// bat文件
fileTypeMap.put("6431303a637265617465", "torrent");
fileTypeMap.put("6D6F6F76", "mov"); // Quicktime (mov)
fileTypeMap.put("FF575043", "wpd"); // WordPerfect (wpd)
fileTypeMap.put("CFAD12FEC5FD746F", "dbx"); // Outlook Express (dbx)
fileTypeMap.put("2142444E", "pst"); // Outlook (pst)
fileTypeMap.put("AC9EBD8F", "qdf"); // Quicken (qdf)
fileTypeMap.put("E3828596", "pwl"); // Windows Password (pwl)
fileTypeMap.put("2E7261FD", "ram"); // Real Audio (ram)
FILE_TYPE_MAP.put("d0cf11e0a1b11ae10", "xls");
FILE_TYPE_MAP.put("504B0304", "zip");
FILE_TYPE_MAP.put("4d5a9000030000000400", "exe");// 可执行文件
FILE_TYPE_MAP.put("3c25402070616765206c", "jsp");// jsp文件
FILE_TYPE_MAP.put("4d616e69666573742d56", "mf");// MF文件
FILE_TYPE_MAP.put("7061636b616765207765", "java");// java文件
FILE_TYPE_MAP.put("406563686f206f66660d", "bat");// bat文件
FILE_TYPE_MAP.put("1f8b0800000000000000", "gz");// gz文件
FILE_TYPE_MAP.put("cafebabe0000002e0041", "class");// bat文件
FILE_TYPE_MAP.put("49545346030000006000", "chm");// bat文件
FILE_TYPE_MAP.put("04000000010000001300", "mxp");// bat文件
FILE_TYPE_MAP.put("6431303a637265617465", "torrent");
FILE_TYPE_MAP.put("6D6F6F76", "mov"); // Quicktime (mov)
FILE_TYPE_MAP.put("FF575043", "wpd"); // WordPerfect (wpd)
FILE_TYPE_MAP.put("CFAD12FEC5FD746F", "dbx"); // Outlook Express (dbx)
FILE_TYPE_MAP.put("2142444E", "pst"); // Outlook (pst)
FILE_TYPE_MAP.put("AC9EBD8F", "qdf"); // Quicken (qdf)
FILE_TYPE_MAP.put("E3828596", "pwl"); // Windows Password (pwl)
FILE_TYPE_MAP.put("2E7261FD", "ram"); // Real Audio (ram)
}
/**
@ -85,7 +85,7 @@ public class FileTypeUtil {
* @return 之前已经存在的文件扩展名
*/
public static String putFileType(String fileStreamHexHead, String extName) {
return fileTypeMap.put(fileStreamHexHead.toLowerCase(), extName);
return FILE_TYPE_MAP.put(fileStreamHexHead.toLowerCase(), extName);
}
/**
@ -95,7 +95,7 @@ public class FileTypeUtil {
* @return 移除的文件扩展名
*/
public static String removeFileType(String fileStreamHexHead) {
return fileTypeMap.remove(fileStreamHexHead.toLowerCase());
return FILE_TYPE_MAP.remove(fileStreamHexHead.toLowerCase());
}
/**
@ -105,7 +105,7 @@ public class FileTypeUtil {
* @return 文件类型未找到为<code>null</code>
*/
public static String getType(String fileStreamHexHead) {
for (Entry<String, String> fileTypeEntry : fileTypeMap.entrySet()) {
for (Entry<String, String> fileTypeEntry : FILE_TYPE_MAP.entrySet()) {
if (StrUtil.startWithIgnoreCase(fileStreamHexHead, fileTypeEntry.getKey())) {
return fileTypeEntry.getValue();
}

View File

@ -8,7 +8,7 @@ package cn.hutool.core.io.checksum.crc16;
*/
public class CRC16Ansi extends CRC16Checksum{
private static final int wCPoly = 0xa001;
private static final int WC_POLY = 0xa001;
@Override
public void reset() {
@ -25,7 +25,7 @@ public class CRC16Ansi extends CRC16Checksum{
int flag = wCRCin & 0x0001;
wCRCin = wCRCin >> 1;
if (flag == 1) {
wCRCin ^= wCPoly;
wCRCin ^= WC_POLY;
}
}
}

View File

@ -9,7 +9,7 @@ package cn.hutool.core.io.checksum.crc16;
*/
public class CRC16CCITT extends CRC16Checksum{
private static final int wCPoly = 0x8408;
private static final int WC_POLY = 0x8408;
@Override
public void update(int b) {
@ -17,7 +17,7 @@ public class CRC16CCITT extends CRC16Checksum{
for (int j = 0; j < 8; j++) {
if ((wCRCin & 0x0001) != 0) {
wCRCin >>= 1;
wCRCin ^= wCPoly;
wCRCin ^= WC_POLY;
} else {
wCRCin >>= 1;
}

View File

@ -8,7 +8,7 @@ package cn.hutool.core.io.checksum.crc16;
*/
public class CRC16CCITTFalse extends CRC16Checksum{
private static final int wCPoly = 0x1021;
private static final int WC_POLY = 0x1021;
@Override
public void reset() {
@ -28,7 +28,7 @@ public class CRC16CCITTFalse extends CRC16Checksum{
boolean c15 = ((wCRCin >> 15 & 1) == 1);
wCRCin <<= 1;
if (c15 ^ bit)
wCRCin ^= wCPoly;
wCRCin ^= WC_POLY;
}
}
}

View File

@ -9,7 +9,7 @@ package cn.hutool.core.io.checksum.crc16;
*/
public class CRC16DNP extends CRC16Checksum{
private static final int wCPoly = 0xA6BC;
private static final int WC_POLY = 0xA6BC;
@Override
public void update(byte[] b, int off, int len) {
@ -23,7 +23,7 @@ public class CRC16DNP extends CRC16Checksum{
for (int j = 0; j < 8; j++) {
if ((wCRCin & 0x0001) != 0) {
wCRCin >>= 1;
wCRCin ^= wCPoly;
wCRCin ^= WC_POLY;
} else {
wCRCin >>= 1;
}

View File

@ -9,7 +9,7 @@ package cn.hutool.core.io.checksum.crc16;
*/
public class CRC16IBM extends CRC16Checksum{
private static final int wCPoly = 0xa001;
private static final int WC_POLY = 0xa001;
@Override
public void update(int b) {
@ -17,7 +17,7 @@ public class CRC16IBM extends CRC16Checksum{
for (int j = 0; j < 8; j++) {
if ((wCRCin & 0x0001) != 0) {
wCRCin >>= 1;
wCRCin ^= wCPoly;
wCRCin ^= WC_POLY;
} else {
wCRCin >>= 1;
}

View File

@ -9,7 +9,7 @@ package cn.hutool.core.io.checksum.crc16;
*/
public class CRC16Maxim extends CRC16Checksum{
private static final int wCPoly = 0xa001;
private static final int WC_POLY = 0xa001;
@Override
public void update(byte[] b, int off, int len) {
@ -23,7 +23,7 @@ public class CRC16Maxim extends CRC16Checksum{
for (int j = 0; j < 8; j++) {
if ((wCRCin & 0x0001) != 0) {
wCRCin >>= 1;
wCRCin ^= wCPoly;
wCRCin ^= WC_POLY;
} else {
wCRCin >>= 1;
}

View File

@ -10,7 +10,7 @@ package cn.hutool.core.io.checksum.crc16;
*/
public class CRC16Modbus extends CRC16Checksum{
private static final int wCPoly = 0xa001;
private static final int WC_POLY = 0xa001;
@Override
public void reset(){
@ -23,7 +23,7 @@ public class CRC16Modbus extends CRC16Checksum{
for (int j = 0; j < 8; j++) {
if ((wCRCin & 0x0001) != 0) {
wCRCin >>= 1;
wCRCin ^= wCPoly;
wCRCin ^= WC_POLY;
} else {
wCRCin >>= 1;
}

View File

@ -9,7 +9,7 @@ package cn.hutool.core.io.checksum.crc16;
*/
public class CRC16USB extends CRC16Checksum{
private static final int wCPoly = 0xa001;
private static final int WC_POLY = 0xa001;
@Override
public void reset(){
@ -28,7 +28,7 @@ public class CRC16USB extends CRC16Checksum{
for (int j = 0; j < 8; j++) {
if ((wCRCin & 0x0001) != 0) {
wCRCin >>= 1;
wCRCin ^= wCPoly;
wCRCin ^= WC_POLY;
} else {
wCRCin >>= 1;
}

View File

@ -9,7 +9,7 @@ package cn.hutool.core.io.checksum.crc16;
*/
public class CRC16X25 extends CRC16Checksum{
private static final int wCPoly = 0x8408;
private static final int WC_POLY = 0x8408;
@Override
public void reset(){
@ -28,7 +28,7 @@ public class CRC16X25 extends CRC16Checksum{
for (int j = 0; j < 8; j++) {
if ((wCRCin & 0x0001) != 0) {
wCRCin >>= 1;
wCRCin ^= wCPoly;
wCRCin ^= WC_POLY;
} else {
wCRCin >>= 1;
}

View File

@ -10,7 +10,7 @@ package cn.hutool.core.io.checksum.crc16;
public class CRC16XModem extends CRC16Checksum{
// 0001 0000 0010 0001 (0, 5, 12)
private static final int wCPoly = 0x1021;
private static final int WC_POLY = 0x1021;
@Override
public void update(byte[] b, int off, int len) {
@ -25,7 +25,7 @@ public class CRC16XModem extends CRC16Checksum{
boolean c15 = ((wCRCin >> 15 & 1) == 1);
wCRCin <<= 1;
if (c15 ^ bit)
wCRCin ^= wCPoly;
wCRCin ^= WC_POLY;
}
}
}

View File

@ -0,0 +1,177 @@
package cn.hutool.core.lang;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 控制台打印表格工具
*
* @author 孙宇
*/
public class ConsoleTableUtil {
/**
* 表格头信息
*/
private final List<List<String>> HEADER_LIST = new ArrayList<>();
/**
* 表格体信息
*/
private final List<List<String>> BODY_LIST = new ArrayList<>();
/**
* 每列最大字符个数
*/
private List<Integer> columnCharNumber;
/**
* 测试
*
* @param args
*/
public static void main(String[] args) {
ConsoleTableUtil t = new ConsoleTableUtil();
t.addHeader("姓名", "年龄");
t.addBody("张三", "15");
t.addBody("李四", "29");
t.addBody("王二麻子", "37");
t.print();
t = new ConsoleTableUtil();
t.addHeader("体温", "占比");
t.addHeader("", "%");
t.addBody("36.8", "10");
t.addBody("37", "5");
t.print();
t = new ConsoleTableUtil();
t.addHeader("标题1", "标题2");
t.addBody("12345", "混合321654asdfcSDF");
t.addBody("sd e3ee ff22", "ff值");
t.print();
}
/**
* 添加头信息
*
* @param titles 列名
* @return 自身对象
*/
public ConsoleTableUtil addHeader(String... titles) {
if (columnCharNumber == null) {
columnCharNumber = new ArrayList<>(Collections.nCopies(titles.length, 0));
}
List<String> l = new ArrayList<>();
HEADER_LIST.add(l);
fillColumns(l, titles);
return this;
}
/**
* 添加体信息
*
* @param values 列值
* @return 自身对象
*/
public ConsoleTableUtil addBody(String... values) {
List<String> l = new ArrayList<>();
BODY_LIST.add(l);
fillColumns(l, values);
return this;
}
/**
* 填充表格头或者体
*
* @param l
* @param columns
*/
private void fillColumns(List<String> l, String[] columns) {
for (int i = 0; i < columns.length; i++) {
String column = columns[i];
String col = Convert.toSBC(column);
l.add(col);
int width = col.length();
if (width > columnCharNumber.get(i)) {
columnCharNumber.set(i, width);
}
}
}
/**
* 获取表格字符串
*
* @return 表格字符串
*/
public String toString() {
StringBuilder sb = new StringBuilder();
fillBorder(sb);
for (List<String> headers : HEADER_LIST) {
for (int i = 0; i < headers.size(); i++) {
if (i == 0) {
sb.append('|');
}
String header = headers.get(i);
sb.append(Convert.toSBC(" "));
sb.append(header);
sb.append(Convert.toSBC(" "));
int l = header.length();
int lw = columnCharNumber.get(i);
if (lw > l) {
for (int j = 0; j < (lw - l); j++) {
sb.append(Convert.toSBC(" "));
}
}
sb.append('|');
}
sb.append('\n');
}
fillBorder(sb);
for (List<String> bodys : BODY_LIST) {
for (int i = 0; i < bodys.size(); i++) {
if (i == 0) {
sb.append('|');
}
String body = bodys.get(i);
sb.append(Convert.toSBC(" "));
sb.append(body);
sb.append(Convert.toSBC(" "));
int l = body.length();
int lw = columnCharNumber.get(i);
if (lw > l) {
for (int j = 0; j < (lw - l); j++) {
sb.append(Convert.toSBC(" "));
}
}
sb.append('|');
}
sb.append('\n');
}
fillBorder(sb);
return sb.toString();
}
/**
* 拼装边框
*
* @param sb
*/
private void fillBorder(StringBuilder sb) {
sb.append('*');
for (Integer width : columnCharNumber) {
sb.append(Convert.toSBC(StrUtil.fillAfter("", '-', width + 2)));
sb.append('*');
}
sb.append('\n');
}
/**
* 打印到控制台
*/
public void print() {
Console.print(toString());
}
}

View File

@ -31,9 +31,9 @@ import cn.hutool.core.util.StrUtil;
public class ObjectId {
/** 线程安全的下一个随机数,每次生成自增+1 */
private static final AtomicInteger nextInc = new AtomicInteger(RandomUtil.randomInt());
private static final AtomicInteger NEXT_INC = new AtomicInteger(RandomUtil.randomInt());
/** 机器信息 */
private static final int machine = getMachinePiece() | getProcessPiece();
private static final int MACHINE = getMachinePiece() | getProcessPiece();
/**
* 给定的字符串是否为有效的ObjectId
@ -77,8 +77,8 @@ public class ObjectId {
public static byte[] nextBytes() {
final ByteBuffer bb = ByteBuffer.wrap(new byte[12]);
bb.putInt((int) DateUtil.currentSeconds());// 4位
bb.putInt(machine);// 4位
bb.putInt(nextInc.getAndIncrement());// 4位
bb.putInt(MACHINE);// 4位
bb.putInt(NEXT_INC.getAndIncrement());// 4位
return bb.array();
}

View File

@ -49,7 +49,7 @@ public class UUID implements java.io.Serializable, Comparable<UUID> {
* @author looly
*/
private static class Holder {
static final SecureRandom numberGenerator = RandomUtil.getSecureRandom();
static final SecureRandom NUMBER_GENERATOR = RandomUtil.getSecureRandom();
}
/**
@ -117,7 +117,7 @@ public class UUID implements java.io.Serializable, Comparable<UUID> {
* @return 随机生成的 {@code UUID}
*/
public static UUID randomUUID(boolean isSecure) {
final Random ng = isSecure ? Holder.numberGenerator : RandomUtil.getRandom();
final Random ng = isSecure ? Holder.NUMBER_GENERATOR : RandomUtil.getRandom();
final byte[] randomBytes = new byte[16];
ng.nextBytes(randomBytes);

View File

@ -17,7 +17,7 @@ import java.util.Map;
*/
public class ActualTypeMapperPool {
private static final SimpleCache<Type, Map<Type, Type>> cache = new SimpleCache<>();
private static final SimpleCache<Type, Map<Type, Type>> CACHE = new SimpleCache<>();
/**
* 获取泛型变量和泛型实际类型的对应关系Map
@ -26,7 +26,7 @@ public class ActualTypeMapperPool {
* @return 泛型对应关系Map
*/
public static Map<Type, Type> get(Type type) {
return cache.get(type, () -> createTypeMap(type));
return CACHE.get(type, () -> createTypeMap(type));
}
/**

View File

@ -67,7 +67,7 @@ public class Money implements Serializable, Comparable<Money> {
* 此处是指货币的最小单位是货币的最常用单位
* 不同的币种有不同的元/分换算比例如人民币是100而日元为1
*/
private static final int[] centFactors = new int[]{1, 10, 100, 1000};
private static final int[] CENT_FACTORS = new int[]{1, 10, 100, 1000};
/**
* 金额以分为单位
@ -318,7 +318,7 @@ public class Money implements Serializable, Comparable<Money> {
* @return 本货币币种的元/分换算比率
*/
public int getCentFactor() {
return centFactors[currency.getDefaultFractionDigits()];
return CENT_FACTORS[currency.getDefaultFractionDigits()];
}
// 基本对象方法 ===================================================

View File

@ -11,41 +11,41 @@ import java.util.Map;
*/
public class MaskBit {
private static final Map<Integer, String> maskBitMap;
private static final Map<Integer, String> MASK_BIT_MAP;
static {
maskBitMap = new HashMap<>(32);
maskBitMap.put(1, "128.0.0.0");
maskBitMap.put(2, "192.0.0.0");
maskBitMap.put(3, "224.0.0.0");
maskBitMap.put(4, "240.0.0.0");
maskBitMap.put(5, "248.0.0.0");
maskBitMap.put(6, "252.0.0.0");
maskBitMap.put(7, "254.0.0.0");
maskBitMap.put(8, "255.0.0.0");
maskBitMap.put(9, "255.128.0.0");
maskBitMap.put(10, "255.192.0.0");
maskBitMap.put(11, "255.224.0.0");
maskBitMap.put(12, "255.240.0.0");
maskBitMap.put(13, "255.248.0.0");
maskBitMap.put(14, "255.252.0.0");
maskBitMap.put(15, "255.254.0.0");
maskBitMap.put(16, "255.255.0.0");
maskBitMap.put(17, "255.255.128.0");
maskBitMap.put(18, "255.255.192.0");
maskBitMap.put(19, "255.255.224.0");
maskBitMap.put(20, "255.255.240.0");
maskBitMap.put(21, "255.255.248.0");
maskBitMap.put(22, "255.255.252.0");
maskBitMap.put(23, "255.255.254.0");
maskBitMap.put(24, "255.255.255.0");
maskBitMap.put(25, "255.255.255.128");
maskBitMap.put(26, "255.255.255.192");
maskBitMap.put(27, "255.255.255.224");
maskBitMap.put(28, "255.255.255.240");
maskBitMap.put(29, "255.255.255.248");
maskBitMap.put(30, "255.255.255.252");
maskBitMap.put(31, "255.255.255.254");
maskBitMap.put(32, "255.255.255.255");
MASK_BIT_MAP = new HashMap<>(32);
MASK_BIT_MAP.put(1, "128.0.0.0");
MASK_BIT_MAP.put(2, "192.0.0.0");
MASK_BIT_MAP.put(3, "224.0.0.0");
MASK_BIT_MAP.put(4, "240.0.0.0");
MASK_BIT_MAP.put(5, "248.0.0.0");
MASK_BIT_MAP.put(6, "252.0.0.0");
MASK_BIT_MAP.put(7, "254.0.0.0");
MASK_BIT_MAP.put(8, "255.0.0.0");
MASK_BIT_MAP.put(9, "255.128.0.0");
MASK_BIT_MAP.put(10, "255.192.0.0");
MASK_BIT_MAP.put(11, "255.224.0.0");
MASK_BIT_MAP.put(12, "255.240.0.0");
MASK_BIT_MAP.put(13, "255.248.0.0");
MASK_BIT_MAP.put(14, "255.252.0.0");
MASK_BIT_MAP.put(15, "255.254.0.0");
MASK_BIT_MAP.put(16, "255.255.0.0");
MASK_BIT_MAP.put(17, "255.255.128.0");
MASK_BIT_MAP.put(18, "255.255.192.0");
MASK_BIT_MAP.put(19, "255.255.224.0");
MASK_BIT_MAP.put(20, "255.255.240.0");
MASK_BIT_MAP.put(21, "255.255.248.0");
MASK_BIT_MAP.put(22, "255.255.252.0");
MASK_BIT_MAP.put(23, "255.255.254.0");
MASK_BIT_MAP.put(24, "255.255.255.0");
MASK_BIT_MAP.put(25, "255.255.255.128");
MASK_BIT_MAP.put(26, "255.255.255.192");
MASK_BIT_MAP.put(27, "255.255.255.224");
MASK_BIT_MAP.put(28, "255.255.255.240");
MASK_BIT_MAP.put(29, "255.255.255.248");
MASK_BIT_MAP.put(30, "255.255.255.252");
MASK_BIT_MAP.put(31, "255.255.255.254");
MASK_BIT_MAP.put(32, "255.255.255.255");
}
/**
@ -55,6 +55,6 @@ public class MaskBit {
* @return 掩码
*/
public static String get(int maskBit) {
return maskBitMap.get(maskBit);
return MASK_BIT_MAP.get(maskBit);
}
}

View File

@ -20,12 +20,12 @@ import cn.hutool.core.swing.clipboard.ClipboardUtil;
*/
public class RobotUtil {
private static final Robot robot;
private static final Robot ROBOT;
private static int delay;
static {
try {
robot = new Robot();
ROBOT = new Robot();
} catch (AWTException e) {
throw new UtilException(e);
}
@ -50,7 +50,7 @@ public class RobotUtil {
* @since 4.5.7
*/
public static void mouseMove(int x, int y) {
robot.mouseMove(x, y);
ROBOT.mouseMove(x, y);
}
/**
@ -60,8 +60,8 @@ public class RobotUtil {
* @since 4.5.7
*/
public static void click() {
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
ROBOT.mousePress(InputEvent.BUTTON1_MASK);
ROBOT.mouseRelease(InputEvent.BUTTON1_MASK);
delay();
}
@ -72,8 +72,8 @@ public class RobotUtil {
* @since 4.5.7
*/
public static void rightClick() {
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
ROBOT.mousePress(InputEvent.BUTTON1_MASK);
ROBOT.mouseRelease(InputEvent.BUTTON1_MASK);
delay();
}
@ -84,7 +84,7 @@ public class RobotUtil {
* @since 4.5.7
*/
public static void mouseWheel(int wheelAmt) {
robot.mouseWheel(wheelAmt);
ROBOT.mouseWheel(wheelAmt);
delay();
}
@ -97,8 +97,8 @@ public class RobotUtil {
*/
public static void keyClick(int... keyCodes) {
for (int keyCode : keyCodes) {
robot.keyPress(keyCode);
robot.keyRelease(keyCode);
ROBOT.keyPress(keyCode);
ROBOT.keyRelease(keyCode);
}
delay();
}
@ -120,10 +120,10 @@ public class RobotUtil {
* @param key 按键
*/
public static void keyPressWithShift(int key) {
robot.keyPress(KeyEvent.VK_SHIFT);
robot.keyPress(key);
robot.keyRelease(key);
robot.keyRelease(KeyEvent.VK_SHIFT);
ROBOT.keyPress(KeyEvent.VK_SHIFT);
ROBOT.keyPress(key);
ROBOT.keyRelease(key);
ROBOT.keyRelease(KeyEvent.VK_SHIFT);
delay();
}
@ -133,10 +133,10 @@ public class RobotUtil {
* @param key 按键
*/
public static void keyPressWithCtrl(int key) {
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(key);
robot.keyRelease(key);
robot.keyRelease(KeyEvent.VK_CONTROL);
ROBOT.keyPress(KeyEvent.VK_CONTROL);
ROBOT.keyPress(key);
ROBOT.keyRelease(key);
ROBOT.keyRelease(KeyEvent.VK_CONTROL);
delay();
}
@ -146,10 +146,10 @@ public class RobotUtil {
* @param key 按键
*/
public static void keyPressWithAlt(int key) {
robot.keyPress(KeyEvent.VK_ALT);
robot.keyPress(key);
robot.keyRelease(key);
robot.keyRelease(KeyEvent.VK_ALT);
ROBOT.keyPress(KeyEvent.VK_ALT);
ROBOT.keyPress(key);
ROBOT.keyRelease(key);
ROBOT.keyRelease(KeyEvent.VK_ALT);
delay();
}
@ -180,7 +180,7 @@ public class RobotUtil {
* @return 截屏的图片
*/
public static BufferedImage captureScreen(Rectangle screenRect) {
return robot.createScreenCapture(screenRect);
return ROBOT.createScreenCapture(screenRect);
}
/**
@ -200,7 +200,7 @@ public class RobotUtil {
*/
private static void delay() {
if (delay > 0) {
robot.delay(delay);
ROBOT.delay(delay);
}
}
}

View File

@ -18,7 +18,6 @@ public class Html4Escape extends ReplacerChain {
{ "&", "&amp;" }, // & - ampersand
{ "<", "&lt;" }, // < - less-than
{ ">", "&gt;" }, // > - greater-than
{"\'", "&apos;"} // ' - quote
};
protected static final String[][] ISO8859_1_ESCAPE = { //

View File

@ -15,11 +15,14 @@ public class Html4Unescape extends ReplacerChain {
protected static final String[][] BASIC_UNESCAPE = InternalEscapeUtil.invert(Html4Escape.BASIC_ESCAPE);
protected static final String[][] ISO8859_1_UNESCAPE = InternalEscapeUtil.invert(Html4Escape.ISO8859_1_ESCAPE);
protected static final String[][] HTML40_EXTENDED_UNESCAPE = InternalEscapeUtil.invert(Html4Escape.HTML40_EXTENDED_ESCAPE);
// issue#1118
protected static final String[][] OTHER_UNESCAPE = new String[][]{new String[]{"&apos;", "'"}};
public Html4Unescape() {
addChain(new LookupReplacer(BASIC_UNESCAPE));
addChain(new LookupReplacer(ISO8859_1_UNESCAPE));
addChain(new LookupReplacer(HTML40_EXTENDED_UNESCAPE));
addChain(new LookupReplacer(OTHER_UNESCAPE));
addChain(new NumericEntityUnescaper());
}
}

View File

@ -1,7 +1,10 @@
package cn.hutool.core.util;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import java.util.Set;
/**
* Boolean类型相关工具类
*
@ -11,7 +14,7 @@ import cn.hutool.core.convert.Convert;
public class BooleanUtil {
/** 表示为真的字符串 */
private static final String[] TRUE_ARRAY = { "true", "yes", "y", "t", "ok", "1", "on", "", "", "", "", ""};
private static final Set<String> TRUE_SET = CollUtil.newHashSet("true", "yes", "y", "t", "ok", "1", "on", "", "", "", "", "");
/**
* 取相反值
@ -77,7 +80,7 @@ public class BooleanUtil {
public static boolean toBoolean(String valueStr) {
if (StrUtil.isNotBlank(valueStr)) {
valueStr = valueStr.trim().toLowerCase();
return ArrayUtil.contains(TRUE_ARRAY, valueStr);
return TRUE_SET.contains(valueStr);
}
return false;
}

View File

@ -11,24 +11,43 @@ import cn.hutool.core.text.ASCIIStrCache;
*/
public class CharUtil {
/** 字符常量:空格符 ' ' */
public static final char SPACE = ' ';
/** 字符常量:制表符 \t */
public static final char TAB = ' ';
/** 字符常量:点 . */
public static final char DOT = '.';
/** 字符常量:斜杠 / */
public static final char SLASH = '/';
/** 字符常量:反斜杠 \ */
public static final char BACKSLASH = '\\';
/** 字符常量:回车符 \r */
public static final char CR = '\r';
/** 字符常量:换行符 \n */
public static final char LF = '\n';
public static final char UNDERLINE = '_';
/** 字符常量:连接符 - */
public static final char DASHED = '-';
/** 字符常量:下划线 _ */
public static final char UNDERLINE = '_';
/** 字符常量:逗号 , */
public static final char COMMA = ',';
/** 字符常量:花括号(左) { */
public static final char DELIM_START = '{';
/** 字符常量:花括号(右) } */
public static final char DELIM_END = '}';
/** 字符常量:中括号(左) [ */
public static final char BRACKET_START = '[';
/** 字符常量:中括号(右) ] */
public static final char BRACKET_END = ']';
public static final char COLON = ':';
/** 字符常量:双引号 : */
public static final char DOUBLE_QUOTES = '"';
/** 字符常量:单引号 ' */
public static final char SINGLE_QUOTE = '\'';
/** 字符常量:与 &amp; */
public static final char AMP = '&';
/** 字符常量:冒号 : */
public static final char COLON = ':';
/** 字符常量:艾特 @ */
public static final char AT = '@';
/**

View File

@ -33,13 +33,13 @@ public class ClassLoaderUtil {
private static final char INNER_CLASS_SEPARATOR = '$';
/** 原始类型名和其class对应表例如int =》 int.class */
private static final Map<String, Class<?>> primitiveTypeNameMap = new ConcurrentHashMap<>(32);
private static final SimpleCache<String, Class<?>> classCache = new SimpleCache<>();
private static final Map<String, Class<?>> PRIMITIVE_TYPE_NAME_MAP = new ConcurrentHashMap<>(32);
private static final SimpleCache<String, Class<?>> CLASS_CACHE = new SimpleCache<>();
static {
List<Class<?>> primitiveTypes = new ArrayList<>(32);
// 加入原始类型
primitiveTypes.addAll(BasicType.primitiveWrapperMap.keySet());
primitiveTypes.addAll(BasicType.PRIMITIVE_WRAPPER_MAP.keySet());
// 加入原始类型数组类型
primitiveTypes.add(boolean[].class);
primitiveTypes.add(byte[].class);
@ -51,7 +51,7 @@ public class ClassLoaderUtil {
primitiveTypes.add(short[].class);
primitiveTypes.add(void.class);
for (Class<?> primitiveType : primitiveTypes) {
primitiveTypeNameMap.put(primitiveType.getName(), primitiveType);
PRIMITIVE_TYPE_NAME_MAP.put(primitiveType.getName(), primitiveType);
}
}
@ -150,7 +150,7 @@ public class ClassLoaderUtil {
// 加载原始类型和缓存中的类
Class<?> clazz = loadPrimitiveClass(name);
if (clazz == null) {
clazz = classCache.get(name);
clazz = CLASS_CACHE.get(name);
}
if (clazz != null) {
return clazz;
@ -188,7 +188,7 @@ public class ClassLoaderUtil {
}
// 加入缓存并返回
return classCache.put(name, clazz);
return CLASS_CACHE.put(name, clazz);
}
/**
@ -202,7 +202,7 @@ public class ClassLoaderUtil {
if (StrUtil.isNotBlank(name)) {
name = name.trim();
if (name.length() <= 8) {
result = primitiveTypeNameMap.get(name);
result = PRIMITIVE_TYPE_NAME_MAP.get(name);
}
}
return result;

View File

@ -713,7 +713,7 @@ public class ClassUtil {
if (null == clazz) {
return false;
}
return BasicType.wrapperPrimitiveMap.containsKey(clazz);
return BasicType.WRAPPER_PRIMITIVE_MAP.containsKey(clazz);
}
/**
@ -798,11 +798,11 @@ public class ClassUtil {
// 基本类型
if (targetType.isPrimitive()) {
// 原始类型
Class<?> resolvedPrimitive = BasicType.wrapperPrimitiveMap.get(sourceType);
Class<?> resolvedPrimitive = BasicType.WRAPPER_PRIMITIVE_MAP.get(sourceType);
return targetType.equals(resolvedPrimitive);
} else {
// 包装类型
Class<?> resolvedWrapper = BasicType.primitiveWrapperMap.get(sourceType);
Class<?> resolvedWrapper = BasicType.PRIMITIVE_WRAPPER_MAP.get(sourceType);
return resolvedWrapper != null && targetType.isAssignableFrom(resolvedWrapper);
}
}

View File

@ -38,7 +38,7 @@ public class IdcardUtil {
/**
* 每位加权因子
*/
private static final int[] power = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
private static final int[] POWER = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
/**
* 省市代码表
*/
@ -602,9 +602,9 @@ public class IdcardUtil {
*/
private static int getPowerSum(char[] iArr) {
int iSum = 0;
if (power.length == iArr.length) {
if (POWER.length == iArr.length) {
for (int i = 0; i < iArr.length; i++) {
iSum += Integer.parseInt(String.valueOf(iArr[i])) * power[i];
iSum += Integer.parseInt(String.valueOf(iArr[i])) * POWER[i];
}
}
return iSum;

View File

@ -43,6 +43,14 @@ public class NumberUtil {
*/
private static final int DEFAUT_DIV_SCALE = 10;
/**
* 0-20对应的阶乘超过20的阶乘会超过Long.MAX_VALUE
*/
private static final long[] FACTORIALS = new long[]{
1L, 1L, 2L, 6L, 24L, 120L, 720L, 5040L, 40320L, 362880L, 3628800L, 39916800L, 479001600L, 6227020800L,
87178291200L, 1307674368000L, 20922789888000L, 355687428096000L, 6402373705728000L, 121645100408832000L,
2432902008176640000L};
/**
* 提供精确的加法运算
*
@ -126,7 +134,7 @@ public class NumberUtil {
}
Number value = values[0];
BigDecimal result = new BigDecimal(null == value ? "0" : value.toString());
BigDecimal result = null == value ? BigDecimal.ZERO : new BigDecimal(value.toString());
for (int i = 1; i < values.length; i++) {
value = values[i];
if (null != value) {
@ -150,7 +158,7 @@ public class NumberUtil {
}
String value = values[0];
BigDecimal result = new BigDecimal(null == value ? "0" : value);
BigDecimal result = null == value ? BigDecimal.ZERO : new BigDecimal(value);
for (int i = 1; i < values.length; i++) {
value = values[i];
if (null != value) {
@ -266,7 +274,7 @@ public class NumberUtil {
}
Number value = values[0];
BigDecimal result = new BigDecimal(null == value ? "0" : value.toString());
BigDecimal result = null == value ? BigDecimal.ZERO : new BigDecimal(value.toString());
for (int i = 1; i < values.length; i++) {
value = values[i];
if (null != value) {
@ -290,7 +298,7 @@ public class NumberUtil {
}
String value = values[0];
BigDecimal result = new BigDecimal(null == value ? "0" : value);
BigDecimal result = null == value ? BigDecimal.ZERO : new BigDecimal(value);
for (int i = 1; i < values.length; i++) {
value = values[i];
if (null != value) {
@ -402,15 +410,15 @@ public class NumberUtil {
* @since 4.0.0
*/
public static BigDecimal mul(Number... values) {
if (ArrayUtil.isEmpty(values)) {
if (ArrayUtil.isEmpty(values) || ArrayUtil.hasNull(values)) {
return BigDecimal.ZERO;
}
Number value = values[0];
BigDecimal result = new BigDecimal(null == value ? "0" : value.toString());
BigDecimal result = new BigDecimal(value.toString());
for (int i = 1; i < values.length; i++) {
value = values[i];
result = result.multiply(new BigDecimal(null == value ? "0" : value.toString()));
result = result.multiply(new BigDecimal(value.toString()));
}
return result;
}
@ -436,18 +444,15 @@ public class NumberUtil {
* @since 4.0.0
*/
public static BigDecimal mul(String... values) {
if (ArrayUtil.isEmpty(values)) {
if (ArrayUtil.isEmpty(values) || ArrayUtil.hasNull(values)) {
return BigDecimal.ZERO;
}
String value = values[0];
BigDecimal result = new BigDecimal(null == value ? "0" : value);
BigDecimal result = new BigDecimal(values[0]);
for (int i = 1; i < values.length; i++) {
value = values[i];
if (null != value) {
result = result.multiply(new BigDecimal(value));
}
result = result.multiply(new BigDecimal(values[i]));
}
return result;
}
@ -460,17 +465,13 @@ public class NumberUtil {
* @since 4.0.0
*/
public static BigDecimal mul(BigDecimal... values) {
if (ArrayUtil.isEmpty(values)) {
if (ArrayUtil.isEmpty(values) || ArrayUtil.hasNull(values)) {
return BigDecimal.ZERO;
}
BigDecimal value = values[0];
BigDecimal result = null == value ? BigDecimal.ZERO : value;
BigDecimal result = values[0];
for (int i = 1; i < values.length; i++) {
value = values[i];
if (null != value) {
result = result.multiply(value);
}
result = result.multiply(values[i]);
}
return result;
}
@ -755,13 +756,13 @@ public class NumberUtil {
/**
* 补充Math.ceilDiv() JDK8中添加了和Math.floorDiv()但却没有ceilDiv()
*
* @param v1 被除数
* @param v2 除数
* @param v1 被除数
* @param v2 除数
* @return 两个参数的商
* @since 5.3.3
*/
public static int ceilDiv(int v1, int v2) {
return (int)Math.ceil((double)v1 / v2);
return (int) Math.ceil((double) v1 / v2);
}
// ------------------------------------------------------------------------------------------- round
@ -1419,24 +1420,42 @@ public class NumberUtil {
// ------------------------------------------------------------------------------------------- others
/**
* 计算阶乘
* 计算范围阶乘
* <p>
* n! = n * (n-1) * ... * end
* factorial(start, end) = start * (start - 1) * ... * (end - 1)
* </p>
*
* @param start 阶乘起始
* @param end 阶乘结束必须小于起始
* @param start 阶乘起始包含
* @param end 阶乘结束必须小于起始不包括
* @return 结果
* @since 4.1.0
*/
public static long factorial(long start, long end) {
// 负数没有阶乘
if (start < 0 || end < 0) {
throw new IllegalArgumentException(StrUtil.format("Factorial start and end both must be >= 0, but got start={}, end={}", start, end));
}
if (0L == start || start == end) {
return 1L;
}
if (start < end) {
return 0L;
}
return start * factorial(start - 1, end);
return factorialMultiplyAndCheck(start, factorial(start - 1, end));
}
/**
* 计算范围阶乘中校验中间的计算是否存在溢出factorial提前做了负数和0的校验因此这里没有校验数字的正负
*
* @param a 乘数
* @param b 被乘数
* @return 如果 a * b的结果没有溢出直接返回否则抛出异常
*/
private static long factorialMultiplyAndCheck(long a, long b) {
if (a <= Long.MAX_VALUE / b) {
return a * b;
}
throw new IllegalArgumentException(StrUtil.format("Overflow in multiplication: {} * {}", a, b));
}
/**
@ -1449,7 +1468,10 @@ public class NumberUtil {
* @return 结果
*/
public static long factorial(long n) {
return factorial(n, 1);
if (n < 0 || n > 20) {
throw new IllegalArgumentException(StrUtil.format("Factorial must have n >= 0 and n <= 20 for n!, but got n = {}", n));
}
return FACTORIALS[(int) n];
}
/**
@ -1713,10 +1735,11 @@ public class NumberUtil {
*/
public static boolean equals(BigDecimal bigNum1, BigDecimal bigNum2) {
//noinspection NumberEquality
if (bigNum1 == bigNum2){
if (bigNum1 == bigNum2) {
// 如果用户传入同一对象省略compareTo以提高性能
return true;
}
if (bigNum1==null || bigNum2==null){
if (bigNum1 == null || bigNum2 == null) {
return false;
}
return 0 == bigNum1.compareTo(bigNum2);
@ -1814,7 +1837,7 @@ public class NumberUtil {
*
* @param numberArray 数字数组
* @return 最小值
* @see ArrayUtil#min(Comparable[])
* @see ArrayUtil#min(Comparable[])
* @since 5.0.8
*/
public static BigDecimal min(BigDecimal... numberArray) {
@ -2163,6 +2186,17 @@ public class NumberUtil {
return number.pow(n);
}
/**
* 判断一个整数是否是2的幂
*
* @param n 待验证的整数
* @return 如果n是2的幂返回true, 反之返回false
*/
public static boolean isPowerOfTwo(long n) {
return (n > 0) && ((n & (n - 1)) == 0);
}
/**
* 解析转换数字字符串为int型数字规则如下
*

View File

@ -522,10 +522,11 @@ public class RandomUtil {
*
* @return 随机颜色
* @since 4.1.5
* @deprecated 使用{@link ImagUtil#randomColor()}
*/
public static Color randomColor() {
public static Color randomColor() {
final Random random = getRandom();
return new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255));
return new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
/**

View File

@ -34,62 +34,125 @@ public class StrUtil {
public static final int INDEX_NOT_FOUND = -1;
/** 字符常量:空格符 ' ' */
public static final char C_SPACE = CharUtil.SPACE;
/** 字符常量:制表符 \t */
public static final char C_TAB = CharUtil.TAB;
/** 字符常量:点 . */
public static final char C_DOT = CharUtil.DOT;
/** 字符常量:斜杠 / */
public static final char C_SLASH = CharUtil.SLASH;
/** 字符常量:反斜杠 \ */
public static final char C_BACKSLASH = CharUtil.BACKSLASH;
/** 字符常量:回车符 \r */
public static final char C_CR = CharUtil.CR;
/** 字符常量:换行符 \n */
public static final char C_LF = CharUtil.LF;
/** 字符常量:下划线 _ */
public static final char C_UNDERLINE = CharUtil.UNDERLINE;
/** 字符常量:逗号 , */
public static final char C_COMMA = CharUtil.COMMA;
/** 字符常量:花括号(左) { */
public static final char C_DELIM_START = CharUtil.DELIM_START;
/** 字符常量:花括号(右) } */
public static final char C_DELIM_END = CharUtil.DELIM_END;
/** 字符常量:中括号(左) [ */
public static final char C_BRACKET_START = CharUtil.BRACKET_START;
/** 字符常量:中括号(右) ] */
public static final char C_BRACKET_END = CharUtil.BRACKET_END;
/** 字符常量:冒号 : */
public static final char C_COLON = CharUtil.COLON;
/** 字符常量:艾特 @ */
public static final char C_AT = CharUtil.AT;
/** 字符串常量:空格符 ' ' */
public static final String SPACE = " ";
/** 字符串常量:制表符 \t */
public static final String TAB = " ";
/** 字符串常量:点 . */
public static final String DOT = ".";
/**
* 字符串常量双点 ..
* 用途作为指向上级文件夹的路径 "../path"
*/
public static final String DOUBLE_DOT = "..";
/** 字符串常量:斜杠 / */
public static final String SLASH = "/";
/** 字符串常量:反斜杠 \ */
public static final String BACKSLASH = "\\";
/** 字符串常量:空字符串 "" */
public static final String EMPTY = "";
/**
* 字符串常量"null"
* 注意"null" != null
*/
public static final String NULL = "null";
/**
* 字符串常量回车符 \r
* 解释该字符常用于表示 Linux 系统和 MacOS 系统下的文本换行
*/
public static final String CR = "\r";
/** 字符串常量:换行符 \n */
public static final String LF = "\n";
/**
* 字符串常量Windows 换行 \r\n
* 解释该字符串常用于表示 Windows 系统下的文本换行
*/
public static final String CRLF = "\r\n";
/** 字符串常量:下划线 _ */
public static final String UNDERLINE = "_";
/** 字符串常量:减号(中划线) - */
public static final String DASHED = "-";
/** 字符串常量:逗号 , */
public static final String COMMA = ",";
/** 字符串常量:花括号(左) { */
public static final String DELIM_START = "{";
/** 字符串常量:花括号(右) } */
public static final String DELIM_END = "}";
/** 字符串常量:中括号(左) [ */
public static final String BRACKET_START = "[";
/** 字符串常量:中括号(右) ] */
public static final String BRACKET_END = "]";
/** 字符串常量:冒号 : */
public static final String COLON = ":";
/** 字符串常量:艾特 @ */
public static final String AT = "@";
/** 字符串常量HTML 空格转义 */
public static final String HTML_NBSP = "&nbsp;";
/** 字符串常量HTML And 符转义 &amp; */
public static final String HTML_AMP = "&amp;";
/** 字符串常量HTML 双引号转义 " */
public static final String HTML_QUOTE = "&quot;";
/** 字符串常量HTML 单引号转义 ' */
public static final String HTML_APOS = "&apos;";
/** 字符串常量HTML 小于号转义 &lt; */
public static final String HTML_LT = "&lt;";
/** 字符串常量HTML 大于号转义 &gt; */
public static final String HTML_GT = "&gt;";
/** 字符串常量:空 JSON "{}" */
public static final String EMPTY_JSON = "{}";
// ------------------------------------------------------------------------ Blank
/**
* 字符串是否为空白 空白的定义如下 <br>
* 1为null <br>
* 2为不可见字符如空格<br>
* 3""<br>
* <p>字符串是否为空白空白的定义如下</p>
* <ol>
* <li>{@code null}</li>
* <li>空字符串{@code ""}</li>
* <li>空格全角空格制表符换行符等不可见字符</li>
* </ol>
*
* <p></p>
* <ul>
* <li>{@code StrUtil.isBlank(null) // true}</li>
* <li>{@code StrUtil.isBlank("") // true}</li>
* <li>{@code StrUtil.isBlank(" \t\n") // true}</li>
* <li>{@code StrUtil.isBlank("abc") // false}</li>
* </ul>
*
* @param str 被检测的字符串
* @return 是否为空
* @return 若为空白则返回 true
*/
public static boolean isBlank(CharSequence str) {
int length;
@ -109,13 +172,25 @@ public class StrUtil {
}
/**
* 如果对象是字符串是否为空白空白的定义如下 <br>
* 1为null <br>
* 2为不可见字符如空格<br>
* 3""<br>
* <p>如果对象是字符串是否为空白空白的定义如下</p>
* <ol>
* <li>{@code null}</li>
* <li>空字符串{@code ""}</li>
* <li>空格全角空格制表符换行符等不可见字符</li>
* </ol>
*
* <p></p>
* <ul>
* <li>{@code StrUtil.isBlankIfStr(null) // true}</li>
* <li>{@code StrUtil.isBlankIfStr("") // true}</li>
* <li>{@code StrUtil.isBlankIfStr(" \t\n") // true}</li>
* <li>{@code StrUtil.isBlankIfStr("abc") // false}</li>
* </ul>
*
* @param obj 对象
* @return 如果为字符串是否为空串
*
* @see StrUtil#isBlank(CharSequence)
* @since 3.3.0
*/
public static boolean isBlankIfStr(Object obj) {
@ -4152,7 +4227,7 @@ public class StrUtil {
}
/**
* 计算个字符串的相似度百分比
* 计算个字符串的相似度百分比
*
* @param str1 字符串1
* @param str2 字符串2

View File

@ -1,255 +1,272 @@
package cn.hutool.core.util;
import org.junit.Assert;
import org.junit.Test;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* {@link NumberUtil} 单元测试类
*
* @author Looly
*
*/
public class NumberUtilTest {
@Test
public void addTest() {
Float a = 3.15f;
Double b = 4.22;
double result = NumberUtil.add(a, b).doubleValue();
Assert.assertEquals(7.37, result, 2);
}
@Test
public void addTest2() {
double a = 3.15f;
double b = 4.22;
double result = NumberUtil.add(a, b);
Assert.assertEquals(7.37, result, 2);
}
@Test
public void addTest3() {
float a = 3.15f;
double b = 4.22;
double result = NumberUtil.add(a, b, a, b).doubleValue();
Assert.assertEquals(14.74, result, 2);
}
@Test
public void addTest4() {
BigDecimal result = NumberUtil.add(new BigDecimal("133"), new BigDecimal("331"));
Assert.assertEquals(new BigDecimal("464"), result);
}
@Test
public void isIntegerTest() {
Assert.assertTrue(NumberUtil.isInteger("-12"));
Assert.assertTrue(NumberUtil.isInteger("256"));
Assert.assertTrue(NumberUtil.isInteger("0256"));
Assert.assertTrue(NumberUtil.isInteger("0"));
Assert.assertFalse(NumberUtil.isInteger("23.4"));
}
@Test
public void isLongTest() {
Assert.assertTrue(NumberUtil.isLong("-12"));
Assert.assertTrue(NumberUtil.isLong("256"));
Assert.assertTrue(NumberUtil.isLong("0256"));
Assert.assertTrue(NumberUtil.isLong("0"));
Assert.assertFalse(NumberUtil.isLong("23.4"));
}
@Test
public void isNumberTest() {
Assert.assertTrue(NumberUtil.isNumber("28.55"));
Assert.assertTrue(NumberUtil.isNumber("0"));
Assert.assertTrue(NumberUtil.isNumber("+100.10"));
Assert.assertTrue(NumberUtil.isNumber("-22.022"));
Assert.assertTrue(NumberUtil.isNumber("0X22"));
}
@Test
public void divTest() {
double result = NumberUtil.div(0, 1);
Assert.assertEquals(0.0, result, 0);
}
@Test
public void roundTest() {
// 四舍
String round1 = NumberUtil.roundStr(2.674, 2);
String round2 = NumberUtil.roundStr("2.674", 2);
Assert.assertEquals("2.67", round1);
Assert.assertEquals("2.67", round2);
// 五入
String round3 = NumberUtil.roundStr(2.675, 2);
String round4 = NumberUtil.roundStr("2.675", 2);
Assert.assertEquals("2.68", round3);
Assert.assertEquals("2.68", round4);
// 四舍六入五成双
String round31 = NumberUtil.roundStr(4.245, 2, RoundingMode.HALF_EVEN);
String round41 = NumberUtil.roundStr("4.2451", 2, RoundingMode.HALF_EVEN);
Assert.assertEquals("4.24", round31);
Assert.assertEquals("4.25", round41);
// 补0
String round5 = NumberUtil.roundStr(2.6005, 2);
String round6 = NumberUtil.roundStr("2.6005", 2);
Assert.assertEquals("2.60", round5);
Assert.assertEquals("2.60", round6);
// 补0
String round7 = NumberUtil.roundStr(2.600, 2);
String round8 = NumberUtil.roundStr("2.600", 2);
Assert.assertEquals("2.60", round7);
Assert.assertEquals("2.60", round8);
}
@Test
public void roundStrTest() {
String roundStr = NumberUtil.roundStr(2.647, 2);
Assert.assertEquals(roundStr, "2.65");
}
@Test
public void roundHalfEvenTest() {
String roundStr = NumberUtil.roundHalfEven(4.245, 2).toString();
Assert.assertEquals(roundStr, "4.24");
roundStr = NumberUtil.roundHalfEven(4.2450, 2).toString();
Assert.assertEquals(roundStr, "4.24");
roundStr = NumberUtil.roundHalfEven(4.2451, 2).toString();
Assert.assertEquals(roundStr, "4.25");
roundStr = NumberUtil.roundHalfEven(4.2250, 2).toString();
Assert.assertEquals(roundStr, "4.22");
roundStr = NumberUtil.roundHalfEven(1.2050, 2).toString();
Assert.assertEquals(roundStr, "1.20");
roundStr = NumberUtil.roundHalfEven(1.2150, 2).toString();
Assert.assertEquals(roundStr, "1.22");
roundStr = NumberUtil.roundHalfEven(1.2250, 2).toString();
Assert.assertEquals(roundStr, "1.22");
roundStr = NumberUtil.roundHalfEven(1.2350, 2).toString();
Assert.assertEquals(roundStr, "1.24");
roundStr = NumberUtil.roundHalfEven(1.2450, 2).toString();
Assert.assertEquals(roundStr, "1.24");
roundStr = NumberUtil.roundHalfEven(1.2550, 2).toString();
Assert.assertEquals(roundStr, "1.26");
roundStr = NumberUtil.roundHalfEven(1.2650, 2).toString();
Assert.assertEquals(roundStr, "1.26");
roundStr = NumberUtil.roundHalfEven(1.2750, 2).toString();
Assert.assertEquals(roundStr, "1.28");
roundStr = NumberUtil.roundHalfEven(1.2850, 2).toString();
Assert.assertEquals(roundStr, "1.28");
roundStr = NumberUtil.roundHalfEven(1.2950, 2).toString();
Assert.assertEquals(roundStr, "1.30");
}
@Test
public void decimalFormatTest() {
long c = 299792458;// 光速
String format = NumberUtil.decimalFormat(",###", c);
Assert.assertEquals("299,792,458", format);
}
@Test
public void decimalFormatMoneyTest() {
double c = 299792400.543534534;
String format = NumberUtil.decimalFormatMoney(c);
Assert.assertEquals("299,792,400.54", format);
double value = 0.5;
String money = NumberUtil.decimalFormatMoney(value);
Assert.assertEquals("0.50", money);
}
@Test
public void equalsTest() {
Assert.assertTrue(NumberUtil.equals(new BigDecimal("0.00"), BigDecimal.ZERO));
}
@Test
public void formatPercentTest() {
String str = NumberUtil.formatPercent(0.33543545, 2);
Assert.assertEquals("33.54%", str);
}
@Test
public void toBigDecimalTest() {
double a = 3.14;
BigDecimal bigDecimal = NumberUtil.toBigDecimal(a);
Assert.assertEquals("3.14", bigDecimal.toString());
}
@Test
public void maxTest() {
int max = NumberUtil.max(5,4,3,6,1);
Assert.assertEquals(6, max);
}
@Test
public void minTest() {
int min = NumberUtil.min(5,4,3,6,1);
Assert.assertEquals(1, min);
}
@Test
public void parseIntTest() {
int v1 = NumberUtil.parseInt("0xFF");
Assert.assertEquals(255, v1);
int v2 = NumberUtil.parseInt("010");
Assert.assertEquals(10, v2);
int v3 = NumberUtil.parseInt("10");
Assert.assertEquals(10, v3);
int v4 = NumberUtil.parseInt(" ");
Assert.assertEquals(0, v4);
int v5 = NumberUtil.parseInt("10F");
Assert.assertEquals(10, v5);
int v6 = NumberUtil.parseInt("22.4D");
Assert.assertEquals(22, v6);
int v7 = NumberUtil.parseInt("0");
Assert.assertEquals(0, v7);
}
@Test
public void parseLongTest() {
long v1 = NumberUtil.parseLong("0xFF");
Assert.assertEquals(255L, v1);
long v2 = NumberUtil.parseLong("010");
Assert.assertEquals(10L, v2);
long v3 = NumberUtil.parseLong("10");
Assert.assertEquals(10L, v3);
long v4 = NumberUtil.parseLong(" ");
Assert.assertEquals(0L, v4);
long v5 = NumberUtil.parseLong("10F");
Assert.assertEquals(10L, v5);
long v6 = NumberUtil.parseLong("22.4D");
Assert.assertEquals(22L, v6);
}
@Test
public void factorialTest(){
long factorial = NumberUtil.factorial(0);
Assert.assertEquals(1, factorial);
factorial = NumberUtil.factorial(5, 0);
Assert.assertEquals(120, factorial);
factorial = NumberUtil.factorial(5, 1);
Assert.assertEquals(120, factorial);
}
@Test
public void mulTest(){
final BigDecimal mul = NumberUtil.mul(new BigDecimal("10"), null);
Assert.assertEquals(BigDecimal.ZERO, mul);
}
}
package cn.hutool.core.util;
import org.junit.Assert;
import org.junit.Test;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* {@link NumberUtil} 单元测试类
*
* @author Looly
*
*/
public class NumberUtilTest {
@Test
public void addTest() {
Float a = 3.15f;
Double b = 4.22;
double result = NumberUtil.add(a, b).doubleValue();
Assert.assertEquals(7.37, result, 2);
}
@Test
public void addTest2() {
double a = 3.15f;
double b = 4.22;
double result = NumberUtil.add(a, b);
Assert.assertEquals(7.37, result, 2);
}
@Test
public void addTest3() {
float a = 3.15f;
double b = 4.22;
double result = NumberUtil.add(a, b, a, b).doubleValue();
Assert.assertEquals(14.74, result, 2);
}
@Test
public void addTest4() {
BigDecimal result = NumberUtil.add(new BigDecimal("133"), new BigDecimal("331"));
Assert.assertEquals(new BigDecimal("464"), result);
}
@Test
public void isIntegerTest() {
Assert.assertTrue(NumberUtil.isInteger("-12"));
Assert.assertTrue(NumberUtil.isInteger("256"));
Assert.assertTrue(NumberUtil.isInteger("0256"));
Assert.assertTrue(NumberUtil.isInteger("0"));
Assert.assertFalse(NumberUtil.isInteger("23.4"));
}
@Test
public void isLongTest() {
Assert.assertTrue(NumberUtil.isLong("-12"));
Assert.assertTrue(NumberUtil.isLong("256"));
Assert.assertTrue(NumberUtil.isLong("0256"));
Assert.assertTrue(NumberUtil.isLong("0"));
Assert.assertFalse(NumberUtil.isLong("23.4"));
}
@Test
public void isNumberTest() {
Assert.assertTrue(NumberUtil.isNumber("28.55"));
Assert.assertTrue(NumberUtil.isNumber("0"));
Assert.assertTrue(NumberUtil.isNumber("+100.10"));
Assert.assertTrue(NumberUtil.isNumber("-22.022"));
Assert.assertTrue(NumberUtil.isNumber("0X22"));
}
@Test
public void divTest() {
double result = NumberUtil.div(0, 1);
Assert.assertEquals(0.0, result, 0);
}
@Test
public void roundTest() {
// 四舍
String round1 = NumberUtil.roundStr(2.674, 2);
String round2 = NumberUtil.roundStr("2.674", 2);
Assert.assertEquals("2.67", round1);
Assert.assertEquals("2.67", round2);
// 五入
String round3 = NumberUtil.roundStr(2.675, 2);
String round4 = NumberUtil.roundStr("2.675", 2);
Assert.assertEquals("2.68", round3);
Assert.assertEquals("2.68", round4);
// 四舍六入五成双
String round31 = NumberUtil.roundStr(4.245, 2, RoundingMode.HALF_EVEN);
String round41 = NumberUtil.roundStr("4.2451", 2, RoundingMode.HALF_EVEN);
Assert.assertEquals("4.24", round31);
Assert.assertEquals("4.25", round41);
// 补0
String round5 = NumberUtil.roundStr(2.6005, 2);
String round6 = NumberUtil.roundStr("2.6005", 2);
Assert.assertEquals("2.60", round5);
Assert.assertEquals("2.60", round6);
// 补0
String round7 = NumberUtil.roundStr(2.600, 2);
String round8 = NumberUtil.roundStr("2.600", 2);
Assert.assertEquals("2.60", round7);
Assert.assertEquals("2.60", round8);
}
@Test
public void roundStrTest() {
String roundStr = NumberUtil.roundStr(2.647, 2);
Assert.assertEquals(roundStr, "2.65");
}
@Test
public void roundHalfEvenTest() {
String roundStr = NumberUtil.roundHalfEven(4.245, 2).toString();
Assert.assertEquals(roundStr, "4.24");
roundStr = NumberUtil.roundHalfEven(4.2450, 2).toString();
Assert.assertEquals(roundStr, "4.24");
roundStr = NumberUtil.roundHalfEven(4.2451, 2).toString();
Assert.assertEquals(roundStr, "4.25");
roundStr = NumberUtil.roundHalfEven(4.2250, 2).toString();
Assert.assertEquals(roundStr, "4.22");
roundStr = NumberUtil.roundHalfEven(1.2050, 2).toString();
Assert.assertEquals(roundStr, "1.20");
roundStr = NumberUtil.roundHalfEven(1.2150, 2).toString();
Assert.assertEquals(roundStr, "1.22");
roundStr = NumberUtil.roundHalfEven(1.2250, 2).toString();
Assert.assertEquals(roundStr, "1.22");
roundStr = NumberUtil.roundHalfEven(1.2350, 2).toString();
Assert.assertEquals(roundStr, "1.24");
roundStr = NumberUtil.roundHalfEven(1.2450, 2).toString();
Assert.assertEquals(roundStr, "1.24");
roundStr = NumberUtil.roundHalfEven(1.2550, 2).toString();
Assert.assertEquals(roundStr, "1.26");
roundStr = NumberUtil.roundHalfEven(1.2650, 2).toString();
Assert.assertEquals(roundStr, "1.26");
roundStr = NumberUtil.roundHalfEven(1.2750, 2).toString();
Assert.assertEquals(roundStr, "1.28");
roundStr = NumberUtil.roundHalfEven(1.2850, 2).toString();
Assert.assertEquals(roundStr, "1.28");
roundStr = NumberUtil.roundHalfEven(1.2950, 2).toString();
Assert.assertEquals(roundStr, "1.30");
}
@Test
public void decimalFormatTest() {
long c = 299792458;// 光速
String format = NumberUtil.decimalFormat(",###", c);
Assert.assertEquals("299,792,458", format);
}
@Test
public void decimalFormatMoneyTest() {
double c = 299792400.543534534;
String format = NumberUtil.decimalFormatMoney(c);
Assert.assertEquals("299,792,400.54", format);
double value = 0.5;
String money = NumberUtil.decimalFormatMoney(value);
Assert.assertEquals("0.50", money);
}
@Test
public void equalsTest() {
Assert.assertTrue(NumberUtil.equals(new BigDecimal("0.00"), BigDecimal.ZERO));
}
@Test
public void formatPercentTest() {
String str = NumberUtil.formatPercent(0.33543545, 2);
Assert.assertEquals("33.54%", str);
}
@Test
public void toBigDecimalTest() {
double a = 3.14;
BigDecimal bigDecimal = NumberUtil.toBigDecimal(a);
Assert.assertEquals("3.14", bigDecimal.toString());
}
@Test
public void maxTest() {
int max = NumberUtil.max(5,4,3,6,1);
Assert.assertEquals(6, max);
}
@Test
public void minTest() {
int min = NumberUtil.min(5,4,3,6,1);
Assert.assertEquals(1, min);
}
@Test
public void parseIntTest() {
int v1 = NumberUtil.parseInt("0xFF");
Assert.assertEquals(255, v1);
int v2 = NumberUtil.parseInt("010");
Assert.assertEquals(10, v2);
int v3 = NumberUtil.parseInt("10");
Assert.assertEquals(10, v3);
int v4 = NumberUtil.parseInt(" ");
Assert.assertEquals(0, v4);
int v5 = NumberUtil.parseInt("10F");
Assert.assertEquals(10, v5);
int v6 = NumberUtil.parseInt("22.4D");
Assert.assertEquals(22, v6);
int v7 = NumberUtil.parseInt("0");
Assert.assertEquals(0, v7);
}
@Test
public void parseLongTest() {
long v1 = NumberUtil.parseLong("0xFF");
Assert.assertEquals(255L, v1);
long v2 = NumberUtil.parseLong("010");
Assert.assertEquals(10L, v2);
long v3 = NumberUtil.parseLong("10");
Assert.assertEquals(10L, v3);
long v4 = NumberUtil.parseLong(" ");
Assert.assertEquals(0L, v4);
long v5 = NumberUtil.parseLong("10F");
Assert.assertEquals(10L, v5);
long v6 = NumberUtil.parseLong("22.4D");
Assert.assertEquals(22L, v6);
}
@Test
public void factorialTest(){
long factorial = NumberUtil.factorial(0);
Assert.assertEquals(1, factorial);
Assert.assertEquals(1L, NumberUtil.factorial(1));
Assert.assertEquals(1307674368000L, NumberUtil.factorial(15));
Assert.assertEquals(2432902008176640000L, NumberUtil.factorial(20));
factorial = NumberUtil.factorial(5, 0);
Assert.assertEquals(120, factorial);
factorial = NumberUtil.factorial(5, 1);
Assert.assertEquals(120, factorial);
Assert.assertEquals(5, NumberUtil.factorial(5, 4));
Assert.assertEquals(2432902008176640000L, NumberUtil.factorial(20, 0));
}
@Test
public void mulTest(){
final BigDecimal mul = NumberUtil.mul(new BigDecimal("10"), null);
Assert.assertEquals(BigDecimal.ZERO, mul);
}
@Test
public void isPowerOfTwoTest() {
Assert.assertEquals(false, NumberUtil.isPowerOfTwo(-1));
Assert.assertEquals(true, NumberUtil.isPowerOfTwo(16));
Assert.assertEquals(true, NumberUtil.isPowerOfTwo(65536));
Assert.assertEquals(true, NumberUtil.isPowerOfTwo(1));
Assert.assertEquals(false, NumberUtil.isPowerOfTwo(17));
}
}

View File

@ -1,12 +1,12 @@
package cn.hutool.cron.listener;
import cn.hutool.cron.TaskExecutor;
import cn.hutool.log.StaticLog;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import cn.hutool.cron.TaskExecutor;
import cn.hutool.log.StaticLog;
/**
* 监听调度器统一管理监听
* @author Looly
@ -49,9 +49,9 @@ public class TaskListenerManager implements Serializable {
synchronized (listeners) {
int size = listeners.size();
TaskListener listener;
for (int i = 0; i < size; i++) {
listener = listeners.get(i);
if(null != listener){
for (TaskListener taskListener : listeners) {
listener = taskListener;
if (null != listener) {
listener.onStart(executor);
}
}
@ -65,8 +65,7 @@ public class TaskListenerManager implements Serializable {
public void notifyTaskSucceeded(TaskExecutor executor) {
synchronized (listeners) {
int size = listeners.size();
for (int i = 0; i < size; i++) {
TaskListener listenerl = listeners.get(i);
for (TaskListener listenerl : listeners) {
listenerl.onSucceeded(executor);
}
}
@ -82,8 +81,7 @@ public class TaskListenerManager implements Serializable {
synchronized (listeners) {
int size = listeners.size();
if(size > 0){
for (int i = 0; i < size; i++) {
TaskListener listenerl = listeners.get(i);
for (TaskListener listenerl : listeners) {
listenerl.onFailed(executor, exception);
}
}else{

View File

@ -1,12 +1,13 @@
package cn.hutool.cron.demo;
import org.junit.Ignore;
import org.junit.Test;
import cn.hutool.core.lang.Console;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.TaskExecutor;
import cn.hutool.cron.listener.TaskListener;
import cn.hutool.cron.task.Task;
import org.junit.Ignore;
import org.junit.Test;
/**
* 定时任务样例
@ -38,6 +39,23 @@ public class CronTest {
@Test
@Ignore
public void cronTest2() {
CronUtil.getScheduler().addListener(new TaskListener() {
@Override
public void onStart(TaskExecutor executor) {
Console.log("Listen task start!");
}
@Override
public void onSucceeded(TaskExecutor executor) {
}
@Override
public void onFailed(TaskExecutor executor, Throwable exception) {
}
});
// 支持秒级别定时任务
CronUtil.setMatchSecond(true);
CronUtil.start();

View File

@ -1,5 +1,6 @@
package cn.hutool.dfa;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
@ -13,8 +14,7 @@ import java.util.List;
*
*/
public final class SensitiveUtil {
// private static final Log log = LogFactory.get();
public static final char DEFAULT_SEPARATOR = StrUtil.C_COMMA;
private static final WordTree sensitiveTree = new WordTree();
@ -72,6 +72,19 @@ public final class SensitiveUtil {
init(sensitiveWords, DEFAULT_SEPARATOR, isAsync);
}
/**
* 设置字符过滤规则通过定义字符串过滤规则过滤不需要的字符<br>
* 当accept为false时此字符不参与匹配
*
* @param charFilter 过滤函数
* @since 5.4.4
*/
public static void setCharFilter(Filter<Character> charFilter) {
if(charFilter != null) {
sensitiveTree.setCharFilter(charFilter);
}
}
/**
* 是否包含敏感词
* @param text 文本

View File

@ -11,7 +11,7 @@ import cn.hutool.core.collection.CollUtil;
*/
public class StopChar {
/** 不需要处理的词,如标点符号、空格等 */
public static final Set<Character> STOP_WORD = CollUtil.newHashSet(new Character[] { ' ', '\'', '、', '。', //
public static final Set<Character> STOP_WORD = CollUtil.newHashSet(' ', '\'', '、', '。', //
'·', 'ˉ', 'ˇ', '々', '—', '', '‖', '…', '', '', '“', '”', '', '', '〈', '〉', '《', '》', '「', '」', '『', //
'』', '〖', '〗', '【', '】', '±', '', '', '×', '÷', '∧', '', '∑', '∏', '', '∩', '∈', '√', '⊥', '⊙', '∫', //
'∮', '≡', '≌', '≈', '∽', '∝', '≠', '≮', '≯', '≤', '≥', '∞', '', '∵', '∴', '∷', '♂', '♀', '°', '', '〃', //
@ -26,7 +26,8 @@ public class StopChar {
'Υ', 'Φ', 'Χ', 'Ψ', 'Ω', 'α', 'β', 'γ', 'δ', 'ε', 'ζ', 'η', 'θ', 'ι', 'κ', 'λ', 'μ', 'ν', 'ξ', 'ο', 'π', //
'ρ', 'σ', 'τ', 'υ', 'φ', 'χ', 'ψ', 'ω', '', '', '', '', '', '﹊', '', '╭', '╮', '╰', '╯', '', '_', //
'', '^', '', '^', '', '', '/', '\\', '\"', '<', '>', '`', '·', '。', '{', '}', '~', '', '(', ')', '-', //
'√', '$', '@', '*', '&', '#', '卐', '㎎', '㎏', '㎜', '㎝', '㎞', '㎡', '㏄', '㏎', '㏑', '㏒', '㏕' });
'√', '$', '@', '*', '&', '#', '卐', '㎎', '㎏', '㎜', '㎝', '㎞', '㎡', '㏄', '㏎', '㏑', '㏒', '㏕', '+', '=', '?',
':', '.', '!', ';', ']','|','%');
/**
* 判断指定的词是否是不处理的词 如果参数为空则返回true因为空也属于不处理的字符

View File

@ -19,7 +19,6 @@ import javax.xml.soap.Name;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import java.io.IOException;
@ -235,7 +234,7 @@ public class SoapClient extends HttpBase<SoapClient> {
*
* @param name 头信息标签名
* @return this
* @deprecated 为了和Http Hrader区分请使用{@link #setSOAPHeader(QName)}
* @deprecated 为了和Http Hrader区分请使用{@link #addSOAPHeader(QName)}
*/
@Deprecated
public SoapClient setHeader(QName name) {
@ -247,9 +246,12 @@ public class SoapClient extends HttpBase<SoapClient> {
*
* @param name 头信息标签名
* @return this
* @deprecated 为了便于设置子节点或者value值请使用{@link #addSOAPHeader(QName)}
*/
@Deprecated
public SoapClient setSOAPHeader(QName name) {
return setSOAPHeader(name, null, null, null, null);
addSOAPHeader(name);
return this;
}
/**
@ -261,7 +263,7 @@ public class SoapClient extends HttpBase<SoapClient> {
* @param mustUnderstand 标题项对于要对其进行处理的接收者来说是强制的还是可选的
* @param relay relay属性
* @return this
* @deprecated 为了和Http Hrader区分请使用{@link #setSOAPHeader(QName, String, String, Boolean, Boolean)}
* @deprecated 为了和Http Header区分请使用{@link #addSOAPHeader(QName, String, String, Boolean, Boolean)}
*/
@Deprecated
public SoapClient setHeader(QName name, String actorURI, String roleUri, Boolean mustUnderstand, Boolean relay) {
@ -277,13 +279,29 @@ public class SoapClient extends HttpBase<SoapClient> {
* @param mustUnderstand 标题项对于要对其进行处理的接收者来说是强制的还是可选的
* @param relay relay属性
* @return this
* @deprecated 为了便于设置子节点或者value值请使用{@link #addSOAPHeader(QName, String, String, Boolean, Boolean)}
*/
@Deprecated
public SoapClient setSOAPHeader(QName name, String actorURI, String roleUri, Boolean mustUnderstand, Boolean relay) {
SOAPHeader header;
SOAPHeaderElement ele;
addSOAPHeader(name, actorURI, roleUri, mustUnderstand, relay);
return this;
}
/**
* 增加SOAP头信息方法返回{@link SOAPHeaderElement}可以设置具体属性和子节点
*
* @param name 头信息标签名
* @param actorURI 中间的消息接收者
* @param roleUri Role的URI
* @param mustUnderstand 标题项对于要对其进行处理的接收者来说是强制的还是可选的
* @param relay relay属性
* @return {@link SOAPHeaderElement}
* @since 5.4.4
*/
public SOAPHeaderElement addSOAPHeader(QName name, String actorURI, String roleUri, Boolean mustUnderstand, Boolean relay) {
final SOAPHeaderElement ele = addSOAPHeader(name);
try {
header = this.message.getSOAPHeader();
ele = header.addHeaderElement(name);
if (StrUtil.isNotBlank(roleUri)) {
ele.setRole(roleUri);
}
@ -301,7 +319,24 @@ public class SoapClient extends HttpBase<SoapClient> {
ele.setMustUnderstand(mustUnderstand);
}
return this;
return ele;
}
/**
* 增加SOAP头信息方法返回{@link SOAPHeaderElement}可以设置具体属性和子节点
*
* @param name 头节点名称
* @return {@link SOAPHeaderElement}
* @since 5.4.4
*/
public SOAPHeaderElement addSOAPHeader(QName name){
SOAPHeaderElement ele;
try {
ele = this.message.getSOAPHeader().addHeaderElement(name);
} catch (SOAPException e) {
throw new SoapRuntimeException(e);
}
return ele;
}
/**

View File

@ -119,7 +119,7 @@ public class HtmlUtilTest {
Assert.assertEquals("&lt;html&gt;&lt;body&gt;123&#039;123&#039;&lt;/body&gt;&lt;/html&gt;", escape);
String restoreEscaped = HtmlUtil.unescape(escape);
Assert.assertEquals(html, restoreEscaped);
Assert.assertEquals("\'", HtmlUtil.unescape("&apos;"));
Assert.assertEquals("'", HtmlUtil.unescape("&apos;"));
}
@Test

View File

@ -10,7 +10,7 @@
<!-- 控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />
<!-- 输出日志的格式 -->
<PatternLayout pattern="[%d{HH:mm:ss.SSS}][%-5level] %class{36}:%L %M - %msg%xEx%n" />
<PatternLayout pattern="[%d{HH:mm:ss.SSS}][%highlight{%-5level}] %class{36}:%L %M - %msg%xEx%n" disableAnsi="false" />
</Console>
</Appenders>

View File

@ -0,0 +1,46 @@
package cn.hutool.poi.excel;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.extractor.ExcelExtractor;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.extractor.XSSFExcelExtractor;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
/**
* {@link ExcelExtractor}工具封装
*
* @author looly
* @since 5.4.4
*/
public class ExcelExtractorUtil {
/**
* 获取 {@link ExcelExtractor} 对象
*
* @param wb {@link Workbook}
* @return {@link ExcelExtractor}
*/
public static ExcelExtractor getExtractor(Workbook wb) {
ExcelExtractor extractor;
if (wb instanceof HSSFWorkbook) {
extractor = new org.apache.poi.hssf.extractor.ExcelExtractor((HSSFWorkbook) wb);
} else {
extractor = new XSSFExcelExtractor((XSSFWorkbook) wb);
}
return extractor;
}
/**
* 读取为文本格式<br>
* 使用{@link ExcelExtractor} 提取Excel内容
*
* @param wb {@link Workbook}
* @param withSheetName 是否附带sheet名
* @return Excel文本
* @since 4.1.0
*/
public static String readAsText(Workbook wb, boolean withSheetName) {
final ExcelExtractor extractor = getExtractor(wb);
extractor.setIncludeSheetNames(withSheetName);
return extractor.getText();
}
}

View File

@ -1,28 +1,22 @@
package cn.hutool.poi.excel;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.cell.CellEditor;
import cn.hutool.poi.excel.cell.CellHandler;
import cn.hutool.poi.excel.cell.CellUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import cn.hutool.poi.excel.reader.BeanSheetReader;
import cn.hutool.poi.excel.reader.ListSheetReader;
import cn.hutool.poi.excel.reader.MapSheetReader;
import cn.hutool.poi.excel.reader.SheetReader;
import org.apache.poi.ss.extractor.ExcelExtractor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.extractor.XSSFExcelExtractor;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -256,37 +250,31 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
}
/**
* 读取工作簿中指定的Sheet
* 读取工作簿中指定的Sheet此方法会把第一行作为标题行替换标题别名
*
* @param startRowIndex 起始行包含从0开始计数
* @param endRowIndex 结束行包含从0开始计数
* @return 行的集合一行使用List表示
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public List<List<Object>> read(int startRowIndex, int endRowIndex) {
checkNotClosed();
List<List<Object>> resultList = new ArrayList<>();
return read(startRowIndex, endRowIndex, true);
}
startRowIndex = Math.max(startRowIndex, this.sheet.getFirstRowNum());// 读取起始行包含
endRowIndex = Math.min(endRowIndex, this.sheet.getLastRowNum());// 读取结束行包含
boolean isFirstLine = true;
List rowList;
for (int i = startRowIndex; i <= endRowIndex; i++) {
rowList = readRow(i);
if (CollUtil.isNotEmpty(rowList) || false == ignoreEmptyRow) {
if (null == rowList) {
rowList = new ArrayList<>(0);
}
if (isFirstLine) {
isFirstLine = false;
if (MapUtil.isNotEmpty(this.headerAlias)) {
rowList = aliasHeader(rowList);
}
}
resultList.add(rowList);
}
}
return resultList;
/**
* 读取工作簿中指定的Sheet
*
* @param startRowIndex 起始行包含从0开始计数
* @param endRowIndex 结束行包含从0开始计数
* @param aliasFirstLine 是否首行作为标题行转换别名
* @return 行的集合一行使用List表示
* @since 5.4.4
*/
public List<List<Object>> read(int startRowIndex, int endRowIndex, boolean aliasFirstLine) {
final ListSheetReader reader = new ListSheetReader(startRowIndex, endRowIndex, aliasFirstLine);
reader.setCellEditor(this.cellEditor);
reader.setIgnoreEmptyRow(this.ignoreEmptyRow);
reader.setHeaderAlias(headerAlias);
return read(reader);
}
/**
@ -348,33 +336,11 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
* @return Map的列表
*/
public List<Map<String, Object>> read(int headerRowIndex, int startRowIndex, int endRowIndex) {
checkNotClosed();
// 边界判断
final int firstRowNum = sheet.getFirstRowNum();
final int lastRowNum = sheet.getLastRowNum();
if (headerRowIndex < firstRowNum) {
throw new IndexOutOfBoundsException(StrUtil.format("Header row index {} is lower than first row index {}.", headerRowIndex, firstRowNum));
} else if (headerRowIndex > lastRowNum) {
throw new IndexOutOfBoundsException(StrUtil.format("Header row index {} is greater than last row index {}.", headerRowIndex, firstRowNum));
}
startRowIndex = Math.max(startRowIndex, firstRowNum);// 读取起始行包含
endRowIndex = Math.min(endRowIndex, lastRowNum);// 读取结束行包含
// 读取header
List<Object> headerList = readRow(sheet.getRow(headerRowIndex));
final List<Map<String, Object>> result = new ArrayList<>(endRowIndex - startRowIndex + 1);
List<Object> rowList;
for (int i = startRowIndex; i <= endRowIndex; i++) {
if (i != headerRowIndex) {
// 跳过标题行
rowList = readRow(sheet.getRow(i));
if (CollUtil.isNotEmpty(rowList) || false == ignoreEmptyRow) {
result.add(IterUtil.toMap(aliasHeader(headerList), rowList, true));
}
}
}
return result;
final MapSheetReader reader = new MapSheetReader(headerRowIndex, startRowIndex, endRowIndex);
reader.setCellEditor(this.cellEditor);
reader.setIgnoreEmptyRow(this.ignoreEmptyRow);
reader.setHeaderAlias(headerAlias);
return read(reader);
}
/**
@ -412,19 +378,25 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
* @param beanType 每行对应Bean的类型
* @return Map的列表
*/
@SuppressWarnings("unchecked")
public <T> List<T> read(int headerRowIndex, int startRowIndex, int endRowIndex, Class<T> beanType) {
checkNotClosed();
final List<Map<String, Object>> mapList = read(headerRowIndex, startRowIndex, endRowIndex);
if (Map.class.isAssignableFrom(beanType)) {
return (List<T>) mapList;
}
final BeanSheetReader<T> reader = new BeanSheetReader<>(headerRowIndex, startRowIndex, endRowIndex, beanType);
reader.setCellEditor(this.cellEditor);
reader.setIgnoreEmptyRow(this.ignoreEmptyRow);
reader.setHeaderAlias(headerAlias);
return read(reader);
}
final List<T> beanList = new ArrayList<>(mapList.size());
for (Map<String, Object> map : mapList) {
beanList.add(BeanUtil.toBean(map, beanType));
}
return beanList;
/**
* 读取数据为指定类型
*
* @param <T> 读取数据类型
* @param sheetReader {@link SheetReader}实现
* @return 数据读取结果
* @since 5.4.4
*/
public <T> T read(SheetReader<T> sheetReader){
checkNotClosed();
return Assert.notNull(sheetReader).read(this.sheet);
}
/**
@ -436,9 +408,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
* @since 4.1.0
*/
public String readAsText(boolean withSheetName) {
final ExcelExtractor extractor = getExtractor();
extractor.setIncludeSheetNames(withSheetName);
return extractor.getText();
return ExcelExtractorUtil.readAsText(this.workbook, withSheetName);
}
/**
@ -448,14 +418,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
* @since 4.1.0
*/
public ExcelExtractor getExtractor() {
ExcelExtractor extractor;
Workbook wb = this.workbook;
if (wb instanceof HSSFWorkbook) {
extractor = new org.apache.poi.hssf.extractor.ExcelExtractor((HSSFWorkbook) wb);
} else {
extractor = new XSSFExcelExtractor((XSSFWorkbook) wb);
}
return extractor;
return ExcelExtractorUtil.getExtractor(this.workbook);
}
/**
@ -504,42 +467,6 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
return RowUtil.readRow(row, this.cellEditor);
}
/**
* 转换标题别名如果没有别名则使用原标题当标题为空时列号对应的字母便是header
*
* @param headerList 原标题列表
* @return 转换别名列表
*/
private List<String> aliasHeader(List<Object> headerList) {
if(CollUtil.isEmpty(headerList)){
return new ArrayList<>(0);
}
final int size = headerList.size();
final ArrayList<String> result = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
result.add(aliasHeader(headerList.get(i), i));
}
return result;
}
/**
* 转换标题别名如果没有别名则使用原标题当标题为空时列号对应的字母便是header
*
* @param headerObj 原标题
* @param index 标题所在列号当标题为空时列号对应的字母便是header
* @return 转换别名列表
* @since 4.3.2
*/
private String aliasHeader(Object headerObj, int index) {
if (null == headerObj) {
return ExcelUtil.indexToColName(index);
}
final String header = headerObj.toString();
return ObjectUtil.defaultIfNull(this.headerAlias.get(header), header);
}
/**
* 检查是否未关闭状态
*/

View File

@ -0,0 +1,140 @@
package cn.hutool.poi.excel.reader;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.RowUtil;
import cn.hutool.poi.excel.cell.CellEditor;
import org.apache.poi.ss.usermodel.Sheet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 抽象{@link Sheet}数据读取实现
*
* @param <T> 读取类型
* @author looly
* @since 5.4.4
*/
public abstract class AbstractSheetReader<T> implements SheetReader<T> {
/**
* 读取起始行包含从0开始计数
*/
protected final int startRowIndex;
/**
* 读取结束行包含从0开始计数
*/
protected final int endRowIndex;
/**
* 是否忽略空行
*/
protected boolean ignoreEmptyRow = true;
/**
* 单元格值处理接口
*/
protected CellEditor cellEditor;
/**
* 标题别名
*/
private Map<String, String> headerAlias = new HashMap<>();
/**
* 构造
*
* @param startRowIndex 起始行包含从0开始计数
* @param endRowIndex 结束行包含从0开始计数
*/
public AbstractSheetReader(int startRowIndex, int endRowIndex) {
this.startRowIndex = startRowIndex;
this.endRowIndex = endRowIndex;
}
/**
* 设置单元格值处理逻辑<br>
* 当Excel中的值并不能满足我们的读取要求时通过传入一个编辑接口可以对单元格值自定义例如对数字和日期类型值转换为字符串等
*
* @param cellEditor 单元格值处理接口
*/
public void setCellEditor(CellEditor cellEditor) {
this.cellEditor = cellEditor;
}
/**
* 设置是否忽略空行
*
* @param ignoreEmptyRow 是否忽略空行
*/
public void setIgnoreEmptyRow(boolean ignoreEmptyRow) {
this.ignoreEmptyRow = ignoreEmptyRow;
}
/**
* 设置标题行的别名Map
*
* @param headerAlias 别名Map
*/
public void setHeaderAlias(Map<String, String> headerAlias) {
this.headerAlias = headerAlias;
}
/**
* 增加标题别名
*
* @param header 标题
* @param alias 别名
*/
public void addHeaderAlias(String header, String alias) {
this.headerAlias.put(header, alias);
}
/**
* 转换标题别名如果没有别名则使用原标题当标题为空时列号对应的字母便是header
*
* @param headerList 原标题列表
* @return 转换别名列表
*/
protected List<String> aliasHeader(List<Object> headerList) {
if (CollUtil.isEmpty(headerList)) {
return new ArrayList<>(0);
}
final int size = headerList.size();
final ArrayList<String> result = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
result.add(aliasHeader(headerList.get(i), i));
}
return result;
}
/**
* 转换标题别名如果没有别名则使用原标题当标题为空时列号对应的字母便是header
*
* @param headerObj 原标题
* @param index 标题所在列号当标题为空时列号对应的字母便是header
* @return 转换别名列表
* @since 4.3.2
*/
protected String aliasHeader(Object headerObj, int index) {
if (null == headerObj) {
return ExcelUtil.indexToColName(index);
}
final String header = headerObj.toString();
return ObjectUtil.defaultIfNull(this.headerAlias.get(header), header);
}
/**
* 读取某一行数据
*
* @param sheet {@link Sheet}
* @param rowIndex 行号从0开始
* @return 一行数据
*/
protected List<Object> readRow(Sheet sheet, int rowIndex) {
return RowUtil.readRow(sheet.getRow(rowIndex), this.cellEditor);
}
}

View File

@ -0,0 +1,87 @@
package cn.hutool.poi.excel.reader;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.poi.excel.cell.CellEditor;
import org.apache.poi.ss.usermodel.Sheet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 读取{@link Sheet}为bean的List列表形式
*
* @author looly
* @since 5.4.4
*/
public class BeanSheetReader<T> implements SheetReader<List<T>> {
private final Class<T> beanClass;
private final MapSheetReader mapSheetReader;
/**
* 构造
*
* @param headerRowIndex 标题所在行如果标题行在读取的内容行中间这行做为数据将忽略
* @param startRowIndex 起始行包含从0开始计数
* @param endRowIndex 结束行包含从0开始计数
* @param beanClass 每行对应Bean的类型
*/
public BeanSheetReader(int headerRowIndex, int startRowIndex, int endRowIndex, Class<T> beanClass) {
mapSheetReader = new MapSheetReader(headerRowIndex, startRowIndex, endRowIndex);
this.beanClass = beanClass;
}
@Override
@SuppressWarnings("unchecked")
public List<T> read(Sheet sheet) {
final List<Map<String, Object>> mapList = mapSheetReader.read(sheet);
if (Map.class.isAssignableFrom(this.beanClass)) {
return (List<T>) mapList;
}
final List<T> beanList = new ArrayList<>(mapList.size());
for (Map<String, Object> map : mapList) {
beanList.add(BeanUtil.toBean(map, this.beanClass));
}
return beanList;
}
/**
* 设置单元格值处理逻辑<br>
* 当Excel中的值并不能满足我们的读取要求时通过传入一个编辑接口可以对单元格值自定义例如对数字和日期类型值转换为字符串等
*
* @param cellEditor 单元格值处理接口
*/
public void setCellEditor(CellEditor cellEditor) {
this.mapSheetReader.setCellEditor(cellEditor);
}
/**
* 设置是否忽略空行
*
* @param ignoreEmptyRow 是否忽略空行
*/
public void setIgnoreEmptyRow(boolean ignoreEmptyRow) {
this.mapSheetReader.setIgnoreEmptyRow(ignoreEmptyRow);
}
/**
* 设置标题行的别名Map
*
* @param headerAlias 别名Map
*/
public void setHeaderAlias(Map<String, String> headerAlias) {
this.mapSheetReader.setHeaderAlias(headerAlias);
}
/**
* 增加标题别名
*
* @param header 标题
* @param alias 别名
*/
public void addHeaderAlias(String header, String alias) {
this.mapSheetReader.addHeaderAlias(header, alias);
}
}

View File

@ -0,0 +1,52 @@
package cn.hutool.poi.excel.reader;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import org.apache.poi.ss.usermodel.Sheet;
import java.util.ArrayList;
import java.util.List;
/**
* 读取{@link Sheet}为List列表形式
*
* @author looly
* @since 5.4.4
*/
public class ListSheetReader extends AbstractSheetReader<List<List<Object>>> {
/** 是否首行作为标题行转换别名 */
private final boolean aliasFirstLine;
/**
* 构造
*
* @param startRowIndex 起始行包含从0开始计数
* @param endRowIndex 结束行包含从0开始计数
* @param aliasFirstLine 是否首行作为标题行转换别名
*/
public ListSheetReader(int startRowIndex, int endRowIndex, boolean aliasFirstLine) {
super(startRowIndex, endRowIndex);
this.aliasFirstLine = aliasFirstLine;
}
@Override
public List<List<Object>> read(Sheet sheet) {
final List<List<Object>> resultList = new ArrayList<>();
int startRowIndex = Math.max(this.startRowIndex, sheet.getFirstRowNum());// 读取起始行包含
int endRowIndex = Math.min(this.endRowIndex, sheet.getLastRowNum());// 读取结束行包含
List<Object> rowList;
for (int i = startRowIndex; i <= endRowIndex; i++) {
rowList = readRow(sheet, i);
if (CollUtil.isNotEmpty(rowList) || false == ignoreEmptyRow) {
if (aliasFirstLine && i == startRowIndex) {
// 第一行作为标题行替换别名
rowList = Convert.toList(Object.class, aliasHeader(rowList));
}
resultList.add(rowList);
}
}
return resultList;
}
}

View File

@ -0,0 +1,63 @@
package cn.hutool.poi.excel.reader;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.util.StrUtil;
import org.apache.poi.ss.usermodel.Sheet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 读取{@link Sheet}为Map的List列表形式
*
* @author looly
* @since 5.4.4
*/
public class MapSheetReader extends AbstractSheetReader<List<Map<String, Object>>> {
private final int headerRowIndex;
/**
* 构造
*
* @param headerRowIndex 标题所在行如果标题行在读取的内容行中间这行做为数据将忽略
* @param startRowIndex 起始行包含从0开始计数
* @param endRowIndex 结束行包含从0开始计数
*/
public MapSheetReader(int headerRowIndex, int startRowIndex, int endRowIndex) {
super(startRowIndex, endRowIndex);
this.headerRowIndex = headerRowIndex;
}
@Override
public List<Map<String, Object>> read(Sheet sheet) {
// 边界判断
final int firstRowNum = sheet.getFirstRowNum();
final int lastRowNum = sheet.getLastRowNum();
if (headerRowIndex < firstRowNum) {
throw new IndexOutOfBoundsException(StrUtil.format("Header row index {} is lower than first row index {}.", headerRowIndex, firstRowNum));
} else if (headerRowIndex > lastRowNum) {
throw new IndexOutOfBoundsException(StrUtil.format("Header row index {} is greater than last row index {}.", headerRowIndex, firstRowNum));
}
final int startRowIndex = Math.max(this.startRowIndex, firstRowNum);// 读取起始行包含
final int endRowIndex = Math.min(this.endRowIndex, lastRowNum);// 读取结束行包含
// 读取header
List<String> headerList = aliasHeader(readRow(sheet, headerRowIndex));
final List<Map<String, Object>> result = new ArrayList<>(endRowIndex - startRowIndex + 1);
List<Object> rowList;
for (int i = startRowIndex; i <= endRowIndex; i++) {
// 跳过标题行
if (i != headerRowIndex) {
rowList = readRow(sheet, i);
if (CollUtil.isNotEmpty(rowList) || false == ignoreEmptyRow) {
result.add(IterUtil.toMap(headerList, rowList, true));
}
}
}
return result;
}
}

View File

@ -0,0 +1,20 @@
package cn.hutool.poi.excel.reader;
import org.apache.poi.ss.usermodel.Sheet;
/**
* Excel {@link Sheet}读取接口通过实现此接口{@link Sheet}中的数据读取为不同类型
*
* @param <T> 读取的数据类型
*/
@FunctionalInterface
public interface SheetReader<T> {
/**
* 读取数据
*
* @param sheet {@link Sheet}
* @return 读取结果
*/
T read(Sheet sheet);
}

View File

@ -0,0 +1,7 @@
/**
* 数据读取接口及实现此包中定义了SheetReader通过实现此接口实现sheet中的数据读取为不同类型
*
* @author looly
*
*/
package cn.hutool.poi.excel.reader;

View File

@ -0,0 +1,59 @@
package cn.hutool.poi.excel.sax.handler;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.func.Func1;
import java.util.List;
/**
* 抽象行数据处理器通过实现{@link #handle(int, long, List)} 处理原始数据<br>
* 并调用{@link #handleData(int, long, Object)}处理经过转换后的数据
*
* @param <T> 转换后的数据类型
* @author looly
* @since 5.4.4
*/
public abstract class AbstractRowHandler<T> implements RowHandler {
/**
* 读取起始行包含从0开始计数
*/
protected final int startRowIndex;
/**
* 读取结束行包含从0开始计数
*/
protected final int endRowIndex;
/**
* 行数据转换函数
*/
protected Func1<List<Object>, T> convertFunc;
/**
* 构造
*
* @param startRowIndex 读取起始行包含从0开始计数
* @param endRowIndex 读取结束行包含从0开始计数
*/
public AbstractRowHandler(int startRowIndex, int endRowIndex) {
this.startRowIndex = startRowIndex;
this.endRowIndex = endRowIndex;
}
@Override
public void handle(int sheetIndex, long rowIndex, List<Object> rowList) {
Assert.notNull(convertFunc);
if (rowIndex < this.startRowIndex || rowIndex > this.endRowIndex) {
return;
}
handleData(sheetIndex, rowIndex, convertFunc.callWithRuntimeException(rowList));
}
/**
* 处理转换后的数据
*
* @param sheetIndex 当前Sheet序号
* @param rowIndex 当前行号从0开始计数
* @param data 行数据
*/
public abstract void handleData(int sheetIndex, long rowIndex, T data);
}

View File

@ -0,0 +1,52 @@
package cn.hutool.poi.excel.sax.handler;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import java.util.List;
/**
* Bean形式的行处理器<br>
* 将一行数据转换为Mapkey为指定行value为当前行对应位置的值
*
* @author looly
* @since 5.4.4
*/
public abstract class BeanRowHandler<T> extends AbstractRowHandler<T> {
/**
* 标题所在行从0开始计数
*/
private final int headerRowIndex;
/**
* 标题行
*/
List<String> headerList;
/**
* 构造
*
* @param headerRowIndex 标题所在行从0开始计数
* @param startRowIndex 读取起始行包含从0开始计数
* @param endRowIndex 读取结束行包含从0开始计数
* @param clazz Bean类型
*/
public BeanRowHandler(int headerRowIndex, int startRowIndex, int endRowIndex, Class<T> clazz) {
super(startRowIndex, endRowIndex);
Assert.isTrue(headerRowIndex <= startRowIndex, "Header row must before the start row!");
this.headerRowIndex = headerRowIndex;
this.convertFunc = (rowList) -> BeanUtil.toBean(IterUtil.toMap(headerList, rowList), clazz);
}
@Override
public void handle(int sheetIndex, long rowIndex, List<Object> rowList) {
if (rowIndex == this.headerRowIndex) {
this.headerList = ListUtil.unmodifiable(Convert.toList(String.class, rowList));
return;
}
super.handle(sheetIndex, rowIndex, rowList);
}
}

View File

@ -0,0 +1,49 @@
package cn.hutool.poi.excel.sax.handler;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import java.util.List;
import java.util.Map;
/**
* Map形式的行处理器<br>
* 将一行数据转换为Mapkey为指定行value为当前行对应位置的值
*
* @author looly
* @since 5.4.4
*/
public abstract class MapRowHandler extends AbstractRowHandler<Map<String, Object>> {
/**
* 标题所在行从0开始计数
*/
private final int headerRowIndex;
/**
* 标题行
*/
List<String> headerList;
/**
* 构造
*
* @param headerRowIndex 标题所在行从0开始计数
* @param startRowIndex 读取起始行包含从0开始计数
* @param endRowIndex 读取结束行包含从0开始计数
*/
public MapRowHandler(int headerRowIndex, int startRowIndex, int endRowIndex){
super(startRowIndex, endRowIndex);
this.headerRowIndex = headerRowIndex;
this.convertFunc = (rowList)-> IterUtil.toMap(headerList, rowList);
}
@Override
public void handle(int sheetIndex, long rowIndex, List<Object> rowList) {
if (rowIndex == this.headerRowIndex) {
this.headerList = ListUtil.unmodifiable(Convert.toList(String.class, rowList));
return;
}
super.handle(sheetIndex, rowIndex, rowList);
}
}

View File

@ -151,7 +151,12 @@ public class ScriptUtil {
}
/**
* 执行Javascript脚本返回Invocable
* 执行Javascript脚本返回Invocable此方法分为两种情况
*
* <ol>
* <li>执行的脚本返回值是可执行的脚本方法</li>
* <li>脚本为函数库则ScriptEngine本身为可执行方法</li>
* </ol>
*
* @param script 脚本内容
* @return 执行结果
@ -159,11 +164,23 @@ public class ScriptUtil {
* @since 5.3.6
*/
public static Invocable evalInvocable(String script) throws ScriptRuntimeException {
return (Invocable) eval(script);
final ScriptEngine jsEngine = getJsEngine();
final Object eval;
try {
eval = jsEngine.eval(script);
} catch (ScriptException e) {
throw new ScriptRuntimeException(e);
}
if(eval instanceof Invocable){
return (Invocable)eval;
} else if(jsEngine instanceof Invocable){
return (Invocable)jsEngine;
}
throw new ScriptRuntimeException("Script is not invocable !");
}
/**
* 执行Javascript脚本
* 执行有返回值的Javascript脚本
*
* @param script 脚本内容
* @return 执行结果
@ -179,7 +196,7 @@ public class ScriptUtil {
}
/**
* 执行脚本
* 执行有返回值的脚本
*
* @param script 脚本内容
* @param context 脚本上下文
@ -196,7 +213,7 @@ public class ScriptUtil {
}
/**
* 执行脚本
* 执行有返回值的脚本
*
* @param script 脚本内容
* @param bindings 绑定的参数

View File

@ -0,0 +1,22 @@
package cn.hutool.script.test;
import cn.hutool.core.io.resource.ResourceUtil;
import org.junit.Assert;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class NashornDeepTest {
public static void main(String[] args) throws ScriptException, NoSuchMethodException {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
engine.eval(ResourceUtil.readUtf8Str("filter1.js"));
final Object filter1 = ((Invocable) engine).invokeFunction("filter1", 1, 2);
Assert.assertFalse((Boolean) filter1);
}
}

View File

@ -1,7 +1,9 @@
package cn.hutool.script.test;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.script.ScriptRuntimeException;
import cn.hutool.script.ScriptUtil;
import org.junit.Assert;
import org.junit.Test;
import javax.script.CompiledScript;
@ -31,6 +33,12 @@ public class ScriptUtilTest {
ScriptUtil.eval("print('Script test!');");
}
@Test
public void invokeTest() {
final Object result = ScriptUtil.invoke(ResourceUtil.readUtf8Str("filter1.js"), "filter1", 2, 1);
Assert.assertTrue((Boolean) result);
}
@Test
public void pythonTest() throws ScriptException {
final ScriptEngine pythonEngine = ScriptUtil.getPythonEngine();

View File

@ -0,0 +1,6 @@
function filter1(a, b) {
if (a > b) {
return a > b;
}
return false;
}