Browse Source

回归优化

miemie 6 năm trước cách đây
mục cha
commit
a83659a7a0

+ 114 - 161
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/StringUtils.java

@@ -17,19 +17,13 @@ package com.baomidou.mybatisplus.core.toolkit;
 
 import com.baomidou.mybatisplus.core.toolkit.sql.StringEscape;
 
-import java.lang.reflect.Array;
 import java.nio.charset.StandardCharsets;
 import java.sql.Blob;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.function.BiFunction;
-import java.util.function.Function;
-import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import java.util.stream.Collector;
-import java.util.stream.Stream;
 
 import static java.util.stream.Collectors.joining;
 
@@ -47,23 +41,25 @@ public class StringUtils {
      * 空字符
      */
     public static final String EMPTY = "";
-
     /**
      * 字符串 is
      */
     public static final String IS = "is";
-
     /**
      * 下划线字符
      */
-    private static final char UNDERLINE = '_';
-
+    public static final char UNDERLINE = '_';
+    /**
+     * 占位符
+     */
+    public static final String PLACE_HOLDER = "{%s}";
     /**
      * 验证字符串是否是数据库字段
      */
     private static final Pattern P_IS_COLUMN = Pattern.compile("^\\w\\S*[\\w\\d]*$");
 
     private StringUtils() {
+        // to do nothing
     }
 
     /**
@@ -86,16 +82,6 @@ public class StringUtils {
         return null;
     }
 
-    /**
-     * 判断字符串是否存在长度
-     *
-     * @param cs 字符序列
-     * @return 如果为 null 或者长度为 0 ,返回 true
-     */
-    public static boolean hasLength(CharSequence cs) {
-        return null == cs || 0 == cs.length();
-    }
-
     /**
      * <p>
      * 判断字符串是否为空
@@ -105,7 +91,16 @@ public class StringUtils {
      * @return 判断结果
      */
     public static boolean isEmpty(final CharSequence cs) {
-        return hasLength(cs) || cs.chars().allMatch(Character::isWhitespace);
+        int strLen;
+        if (cs == null || (strLen = cs.length()) == 0) {
+            return true;
+        }
+        for (int i = 0; i < strLen; i++) {
+            if (!Character.isWhitespace(cs.charAt(i))) {
+                return false;
+            }
+        }
+        return true;
     }
 
     /**
@@ -141,44 +136,17 @@ public class StringUtils {
      * @return 转换好的字符串
      */
     public static String camelToUnderline(String param) {
-        if (hasLength(param)) {
-            char[] chars = param.toCharArray();
-            StringBuilder sb = new StringBuilder();
-            sb.append(Character.toLowerCase(chars[0]));
-            char c;
-            for (int i = 1, len = chars.length; i < len; i++) {
-                c = chars[i];
-                sb.append(Character.isUpperCase(c) ? "_" + Character.toLowerCase(c) : c);
-            }
-            return sb.toString();
-        }
-        return param;
-    }
-
-    /**
-     * <p>
-     * 字符串下划线转驼峰格式
-     * </p>
-     *
-     * @param param 需要转换的字符串
-     * @return 转换好的字符串
-     */
-    public static String underlineToCamel(String param) {
         if (isEmpty(param)) {
             return EMPTY;
         }
-        String temp = param.toLowerCase();
-        int len = temp.length();
+        int len = param.length();
         StringBuilder sb = new StringBuilder(len);
-        // 标记下一个字符是否需要大写
-        boolean upper = false;
-        for (char c : temp.toCharArray()) {
-            if (c == UNDERLINE) {
-                upper = true;
-            } else {
-                sb.append(upper ? Character.toUpperCase(c) : c);
-                upper = false;
+        for (int i = 0; i < len; i++) {
+            char c = param.charAt(i);
+            if (Character.isUpperCase(c) && i > 0) {
+                sb.append(UNDERLINE);
             }
+            sb.append(Character.toLowerCase(c));
         }
         return sb.toString();
     }
@@ -201,6 +169,34 @@ public class StringUtils {
         return StringUtils.firstToLowerCase(getMethodName);
     }
 
+    /**
+     * <p>
+     * 字符串下划线转驼峰格式
+     * </p>
+     *
+     * @param param 需要转换的字符串
+     * @return 转换好的字符串
+     */
+    public static String underlineToCamel(String param) {
+        if (isEmpty(param)) {
+            return EMPTY;
+        }
+        String temp = param.toLowerCase();
+        int len = temp.length();
+        StringBuilder sb = new StringBuilder(len);
+        for (int i = 0; i < len; i++) {
+            char c = temp.charAt(i);
+            if (c == UNDERLINE) {
+                if (++i < len) {
+                    sb.append(Character.toUpperCase(temp.charAt(i)));
+                }
+            } else {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
     /**
      * <p>
      * 首字母转换小写
@@ -216,6 +212,18 @@ public class StringUtils {
         return param.substring(0, 1).toLowerCase() + param.substring(1);
     }
 
+    /**
+     * <p>
+     * 判断字符串是否为纯大写字母
+     * </p>
+     *
+     * @param str 要匹配的字符串
+     * @return
+     */
+    public static boolean isUpperCase(String str) {
+        return matches("^[A-Z]+$", str);
+    }
+
     /**
      * <p>
      * 正则表达式匹配
@@ -232,27 +240,28 @@ public class StringUtils {
         return Pattern.matches(regex, input);
     }
 
-    /**
-     * SQL 参数占位符 预编译的正则表达式,匹配配型 {1} , {10} ...
-     * 因为字符串中储存的是索引,所以可以在匹配的 Matcher 使用 m.group("idx") 获取匹配的结果 1,2,3,4,5。。。
-     */
-    private static final Pattern SQL_ARG_PLACE_HOLDER_PATTERN = Pattern.compile("\\{(?<idx>[\\d]+)}");
-
     /**
      * <p>
-     * SQL 参数填充,未填充的 SQL 语句的样子类似:
-     * SELECT * FROM TEST WHERE id = {1} AND NAME = {2}
+     * SQL 参数填充
      * </p>
      *
-     * @param outerSql 不含有参数的 SQL 语句
-     * @param args     填充参数列表
-     * @return 返回填充后的字符串
+     * @param content 填充内容
+     * @param args    填充参数
+     * @return
      */
-    public static String sqlArgsFill(String outerSql, Object... args) {
-        if (StringUtils.isEmpty(outerSql) || null == args) {
-            return outerSql;
+    public static String sqlArgsFill(String content, Object... args) {
+        if (StringUtils.isEmpty(content)) {
+            return null;
         }
-        return replace(outerSql, SQL_ARG_PLACE_HOLDER_PATTERN, m -> sqlParam(args[Integer.valueOf(m.group("idx"))])).toString();
+        if (args != null) {
+            int length = args.length;
+            if (length >= 1) {
+                for (int i = 0; i < length; i++) {
+                    content = content.replace(String.format(PLACE_HOLDER, i), sqlParam(args[i]));
+                }
+            }
+        }
+        return content;
     }
 
     /**
@@ -260,39 +269,17 @@ public class StringUtils {
      * 获取SQL PARAMS字符串
      * </p>
      *
-     * @param obj 参数对象
-     * @return 返回处理后的 SQL 参数字符串
+     * @param obj
+     * @return
      */
-    private static String sqlParam(Object obj) {
-        if (null == obj) {
-            return "null";
-        }
+    public static String sqlParam(Object obj) {
+        String repStr;
         if (obj instanceof Collection) {
-            return StringUtils.quotaMarkList((Collection<?>) obj);
-        } else if (obj.getClass().isArray()) {
-            return arrayToSqlString(obj);
+            repStr = StringUtils.quotaMarkList((Collection<?>) obj);
+        } else {
+            repStr = StringUtils.quotaMark(obj);
         }
-        return StringUtils.quotaMark(obj);
-    }
-
-    /**
-     * 数组转转为 SQL 语句中的字符串形式
-     *
-     * @param obj 数组对象
-     * @return 返回处理后的字符串
-     */
-    private static String arrayToSqlString(Object obj) {
-        return Stream.iterate(0, i -> i + 1).limit(Array.getLength(obj)).map(StringUtils::quotaMark)
-            .collect(sqlJoinCollector());
-    }
-
-    /**
-     * 适用于 SQL 的结果收集器,这里不能写成常量,因为收集器不是可复用的,必须产生新的实例
-     *
-     * @return 返回结果收集器
-     */
-    private static Collector<CharSequence, ?, String> sqlJoinCollector() {
-        return joining(StringPool.COMMA, StringPool.LEFT_BRACKET, StringPool.RIGHT_BRACKET);
+        return repStr;
     }
 
     /**
@@ -303,9 +290,10 @@ public class StringUtils {
      * @param obj 原字符串
      * @return 单引号包含的原字符串
      */
-    private static String quotaMark(Object obj) {
+    public static String quotaMark(Object obj) {
         String srcStr = String.valueOf(obj);
         if (obj instanceof CharSequence) {
+            // fix #79
             return StringEscape.escapeString(srcStr);
         }
         return srcStr;
@@ -319,61 +307,43 @@ public class StringUtils {
      * @param coll 集合
      * @return 单引号包含的原字符串的集合形式
      */
-    private static String quotaMarkList(Collection<?> coll) {
-        return coll.stream().map(StringUtils::quotaMark).collect(sqlJoinCollector());
-    }
-
-    /**
-     * 替换字符序列中满足条件的部分,参数为 匹配的 matcher,返回值需要是字符序列
-     * 所有的参数都不能为 null,否则会抛出 NPE 错误,这是来自 JAVA 的错误!
-     *
-     * @param origin   原字符串
-     * @param pattern  用于匹配的正则表达式
-     * @param replacer 替换函数
-     * @return 返回 StringBuilder
-     * @see #replace(CharSequence, Pattern, BiFunction)
-     */
-    public static StringBuilder replace(CharSequence origin, Pattern pattern, Function<Matcher, CharSequence> replacer) {
-        return replace(origin, pattern, (m, i) -> replacer.apply(m));
+    public static String quotaMarkList(Collection<?> coll) {
+        return coll.stream().map(StringUtils::quotaMark)
+            .collect(joining(StringPool.COMMA, StringPool.LEFT_BRACKET, StringPool.RIGHT_BRACKET));
     }
 
     /**
-     * 替换字符序列中满足条件的部分,参数为 匹配的 matcher,和匹配的索引序号,序号从 0 开始
-     * 返回值需要是字符序列
-     *
-     * @param origin   原字符串
-     * @param pattern  用于匹配的正则表达式
-     * @param replacer 替换函数
-     * @return 返回 StringBuilder
+     * <p>
+     * 拼接字符串第二个字符串第一个字母大写
+     * </p>
      */
-    public static StringBuilder replace(CharSequence origin, Pattern pattern, BiFunction<Matcher, Integer, CharSequence> replacer) {
-        StringBuilder builder = new StringBuilder();
-        Matcher matcher = pattern.matcher(origin);
-        int last = 0, idx = 0;
-        while (matcher.find()) {
-            builder.append(origin, last, matcher.start()).append(replacer.apply(matcher, idx++));
-            last = matcher.end();
+    public static String concatCapitalize(String concatStr, final String str) {
+        if (isEmpty(concatStr)) {
+            concatStr = EMPTY;
         }
-        // 如果匹配没有达到结尾,需要追加后面的字符序列;如果没有匹配到任何字符串,该判断同样用于保证字符的完整性
-        int length = origin.length();
-        if (last < length) {
-            builder.append(origin, last, length);
+        if (str == null || str.length() == 0) {
+            return str;
         }
-        return builder;
+
+        final char firstChar = str.charAt(0);
+        if (Character.isTitleCase(firstChar)) {
+            // already capitalized
+            return str;
+        }
+
+        return concatStr + Character.toTitleCase(firstChar) + str.substring(1);
     }
 
     /**
      * <p>
-     * 拼接字符串,第二个字符串第一个字母大写
+     * 字符串第一个字母大写
      * </p>
-     * example : concatCapitalize("is", "male") 返回 isMale
      *
-     * @param first 第一个字符串
-     * @param str   第二个字符串
-     * @return 返回拼接后的字符串
+     * @param str
+     * @return
      */
-    public static String concatCapitalize(String first, String str) {
-        return first + Character.toTitleCase(str.charAt(0)) + str.substring(1);
+    public static String capitalize(final String str) {
+        return concatCapitalize(null, str);
     }
 
     /**
@@ -684,7 +654,6 @@ public class StringUtils {
      *
      * @param propertyName 字段名
      * @param propertyType 字段类型
-     * @return
      */
     public static String removeIsPrefixIfBoolean(String propertyName, Class<?> propertyType) {
         if (isBoolean(propertyType) && propertyName.startsWith(IS)) {
@@ -699,22 +668,6 @@ public class StringUtils {
         return propertyName;
     }
 
-    /**
-     * <p>
-     * 是否为CharSequence类型
-     * </p>
-     *
-     * @param propertyType
-     * @return
-     */
-    public static Boolean isCharSequence(String propertyType) {
-        try {
-            return isCharSequence(Class.forName(propertyType));
-        } catch (ClassNotFoundException e) {
-            return false;
-        }
-    }
-
     /**
      * <p>
      * 是否为Boolean类型(包含普通类型)
@@ -752,7 +705,7 @@ public class StringUtils {
      */
     public static String prefixToLower(String rawString, int index) {
         String beforeChar = rawString.substring(0, index).toLowerCase();
-        String afterChar = rawString.substring(index, rawString.length());
+        String afterChar = rawString.substring(index);
         return beforeChar + afterChar;
     }
 
@@ -768,7 +721,7 @@ public class StringUtils {
      * @return
      */
     public static String removePrefixAfterPrefixToLower(String rawString, int index) {
-        return prefixToLower(rawString.substring(index, rawString.length()), 1);
+        return prefixToLower(rawString.substring(index), 1);
     }
 
     /**