[Guava源码日报](2)Strings分析

时间:2021-07-29 20:45:52

我们先看大体看一下Strings的源码:

 
 
  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5. package com.google.common.base;
  6. import com.google.common.annotations.GwtCompatible;
  7. import com.google.common.annotations.VisibleForTesting;
  8. import com.google.common.base.Preconditions;
  9. import javax.annotation.CheckReturnValue;
  10. import javax.annotation.Nullable;
  11. @CheckReturnValue
  12. @GwtCompatible
  13. public final class Strings {
  14.    private Strings() {
  15.    }
  16.    public static String nullToEmpty(@Nullable String string) {
  17.        return string == null?"":string;
  18.    }
  19.    @Nullable
  20.    public static String emptyToNull(@Nullable String string) {
  21.        return isNullOrEmpty(string)?null:string;
  22.    }
  23.    public static boolean isNullOrEmpty(@Nullable String string) {
  24.        return string == null || string.length() == 0;
  25.    }
  26.    public static String padStart(String string, int minLength, char padChar) {
  27.        Preconditions.checkNotNull(string);
  28.        if(string.length() >= minLength) {
  29.            return string;
  30.        } else {
  31.            StringBuilder sb = new StringBuilder(minLength);
  32.            for(int i = string.length(); i < minLength; ++i) {
  33.                sb.append(padChar);
  34.            }
  35.            sb.append(string);
  36.            return sb.toString();
  37.        }
  38.    }
  39.    public static String padEnd(String string, int minLength, char padChar) {
  40.        Preconditions.checkNotNull(string);
  41.        if(string.length() >= minLength) {
  42.            return string;
  43.        } else {
  44.            StringBuilder sb = new StringBuilder(minLength);
  45.            sb.append(string);
  46.            for(int i = string.length(); i < minLength; ++i) {
  47.                sb.append(padChar);
  48.            }
  49.            return sb.toString();
  50.        }
  51.    }
  52.    public static String repeat(String string, int count) {
  53.        Preconditions.checkNotNull(string);
  54.        if(count <= 1) {
  55.            Preconditions.checkArgument(count >= 0, "invalid count: %s", new Object[]{Integer.valueOf(count)});
  56.            return count == 0?"":string;
  57.        } else {
  58.            int len = string.length();
  59.            long longSize = (long)len * (long)count;
  60.            int size = (int)longSize;
  61.            if((long)size != longSize) {
  62.                throw new ArrayIndexOutOfBoundsException("Required array size too large: " + longSize);
  63.            } else {
  64.                char[] array = new char[size];
  65.                string.getChars(0, len, array, 0);
  66.                int n;
  67.                for(n = len; n < size - n; n <<= 1) {
  68.                    System.arraycopy(array, 0, array, n, n);
  69.                }
  70.                System.arraycopy(array, 0, array, n, size - n);
  71.                return new String(array);
  72.            }
  73.        }
  74.    }
  75.    public static String commonPrefix(CharSequence a, CharSequence b) {
  76.        Preconditions.checkNotNull(a);
  77.        Preconditions.checkNotNull(b);
  78.        int maxPrefixLength = Math.min(a.length(), b.length());
  79.        int p;
  80.        for(p = 0; p < maxPrefixLength && a.charAt(p) == b.charAt(p); ++p) {
  81.            ;
  82.        }
  83.        if(validSurrogatePairAt(a, p - 1) || validSurrogatePairAt(b, p - 1)) {
  84.            --p;
  85.        }
  86.        return a.subSequence(0, p).toString();
  87.    }
  88.    public static String commonSuffix(CharSequence a, CharSequence b) {
  89.        Preconditions.checkNotNull(a);
  90.        Preconditions.checkNotNull(b);
  91.        int maxSuffixLength = Math.min(a.length(), b.length());
  92.        int s;
  93.        for(s = 0; s < maxSuffixLength && a.charAt(a.length() - s - 1) == b.charAt(b.length() - s - 1); ++s) {
  94.            ;
  95.        }
  96.        if(validSurrogatePairAt(a, a.length() - s - 1) || validSurrogatePairAt(b, b.length() - s - 1)) {
  97.            --s;
  98.        }
  99.        return a.subSequence(a.length() - s, a.length()).toString();
  100.    }
  101.    @VisibleForTesting
  102.    static boolean validSurrogatePairAt(CharSequence string, int index) {
  103.        return index >= 0 && index <= string.length() - 2 && Character.isHighSurrogate(string.charAt(index)) && Character.isLowSurrogate(string.charAt(index + 1));
  104.    }
  105. }

现在我们具体看一下每个方法具体含义以及使用方式:

(1)私有构造器

 
 
  1. private Strings() {}

静态方式使用strings,所以不需要使用权限为public的构造器,设置为private更合理。

(2)isNullOrEmpty

 
 
  1. public static boolean isNullOrEmpty(@Nullable String string) {
  2.     return string == null || string.length() == 0;
  3. }

@Nullable 表示该参数变量可以为空。

含义:如果传入的参数string变量为null或者为空,则返回true,否则返回false。

(3)nullToEmpty

 
 
  1. public static String nullToEmpty(@Nullable String string) {
  2.     return string == null?"":string;
  3. }

含义:如果传入的参数string变量不为null,则返回该string变量,否则返回空字符串。使用此方法的目的是使null转换为空字符串。

(4)emptyToNull(@Nullable String string)

 
 
  1. @Nullable
  2. public static String emptyToNull(@Nullable String string) {
  3.    return isNullOrEmpty(string) ? null : string;
  4. }

含义:

如果传入的参数string变量不为空或者null,则返回该string变量,否则返回null。使用此方法的目的是使空字符串转换为null。

(5)padStart(String string,int minLength,char padChar) 

含义:

从开始位置使用padChar传入的字符补全字符串,长度至少为minLength。即如果如果给定的字符串的长度已经大于minLength,则不用补全字符串。

举例:

 
 
  1. // 使用字符0从开始位置填充补全字符串,长度至少为5
  2. String padStartResult = Strings.padStart("123", 5, '0');
  3. System.out.println("padStartResult is " + padStartResult);
  4. // 使用字符0从开始位置填充补全字符串,长度至少为3
  5. String padStartResult2 = Strings.padStart("12345", 3, '0');
  6. System.out.println("padStartResult is " + padStartResult2);

结果:

 
 
  1. padStartResult is 00123
  2. padStartResult is 12345

源码分析:

 
 
  1.    /**
  2.     *
  3.     * @param string 待补全字符串
  4.     * @param minLength 补全后的长度至少为minLength
  5.     * @param padChar 填充的字符
  6.     * @return 返回补全后的字符串
  7.     */
  8.    public static String padStart(String string, int minLength, char padChar) {
  9.        // 先决条件 检查是否为null
  10.        Preconditions.checkNotNull(string);
  11.        // 如果字符串本身长度大于minLength(最低要求)则直接返回
  12.        if(string.length() >= minLength) {
  13.            return string;
  14.        }
  15.        // 如果不够minLength,则需要填充
  16.        else {
  17.            // 开辟minLength大小空间
  18.            StringBuilder sb = new StringBuilder(minLength);
  19.            // 使用padChar字符在字符串开始填充直至达到minLength
  20.            for(int i = string.length(); i < minLength; ++i) {
  21.                sb.append(padChar);
  22.            }
  23.            sb.append(string);
  24.            return sb.toString();
  25.        }
  26.    }

注意:待补全字符串string不能为null,否则抛出异常

[Guava源码日报](2)Strings分析

(6)padEnd(String string,int minLength,char padChar) 

含义:

从字符串后使用padChar字符填充字符串,使长度达到minLength。如果如果给定的字符串的长度已经大于等于minLength,则不用补全字符串。

举例:

 
 
  1. // 使用字符0从字符串末尾填充补全字符串,长度不足6进行补全
  2. String padEndResult = Strings.padEnd("123", 6, '0');
  3. System.out.println("padEndResult is " + padEndResult);
  4. // 使用字符0从字符串末尾填充补全字符串,长度至不足3进行补全
  5. String padEndResult2 = Strings.padEnd("12345", 4, '0');
  6. System.out.println("padEndResult is " + padEndResult2);

结果:

 
 
  1. padEndResult is 123000
  2. padEndResult is 12345

源码分析:

 
 
  1.    /**
  2.     *
  3.     * @param string 待补全字符串
  4.     * @param minLength 补全后的长度至少为minLength
  5.     * @param padChar 填充字符
  6.     * @return 返回补全后的字符串
  7.     */
  8.    public static String padEnd(String string, int minLength, char padChar) {
  9.        // 先决条件 检查是否为null
  10.        Preconditions.checkNotNull(string);
  11.        // 如果字符串本身长度大于等于minLength(最低要求)则直接返回
  12.        if(string.length() >= minLength) {
  13.            return string;
  14.        }
  15.        // 如果不够minLength,则需要填充
  16.        else {
  17.            // 开辟minLength大小空间
  18.            StringBuilder sb = new StringBuilder(minLength);
  19.            sb.append(string);
  20.            // 使用padChar字符在字符串后填充直至字符串长度达到minLength
  21.            for(int i = string.length(); i < minLength; ++i) {
  22.                sb.append(padChar);
  23.            }
  24.            return sb.toString();
  25.        }
  26.    }

(7)repeat(String string,int count)

含义:


举例:

 
 
  1. String repeatStr = Strings.repeat("123",3);
  2. System.out.println("repeatStr is " + repeatStr);
  3. String repeatStr2 = Strings.repeat("12",0);
  4. System.out.println("repeatStr is " + repeatStr2);

结果:

 
 
  1. repeatStr is 123123123
  2. repeatStr is

源码分析:

 
 
  1. /**
  2.     *
  3.     * @param string 待重复字符串
  4.     * @param count 重复次数
  5.     * @return
  6.     */
  7.    public static String repeat(String string, int count) {
  8.        // 先决条件 检查是否为null
  9.        Preconditions.checkNotNull(string);
  10.        // 重复次数小于等于1
  11.        if(count <= 1) {
  12.            // 重复次数必须大于等于0 小于0报非法参数异常
  13.            Preconditions.checkArgument(count >= 0, "invalid count: %s", new Object[]{Integer.valueOf(count)});
  14.            // 如果重复次数为0则返回空字符串
  15.            return count == 0?"":string;
  16.        }
  17.        // 重复次数大于1
  18.        else {
  19.            int len = string.length();
  20.            // 计算重复后的大小
  21.            long longSize = (long)len * (long)count;
  22.            // long 防止溢出
  23.            int size = (int)longSize;
  24.            // 判断是否溢出 抛出数组下标越界异常
  25.            if((long)size != longSize) {
  26.                throw new ArrayIndexOutOfBoundsException("Required array size too large: " + longSize);
  27.            }
  28.            else {
  29.                // 开辟size大小空间
  30.                char[] array = new char[size];
  31.                // 把这个字符串中的[0,len)区间字符复制到目标字符数组[0,len)区间
  32.                string.getChars(0, len, array, 0);
  33.                int n;
  34.                for(n = len; n < size - n; n <<= 1) {
  35.                    // 复制源数组中[0,n)区间数据到目标数组[n,2n)区间中
  36.                    System.arraycopy(array, 0, array, n, n);
  37.                }
  38.                // 复制源数组中[0,size - n)区间数据到目标数组[n,size)区间中
  39.                System.arraycopy(array, 0, array, n, size - n);
  40.                return new String(array);
  41.            }
  42.        }
  43.    }

备注:

 
 
  1. public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)

java.lang.String.getChars() 方法从这个字符串中的字符复制到目标字符数组。要复制的第一个字符在索引srcBegin处,被复制的最后一个字符是在srcEnd-1位置,即要复制的字符区间为[srcBegin,srcEnd)。字符被复制到子数组的dstBegin位置。

 
 
  1. public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

复制指定的源容器数据到目标容器,从源容器指定的位置开始,复制到目标容器的指定位置。src容器的[srcPos,srcPos+len)区间数据复制到目标容器的[destPos,destPos+len)区间。


注意:count必须大于等于0,否则报非法参数异常。

[Guava源码日报](2)Strings分析

(8)validSurrogatePairAt(CharSequence string, int index)

含义:

判断最后两个字符是不是合法的“Java 平台增补字符”

源码分析:

 
 
  1.    @VisibleForTesting
  2.    static boolean validSurrogatePairAt(CharSequence string, int index) {
  3.        return index >= 0 && index <= string.length() - 2 && Character.isHighSurrogate(string.charAt(index)) && Character.isLowSurrogate(string.charAt(index + 1));
  4.    }

Character.isHighSurrogate   确定给定char值是Unicode高代理项代码单元(也称为高级代理项代码单元)。这个值并不代表字符本身,而是在UTF-16编码的补充的字符的表示被使用。

Character.isLowSurrogate  确定给定char值是否为一个Unicode低代理项代码单元(也称为尾部代理项代码单元)。这些值并不代表本身的字符,但用于表示增补字符的UTF-16编码。

(9)commonPrefix(CharSequence a, CharSequence b)

含义:

获得两个字符串相同的前缀

举例:

 
 
  1. // 相同前缀
  2. String a = "com.qunar.exercise.exception";
  3. String b = "com.qunar.exercise.log";
  4. String ourCommonPrefix = Strings.commonPrefix(a,b);
  5. System.out.println("a,b common prefix is " + ourCommonPrefix);

结果:

 
 
  1. a,b common prefix is com.qunar.exercise.

源码分析:

 
 
  1. /**
  2.     *
  3.     * @param a 字符序列a
  4.     * @param b 字符序列b
  5.     * @return 公共前缀
  6.     */
  7. public static String commonPrefix(CharSequence a, CharSequence b) {
  8.        // Preconditions.checkNotNull 先决条件 判断是否为null
  9.        checkNotNull(a);
  10.        checkNotNull(b);
  11.        // 两者最小长度(公共前缀不超过两者的最小长度)
  12.        int maxPrefixLength = Math.min(a.length(), b.length());
  13.        // 从字符串开始比较是否相同直至失败
  14.        int p = 0;
  15.        while (p < maxPrefixLength && a.charAt(p) == b.charAt(p)) {
  16.            p++;
  17.        }
  18.        // 判断最后两个字符是不是合法的“Java 平台增补字符”
  19.        if (validSurrogatePairAt(a, p - 1) || validSurrogatePairAt(b, p - 1)) {
  20.            p--;
  21.        }
  22.        return a.subSequence(0, p).toString();
  23. }

(10)commonSuffix(CharSequence a, CharSequence b)

含义:

获得两个字符串相同的后缀

举例:

      // 相同后缀
  1. String c = "com.google.Hello";
  2. String d = "com.jd.Hello";
  3. String ourSuffix = Strings.commonSuffix(c,d);
  4. System.out.println("c,d common suffix is " + ourSuffix);

结果:

 
 
  1. c,d common suffix is .Hello

源码分析:

 
 
  1. /**
  2.     *
  3.     * @param a 字符序列a
  4.     * @param b 字符序列b
  5.     * @return 公共后缀
  6.     */
  7. public static String commonSuffix(CharSequence a, CharSequence b) {
  8.        // Preconditions.checkNotNull 先决条件 判断是否为null
  9.        Preconditions.checkNotNull(a);
  10.        Preconditions.checkNotNull(b);
  11.        // 两者最小长度(公共后缀不超过两者的最小长度)
  12.        int maxSuffixLength = Math.min(a.length(), b.length());
  13.        int s;
  14.        // 从字符串末尾开始比较,查看是否相同直至失败
  15.        for(s = 0; s < maxSuffixLength && a.charAt(a.length() - s - 1) == b.charAt(b.length() - s - 1); ++s) {
  16.            ;
  17.        }
  18.        // 判断最后两个字符是不是合法的“Java 平台增补字符” ?
  19.        if(validSurrogatePairAt(a, a.length() - s - 1) || validSurrogatePairAt(b, b.length() - s - 1)) {
  20.            --s;
  21.        }
  22.        return a.subSequence(a.length() - s, a.length()).toString();
  23. }