String
package java.lang; import java.io.ObjectStreamField; import java.io.UnsupportedEncodingException; import java.lang.annotation.Native; import java.lang.invoke.MethodHandles; import java.lang.constant.Constable; import java.lang.constant.ConstantDesc; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Formatter; import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.Optional; import java.util.Spliterator; import java.util.StringJoiner; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; import java.util.stream.StreamSupport; import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.vm.annotation.Stable; import static java.util.function.Predicate.not; /** * final不可被继承 * Serializable:序列化接口,标志性接口,没有方法 * Comparable:比较接口,方法compareTo * CharSequence:描述字符串结构,方法-length(),charAt(int index),截取字符串subSequence(int start, int end) * Constable:表示该类型的值是常量。可以在常量池中定义,方法-describeConstable * ConstantDesc:返回当前对象,方法-resolveConstantDesc。该接口用法目前比较迷 */ public final class String implements java.io.Serializable, Comparable<String>, CharSequence, Constable, ConstantDesc { /** * 注解@Stable,对于被这个注解修饰的变量或者数组,值或其中所有只能被修改一次 * 引用类型初始为null,原生类型初始为0,他们能被修改为非null或者非0只能修改一次 */ @Stable private final byte[] value; /** * 用于编码字节的编码的标识符,分为 LATIN1 与 UTF16 * coder一般只有两个值:LATIN1-0,UTF16-1 * Latin1是ISO-8859-1的别名 */ private final byte coder; private int hash; // Default to 0 private boolean hashIsZero; // Default to false; /** * Serializable接口的字段 * 序列化机制是通过判断类的serialVersionUID来验证版本一致性的 * 在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较 * 如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException */ private static final long serialVersionUID = -6849794470754667710L; static final boolean COMPACT_STRINGS; static { COMPACT_STRINGS = true; // 启用byte数组压缩,两个字节存储。在方法isLatin1进行控制。默认是UTF16 } /** * ObjectStreamField描述串行化类中串行化字段的类 * */ private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; public String() { this.value = "".value; this.coder = "".coder; } @HotSpotIntrinsicCandidate public String(String original) { this.value = original.value; this.coder = original.coder; this.hash = original.hash; } public String(char value[]) { this(value, 0, value.length, null); } public String(char value[], int offset, int count) { this(value, offset, count, rangeCheck(value, offset, count)); } /** * 返回的是类Void,不是void。Void表示空。 */ private static Void rangeCheck(char[] value, int offset, int count) { checkBoundsOffCount(offset, count, value.length); return null; } /** * 这构造器在编码上优化了内存空间 */ public String(int[] codePoints, int offset, int count) { checkBoundsOffCount(offset, count, codePoints.length); if (count == 0) { this.value = "".value; this.coder = "".coder; return; } if (COMPACT_STRINGS) { // 根据latin1编码 byte[] val = StringLatin1.toBytes(codePoints, offset, count); if (val != null) { // 如果都是单字节字符,就以LATIN1编码 this.coder = LATIN1; this.value = val; return; } } // 没有压缩的话,默认是UTF16,根据UTF16编码 this.coder = UTF16; this.value = StringUTF16.toBytes(codePoints, offset, count); } /** * 不推荐使用 */ @Deprecated(since="1.1") public String(byte ascii[], int hibyte, int offset, int count) { checkBoundsOffCount(offset, count, ascii.length); if (count == 0) { this.value = "".value; this.coder = "".coder; return; } if (COMPACT_STRINGS && (byte)hibyte == 0) { this.value = Arrays.copyOfRange(ascii, offset, offset + count); this.coder = LATIN1; } else { hibyte <<= 8; byte[] val = StringUTF16.newBytesFor(count); for (int i = 0; i < count; i++) { StringUTF16.putChar(val, i, hibyte | (ascii[offset++] & 0xff)); } this.value = val; this.coder = UTF16; } } /** * 不推荐使用 * */ @Deprecated(since="1.1") public String(byte ascii[], int hibyte) { this(ascii, hibyte, 0, ascii.length); } /** * 根据编码生成String */ public String(byte bytes[], int offset, int length, String charsetName) throws UnsupportedEncodingException { if (charsetName == null) throw new NullPointerException("charsetName"); checkBoundsOffCount(offset, length, bytes.length); StringCoding.Result ret = StringCoding.decode(charsetName, bytes, offset, length); this.value = ret.value; this.coder = ret.coder; } /** * 根据编码生成String */ public String(byte bytes[], int offset, int length, Charset charset) { if (charset == null) throw new NullPointerException("charset"); checkBoundsOffCount(offset, length, bytes.length); StringCoding.Result ret = StringCoding.decode(charset, bytes, offset, length); this.value = ret.value; this.coder = ret.coder; } public String(byte bytes[], String charsetName) throws UnsupportedEncodingException { this(bytes, 0, bytes.length, charsetName); } public String(byte bytes[], Charset charset) { this(bytes, 0, bytes.length, charset); } public String(byte bytes[], int offset, int length) { checkBoundsOffCount(offset, length, bytes.length); StringCoding.Result ret = StringCoding.decode(bytes, offset, length); this.value = ret.value; this.coder = ret.coder; } public String(byte[] bytes) { this(bytes, 0, bytes.length); } public String(StringBuffer buffer) { this(buffer.toString()); } public String(StringBuilder builder) { this(builder, null); } public int length() { return value.length >> coder(); } public boolean isEmpty() { return value.length == 0; } public char charAt(int index) { if (isLatin1()) { return StringLatin1.charAt(value, index); } else { return StringUTF16.charAt(value, index); } } /** * 返回指定索引处的字符(Unicode 代码点) */ public int codePointAt(int index) { if (isLatin1()) { checkIndex(index, value.length); return value[index] & 0xff; } int length = value.length >> 1; checkIndex(index, length); return StringUTF16.codePointAt(value, index, length); } /** * 提取前一个索引字符代码点 */ public int codePointBefore(int index) { int i = index - 1; if (i < 0 || i >= length()) { throw new StringIndexOutOfBoundsException(index); } if (isLatin1()) { return (value[i] & 0xff); } return StringUTF16.codePointBefore(value, index); } /** * 统计unicode字符的数量 */ public int codePointCount(int beginIndex, int endIndex) { if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) { throw new IndexOutOfBoundsException(); } if (isLatin1()) { return endIndex - beginIndex; } return StringUTF16.codePointCount(value, beginIndex, endIndex); } /** * 返回此 String 中从给定的 index 处偏移 codePointOffset 个代码点的索引 */ public int offsetByCodePoints(int index, int codePointOffset) { if (index < 0 || index > length()) { throw new IndexOutOfBoundsException(); } return Character.offsetByCodePoints(this, index, codePointOffset); } /** * 将字符从字符串复制到目标字符数组 */ public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) { checkBoundsBeginEnd(srcBegin, srcEnd, length()); checkBoundsOffCount(dstBegin, srcEnd - srcBegin, dst.length); if (isLatin1()) { StringLatin1.getChars(value, srcBegin, srcEnd, dst, dstBegin); } else { StringUTF16.getChars(value, srcBegin, srcEnd, dst, dstBegin); } } /** * 不推荐使用 */ @Deprecated(since="1.1") public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) { checkBoundsBeginEnd(srcBegin, srcEnd, length()); Objects.requireNonNull(dst); checkBoundsOffCount(dstBegin, srcEnd - srcBegin, dst.length); if (isLatin1()) { StringLatin1.getBytes(value, srcBegin, srcEnd, dst, dstBegin); } else { StringUTF16.getBytes(value, srcBegin, srcEnd, dst, dstBegin); } } public byte[] getBytes(String charsetName) throws UnsupportedEncodingException { if (charsetName == null) throw new NullPointerException(); return StringCoding.encode(charsetName, coder(), value); } public byte[] getBytes(Charset charset) { if (charset == null) throw new NullPointerException(); return StringCoding.encode(charset, coder(), value); } public byte[] getBytes() { return StringCoding.encode(coder(), value); } /** * 重新equals,比较地址或字符串内容 */ public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String aString = (String)anObject; if (!COMPACT_STRINGS || this.coder == aString.coder) { return StringLatin1.equals(value, aString.value); } } return false; } /** * 与equals类似,比较内容 * equals方法只有在另一个对象是String的情况下才可能返回true * contentEquals只要求另一个对象是CharSequence或其子类的对象 */ public boolean contentEquals(StringBuffer sb) { return contentEquals((CharSequence)sb); } /** * 私有方法 * 非同步方式(线程不安全)比较与 AbstractStringBuilder 是否相等, */ private boolean nonSyncContentEquals(AbstractStringBuilder sb) { int len = length(); if (len != sb.length()) { return false; } byte v1[] = value; byte v2[] = sb.getValue(); byte coder = coder(); if (coder == sb.getCoder()) { int n = v1.length; for (int i = 0; i < n; i++) { if (v1[i] != v2[i]) { return false; } } } else { if (coder != LATIN1) { // utf16 str and latin1 abs can never be "equal" return false; } return StringUTF16.contentEquals(v1, v2, len); } return true; } public boolean contentEquals(CharSequence cs) { // Argument is a StringBuffer, StringBuilder if (cs instanceof AbstractStringBuilder) { if (cs instanceof StringBuffer) { synchronized(cs) { return nonSyncContentEquals((AbstractStringBuilder)cs); } } else { return nonSyncContentEquals((AbstractStringBuilder)cs); } } // Argument is a String if (cs instanceof String) { return equals(cs); } // Argument is a generic CharSequence int n = cs.length(); if (n != length()) { return false; } byte[] val = this.value; if (isLatin1()) { for (int i = 0; i < n; i++) { if ((val[i] & 0xff) != cs.charAt(i)) { return false; } } } else { if (!StringUTF16.contentEquals(val, cs, n)) { return false; } } return true; } /** * 不考虑大小写比较 */ public boolean equalsIgnoreCase(String anotherString) { return (this == anotherString) ? true : (anotherString != null) && (anotherString.length() == length()) && regionMatches(true, 0, anotherString, 0, length()); } /** * Comparable接口的比较方法 */ public int compareTo(String anotherString) { byte v1[] = value; byte v2[] = anotherString.value; byte coder = coder(); if (coder == anotherString.coder()) { return coder == LATIN1 ? StringLatin1.compareTo(v1, v2) : StringUTF16.compareTo(v1, v2); } return coder == LATIN1 ? StringLatin1.compareToUTF16(v1, v2) : StringUTF16.compareToLatin1(v1, v2); } public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator(); /** * 内部类 */ private static class CaseInsensitiveComparator implements Comparator<String>, java.io.Serializable { // use serialVersionUID from JDK 1.2.2 for interoperability private static final long serialVersionUID = 8575799808933029326L; public int compare(String s1, String s2) { byte v1[] = s1.value; byte v2[] = s2.value; byte coder = s1.coder(); if (coder == s2.coder()) { return coder == LATIN1 ? StringLatin1.compareToCI(v1, v2) : StringUTF16.compareToCI(v1, v2); } return coder == LATIN1 ? StringLatin1.compareToCI_UTF16(v1, v2) : StringUTF16.compareToCI_Latin1(v1, v2); } /** Replaces the de-serialized object. */ /** * 防止反射破坏单例 */ private Object readResolve() { return CASE_INSENSITIVE_ORDER; } } /** * 忽略大小写比较 */ public int compareToIgnoreCase(String str) { return CASE_INSENSITIVE_ORDER.compare(this, str); } /** * 检测两个字符串在一个区域内是否相等 */ public boolean regionMatches(int toffset, String other, int ooffset, int len) { byte tv[] = value; byte ov[] = other.value; // Note: toffset, ooffset, or len might be near -1>>>1. if ((ooffset < 0) || (toffset < 0) || (toffset > (long)length() - len) || (ooffset > (long)other.length() - len)) { return false; } byte coder = coder(); if (coder == other.coder()) { if (!isLatin1() && (len > 0)) { toffset = toffset << 1; ooffset = ooffset << 1; len = len << 1; } while (len-- > 0) { if (tv[toffset++] != ov[ooffset++]) { return false; } } } else { if (coder == LATIN1) { while (len-- > 0) { if (StringLatin1.getChar(tv, toffset++) != StringUTF16.getChar(ov, ooffset++)) { return false; } } } else { while (len-- > 0) { if (StringUTF16.getChar(tv, toffset++) != StringLatin1.getChar(ov, ooffset++)) { return false; } } } } return true; } /** * 检测两个字符串在一个区域内是否相等(忽略大小写) */ public boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) { if (!ignoreCase) { return regionMatches(toffset, other, ooffset, len); } // Note: toffset, ooffset, or len might be near -1>>>1. if ((ooffset < 0) || (toffset < 0) || (toffset > (long)length() - len) || (ooffset > (long)other.length() - len)) { return false; } byte tv[] = value; byte ov[] = other.value; byte coder = coder(); if (coder == other.coder()) { return coder == LATIN1 ? StringLatin1.regionMatchesCI(tv, toffset, ov, ooffset, len) : StringUTF16.regionMatchesCI(tv, toffset, ov, ooffset, len); } return coder == LATIN1 ? StringLatin1.regionMatchesCI_UTF16(tv, toffset, ov, ooffset, len) : StringUTF16.regionMatchesCI_Latin1(tv, toffset, ov, ooffset, len); } /** * 是否以某字符串开头,可进行偏移操作 */ public boolean startsWith(String prefix, int toffset) { // Note: toffset might be near -1>>>1. if (toffset < 0 || toffset > length() - prefix.length()) { return false; } byte ta[] = value; byte pa[] = prefix.value; int po = 0; int pc = pa.length; byte coder = coder(); if (coder == prefix.coder()) { int to = (coder == LATIN1) ? toffset : toffset << 1; while (po < pc) { if (ta[to++] != pa[po++]) { return false; } } } else { if (coder == LATIN1) { // && pcoder == UTF16 return false; } // coder == UTF16 && pcoder == LATIN1) while (po < pc) { if (StringUTF16.getChar(ta, toffset++) != (pa[po++] & 0xff)) { return false; } } } return true; } public boolean startsWith(String prefix) { return startsWith(prefix, 0); } public boolean endsWith(String suffix) { return startsWith(suffix, length() - suffix.length()); } public int hashCode() { // The hash or hashIsZero fields are subject to a benign data race, // making it crucial to ensure that any observable result of the // calculation in this method stays correct under any possible read of // these fields. Necessary restrictions to allow this to be correct // without explicit memory fences or similar concurrency primitives is // that we can ever only write to one of these two fields for a given // String instance, and that the computation is idempotent and derived // from immutable state int h = hash; if (h == 0 && !hashIsZero) { h = isLatin1() ? StringLatin1.hashCode(value) : StringUTF16.hashCode(value); if (h == 0) { hashIsZero = true; } else { hash = h; } } return h; } /** * ch是ASCII码 */ public int indexOf(int ch) { return indexOf(ch, 0); } public int indexOf(int ch, int fromIndex) { return isLatin1() ? StringLatin1.indexOf(value, ch, fromIndex) : StringUTF16.indexOf(value, ch, fromIndex); } public int lastIndexOf(int ch) { return lastIndexOf(ch, length() - 1); } public int lastIndexOf(int ch, int fromIndex) { return isLatin1() ? StringLatin1.lastIndexOf(value, ch, fromIndex) : StringUTF16.lastIndexOf(value, ch, fromIndex); } public int indexOf(String str) { byte coder = coder(); if (coder == str.coder()) { return isLatin1() ? StringLatin1.indexOf(value, str.value) : StringUTF16.indexOf(value, str.value); } if (coder == LATIN1) { // str.coder == UTF16 return -1; } return StringUTF16.indexOfLatin1(value, str.value); } public int indexOf(String str, int fromIndex) { return indexOf(value, coder(), length(), str, fromIndex); } /** * [indexOf description] * @param {[type]} byte[] src 代表源字符串的字节数组 * @param {[type]} byte srcCoder 代表源字符串的编码方式 * @param {[type]} int srcCount 代表源字符串的长度 * @param {[type]} String tgtStr 代表子串 * @param {[type]} int fromIndex 代表源字符串开始查找的下标位置 * @return {[type]} [description] */ static int indexOf(byte[] src, byte srcCoder, int srcCount, String tgtStr, int fromIndex) { byte[] tgt = tgtStr.value; byte tgtCoder = tgtStr.coder(); int tgtCount = tgtStr.length(); if (fromIndex >= srcCount) { return (tgtCount == 0 ? srcCount : -1); } if (fromIndex < 0) { fromIndex = 0; } if (tgtCount == 0) { return fromIndex; } if (tgtCount > srcCount) { return -1; } if (srcCoder == tgtCoder) { return srcCoder == LATIN1 ? StringLatin1.indexOf(src, srcCount, tgt, tgtCount, fromIndex) : StringUTF16.indexOf(src, srcCount, tgt, tgtCount, fromIndex); } if (srcCoder == LATIN1) { // && tgtCoder == UTF16 return -1; } // srcCoder == UTF16 && tgtCoder == LATIN1) { return StringUTF16.indexOfLatin1(src, srcCount, tgt, tgtCount, fromIndex); } public int lastIndexOf(String str) { return lastIndexOf(str, length()); } public int lastIndexOf(String str, int fromIndex) { return lastIndexOf(value, coder(), length(), str, fromIndex); } static int lastIndexOf(byte[] src, byte srcCoder, int srcCount, String tgtStr, int fromIndex) { byte[] tgt = tgtStr.value; byte tgtCoder = tgtStr.coder(); int tgtCount = tgtStr.length(); /* * Check arguments; return immediately where possible. For * consistency, don't check for null str. */ int rightIndex = srcCount - tgtCount; if (fromIndex > rightIndex) { fromIndex = rightIndex; } if (fromIndex < 0) { return -1; } /* Empty string always matches. */ if (tgtCount == 0) { return fromIndex; } if (srcCoder == tgtCoder) { return srcCoder == LATIN1 ? StringLatin1.lastIndexOf(src, srcCount, tgt, tgtCount, fromIndex) : StringUTF16.lastIndexOf(src, srcCount, tgt, tgtCount, fromIndex); } if (srcCoder == LATIN1) { // && tgtCoder == UTF16 return -1; } // srcCoder == UTF16 && tgtCoder == LATIN1 return StringUTF16.lastIndexOfLatin1(src, srcCount, tgt, tgtCount, fromIndex); } public String substring(int beginIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } int subLen = length() - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } if (beginIndex == 0) { return this; } return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen) : StringUTF16.newString(value, beginIndex, subLen); } public String substring(int beginIndex, int endIndex) { int length = length(); checkBoundsBeginEnd(beginIndex, endIndex, length); int subLen = endIndex - beginIndex; if (beginIndex == 0 && endIndex == length) { return this; } return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen) : StringUTF16.newString(value, beginIndex, subLen); } public CharSequence subSequence(int beginIndex, int endIndex) { return this.substring(beginIndex, endIndex); } public String concat(String str) { if (str.isEmpty()) { return this; } return StringConcatHelper.simpleConcat(this, str); } public String replace(char oldChar, char newChar) { if (oldChar != newChar) { String ret = isLatin1() ? StringLatin1.replace(value, oldChar, newChar) : StringUTF16.replace(value, oldChar, newChar); if (ret != null) { return ret; } } return this; } public boolean matches(String regex) { return Pattern.matches(regex, this); } public boolean contains(CharSequence s) { return indexOf(s.toString()) >= 0; } public String replaceFirst(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceFirst(replacement); } public String replaceAll(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceAll(replacement); } public String replace(CharSequence target, CharSequence replacement) { String trgtStr = target.toString(); String replStr = replacement.toString(); int thisLen = length(); int trgtLen = trgtStr.length(); int replLen = replStr.length(); if (trgtLen > 0) { if (trgtLen == 1 && replLen == 1) { return replace(trgtStr.charAt(0), replStr.charAt(0)); } boolean thisIsLatin1 = this.isLatin1(); boolean trgtIsLatin1 = trgtStr.isLatin1(); boolean replIsLatin1 = replStr.isLatin1(); String ret = (thisIsLatin1 && trgtIsLatin1 && replIsLatin1) ? StringLatin1.replace(value, thisLen, trgtStr.value, trgtLen, replStr.value, replLen) : StringUTF16.replace(value, thisLen, thisIsLatin1, trgtStr.value, trgtLen, trgtIsLatin1, replStr.value, replLen, replIsLatin1); if (ret != null) { return ret; } return this; } else { // trgtLen == 0 int resultLen; try { resultLen = Math.addExact(thisLen, Math.multiplyExact( Math.addExact(thisLen, 1), replLen)); } catch (ArithmeticException ignored) { throw new OutOfMemoryError(); } StringBuilder sb = new StringBuilder(resultLen); sb.append(replStr); for (int i = 0; i < thisLen; ++i) { sb.append(charAt(i)).append(replStr); } return sb.toString(); } } /** * limit为非正整数表示 模式被应用尽可能多的次数 比如-1 * limit =0 表示模式应用尽可能多的次数,数组可以是任意长度,并且结尾空字符串将被丢弃 * limit>0时 那么模式将会应用limit-1次 数组长度不会超过limit */ public String[] split(String regex, int limit) { /* fastpath if the regex is a (1)one-char String and this character is not one of the RegEx's meta characters ".$|()[{^?*+\\", or (2)two-char String and the first char is the backslash and the second is not the ascii digit or ascii letter. */ char ch = 0; if (((regex.length() == 1 && ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) || (regex.length() == 2 && regex.charAt(0) == '\\' && (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 && ((ch-'a')|('z'-ch)) < 0 && ((ch-'A')|('Z'-ch)) < 0)) && (ch < Character.MIN_HIGH_SURROGATE || ch > Character.MAX_LOW_SURROGATE)) { int off = 0; int next = 0; boolean limited = limit > 0; ArrayList<String> list = new ArrayList<>(); while ((next = indexOf(ch, off)) != -1) { if (!limited || list.size() < limit - 1) { list.add(substring(off, next)); off = next + 1; } else { // last one //assert (list.size() == limit - 1); int last = length(); list.add(substring(off, last)); off = last; break; } } // If no match was found, return this if (off == 0) return new String[]{this}; // Add remaining segment if (!limited || list.size() < limit) list.add(substring(off, length())); // Construct result int resultSize = list.size(); if (limit == 0) { while (resultSize > 0 && list.get(resultSize - 1).isEmpty()) { resultSize--; } } String[] result = new String[resultSize]; return list.subList(0, resultSize).toArray(result); } return Pattern.compile(regex).split(this, limit); } public String[] split(String regex) { return split(regex, 0); } /** * [join description] * @param {[type]} CharSequence delimiter 分隔符 * @param {[type]} CharSequence... elements 需要连接的字符数组 * @return {[type]} [description] */ public static String join(CharSequence delimiter, CharSequence... elements) { Objects.requireNonNull(delimiter); Objects.requireNonNull(elements); // Number of elements not likely worth Arrays.stream overhead. StringJoiner joiner = new StringJoiner(delimiter); for (CharSequence cs: elements) { joiner.add(cs); } return joiner.toString(); } public static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements) { Objects.requireNonNull(delimiter); Objects.requireNonNull(elements); StringJoiner joiner = new StringJoiner(delimiter); for (CharSequence cs: elements) { joiner.add(cs); } return joiner.toString(); } /** * 将字符串转换为小写 * @param {[type]} Locale locale 转换规则 * @return {[type]} [description] */ public String toLowerCase(Locale locale) { return isLatin1() ? StringLatin1.toLowerCase(this, value, locale) : StringUTF16.toLowerCase(this, value, locale); } public String toLowerCase() { return toLowerCase(Locale.getDefault()); } public String toUpperCase(Locale locale) { return isLatin1() ? StringLatin1.toUpperCase(this, value, locale) : StringUTF16.toUpperCase(this, value, locale); } public String toUpperCase() { return toUpperCase(Locale.getDefault()); } /** * 移除字符串两侧的空白字符(空格、tab键、换行符) * @return {[type]} [description] */ public String trim() { String ret = isLatin1() ? StringLatin1.trim(value) : StringUTF16.trim(value); return ret == null ? this : ret; } /** * 去掉字符串的开始和结尾的空白字符 * 适用于字符首尾空白是Unicode空白字符的情况 * Character.isWhitespace(c)可以判断是否为Unicode空白字符'\u2000'。 * @return {[type]} [description] */ public String strip() { String ret = isLatin1() ? StringLatin1.strip(value) : StringUTF16.strip(value); return ret == null ? this : ret; } /** * 去掉头部空格 * @return {[type]} [description] */ public String stripLeading() { String ret = isLatin1() ? StringLatin1.stripLeading(value) : StringUTF16.stripLeading(value); return ret == null ? this : ret; } /** * 去掉尾部空格 * @return {[type]} [description] */ public String stripTrailing() { String ret = isLatin1() ? StringLatin1.stripTrailing(value) : StringUTF16.stripTrailing(value); return ret == null ? this : ret; } /** * 字符串为空或只包含空格 * @return {Boolean} [description] */ public boolean isBlank() { return indexOfNonWhitespace() == length(); } /** * 返回一个字符串 Stream, 可以识别 \n 和 \r 换行符换行 * XX.lines().count() 可以计算行数 * @return {[type]} [description] */ public Stream<String> lines() { return isLatin1() ? StringLatin1.lines(value) : StringUTF16.lines(value); } /** * 控制每行开头增加或减少几个空格,n为正数时增加,n为负数时减少 * @param {[type]} int n [description] * @return {[type]} [description] */ public String indent(int n) { if (isEmpty()) { return ""; } Stream<String> stream = lines(); if (n > 0) { final String spaces = " ".repeat(n); stream = stream.map(s -> spaces + s); } else if (n == Integer.MIN_VALUE) { stream = stream.map(s -> s.stripLeading()); } else if (n < 0) { stream = stream.map(s -> s.substring(Math.min(-n, s.indexOfNonWhitespace()))); } return stream.collect(Collectors.joining("\n", "", "\n")); } private int indexOfNonWhitespace() { return isLatin1() ? StringLatin1.indexOfNonWhitespace(value) : StringUTF16.indexOfNonWhitespace(value); } private int lastIndexOfNonWhitespace() { return isLatin1() ? StringLatin1.lastIndexOfNonWhitespace(value) : StringUTF16.lastIndexOfNonWhitespace(value); } /** * 不推荐使用 */ @Deprecated(forRemoval=true, since="13") public String stripIndent() { int length = length(); if (length == 0) { return ""; } char lastChar = charAt(length - 1); boolean optOut = lastChar == '\n' || lastChar == '\r'; List<String> lines = lines().collect(Collectors.toList()); final int outdent = optOut ? 0 : outdent(lines); return lines.stream() .map(line -> { int firstNonWhitespace = line.indexOfNonWhitespace(); int lastNonWhitespace = line.lastIndexOfNonWhitespace(); int incidentalWhitespace = Math.min(outdent, firstNonWhitespace); return firstNonWhitespace > lastNonWhitespace ? "" : line.substring(incidentalWhitespace, lastNonWhitespace); }) .collect(Collectors.joining("\n", "", optOut ? "\n" : "")); } private static int outdent(List<String> lines) { // Note: outdent is guaranteed to be zero or positive number. // If there isn't a non-blank line then the last must be blank int outdent = Integer.MAX_VALUE; for (String line : lines) { int leadingWhitespace = line.indexOfNonWhitespace(); if (leadingWhitespace != line.length()) { outdent = Integer.min(outdent, leadingWhitespace); } } String lastLine = lines.get(lines.size() - 1); if (lastLine.isBlank()) { outdent = Integer.min(outdent, lastLine.length()); } return outdent; } /** * 不推荐使用 */ @Deprecated(forRemoval=true, since="13") public String translateEscapes() { if (isEmpty()) { return ""; } char[] chars = toCharArray(); int length = chars.length; int from = 0; int to = 0; while (from < length) { char ch = chars[from++]; if (ch == '\\') { ch = from < length ? chars[from++] : '\0'; switch (ch) { case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case '\'': case '\"': case '\\': // as is break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': int limit = Integer.min(from + (ch <= '3' ? 2 : 1), length); int code = ch - '0'; while (from < limit) { ch = chars[from]; if (ch < '0' || '7' < ch) { break; } from++; code = (code << 3) | (ch - '0'); } ch = (char)code; break; default: { String msg = String.format( "Invalid escape sequence: \\%c \\\\u%04X", ch, (int)ch); throw new IllegalArgumentException(msg); } } } chars[to++] = ch; } return new String(chars, 0, to); } /** * 字符串转换 * @param {[type]} Function<? super String, ? extends R> f 函数式接口 Function * @return {[type]} [description] */ public <R> R transform(Function<? super String, ? extends R> f) { return f.apply(this); } /** * This object (which is already a string!) is itself returned. * * @return the string itself. */ public String toString() { return this; } /** * 返回代表字符代码的int(IntStream)流 */ @Override public IntStream chars() { return StreamSupport.intStream( isLatin1() ? new StringLatin1.CharsSpliterator(value, Spliterator.IMMUTABLE) : new StringUTF16.CharsSpliterator(value, Spliterator.IMMUTABLE), false); } /** * 返回所有代码点值的Stream */ @Override public IntStream codePoints() { return StreamSupport.intStream( isLatin1() ? new StringLatin1.CharsSpliterator(value, Spliterator.IMMUTABLE) : new StringUTF16.CodePointsSpliterator(value, Spliterator.IMMUTABLE), false); } public char[] toCharArray() { return isLatin1() ? StringLatin1.toChars(value) : StringUTF16.toChars(value); } /** * 示例:String.format("你可以成为%s,他也可以成为%s","平凡的人","不平凡的人") ------> * 你可以成为平凡的人,他也可以成为不平凡的人 * @param {[type]} String format [description] * @param {[type]} Object... args [description] * @return {[type]} [description] */ public static String format(String format, Object... args) { return new Formatter().format(format, args).toString(); } public static String format(Locale l, String format, Object... args) { return new Formatter(l).format(format, args).toString(); } /** * 不推荐使用 */ @Deprecated(forRemoval=true, since="13") public String formatted(Object... args) { return new Formatter().format(this, args).toString(); } public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); } public static String valueOf(char data[]) { return new String(data); } public static String valueOf(char data[], int offset, int count) { return new String(data, offset, count); } public static String copyValueOf(char data[], int offset, int count) { return new String(data, offset, count); } public static String copyValueOf(char data[]) { return new String(data); } public static String valueOf(boolean b) { return b ? "true" : "false"; } public static String valueOf(char c) { if (COMPACT_STRINGS && StringLatin1.canEncode(c)) { return new String(StringLatin1.toBytes(c), LATIN1); } return new String(StringUTF16.toBytes(c), UTF16); } public static String valueOf(int i) { return Integer.toString(i); } public static String valueOf(long l) { return Long.toString(l); } public static String valueOf(float f) { return Float.toString(f); } public static String valueOf(double d) { return Double.toString(d); } public native String intern(); /** * 示例 String str = "abc"; * String repeated = str.repeat(3); * repeated.equals("abcabcabc") = true; * 重复字符串 * @param {[type]} int count [description] * @return {[type]} [description] */ public String repeat(int count) { if (count < 0) { throw new IllegalArgumentException("count is negative: " + count); } if (count == 1) { return this; } final int len = value.length; if (len == 0 || count == 0) { return ""; } if (len == 1) { final byte[] single = new byte[count]; Arrays.fill(single, value[0]); return new String(single, coder); } if (Integer.MAX_VALUE / count < len) { throw new OutOfMemoryError("Repeating " + len + " bytes String " + count + " times will produce a String exceeding maximum size."); } final int limit = len * count; final byte[] multiple = new byte[limit]; System.arraycopy(value, 0, multiple, 0, len); int copied = len; for (; copied < limit - copied; copied <<= 1) { System.arraycopy(multiple, 0, multiple, copied, copied); } System.arraycopy(multiple, 0, multiple, copied, limit - copied); return new String(multiple, coder); } void getBytes(byte dst[], int dstBegin, byte coder) { if (coder() == coder) { System.arraycopy(value, 0, dst, dstBegin << coder, value.length); } else { // this.coder == LATIN && coder == UTF16 StringLatin1.inflate(value, 0, dst, dstBegin, value.length); } } String(char[] value, int off, int len, Void sig) { if (len == 0) { this.value = "".value; this.coder = "".coder; return; } if (COMPACT_STRINGS) { byte[] val = StringUTF16.compress(value, off, len); if (val != null) { this.value = val; this.coder = LATIN1; return; } } this.coder = UTF16; this.value = StringUTF16.toBytes(value, off, len); } String(AbstractStringBuilder asb, Void sig) { byte[] val = asb.getValue(); int length = asb.length(); if (asb.isLatin1()) { this.coder = LATIN1; this.value = Arrays.copyOfRange(val, 0, length); } else { if (COMPACT_STRINGS) { byte[] buf = StringUTF16.compress(val, 0, length); if (buf != null) { this.coder = LATIN1; this.value = buf; return; } } this.coder = UTF16; this.value = Arrays.copyOfRange(val, 0, length << 1); } } String(byte[] value, byte coder) { this.value = value; this.coder = coder; } byte coder() { return COMPACT_STRINGS ? coder : UTF16; } byte[] value() { return value; } boolean isLatin1() { return COMPACT_STRINGS && coder == LATIN1; } @Native static final byte LATIN1 = 0; @Native static final byte UTF16 = 1; /** * 检查越界 * @param {[type]} int index [description] * @param {[type]} int length [description] * @return {[type]} [description] */ static void checkIndex(int index, int length) { if (index < 0 || index >= length) { throw new StringIndexOutOfBoundsException("index " + index + ",length " + length); } } static void checkOffset(int offset, int length) { if (offset < 0 || offset > length) { throw new StringIndexOutOfBoundsException("offset " + offset + ",length " + length); } } /** * 检查是否越界 */ static void checkBoundsOffCount(int offset, int count, int length) { if (offset < 0 || count < 0 || offset > length - count) { throw new StringIndexOutOfBoundsException( "offset " + offset + ", count " + count + ", length " + length); } } static void checkBoundsBeginEnd(int begin, int end, int length) { if (begin < 0 || begin > end || end > length) { throw new StringIndexOutOfBoundsException( "begin " + begin + ", end " + end + ", length " + length); } } static String valueOfCodePoint(int codePoint) { if (COMPACT_STRINGS && StringLatin1.canEncode(codePoint)) { return new String(StringLatin1.toBytes((char)codePoint), LATIN1); } else if (Character.isBmpCodePoint(codePoint)) { return new String(StringUTF16.toBytes((char)codePoint), UTF16); } else if (Character.isSupplementaryCodePoint(codePoint)) { return new String(StringUTF16.toBytesSupplementary(codePoint), UTF16); } throw new IllegalArgumentException( format("Not a valid Unicode code point: 0x%X", codePoint)); } /** * 来自接口Constable,这类型的值是常量,可以在JVMS 4.4常量池中定义 */ @Override public Optional<String> describeConstable() { return Optional.of(this); } /** * 来自接口ConstantDesc */ @Override public String resolveConstantDesc(MethodHandles.Lookup lookup) { return this; } }
花出去的时间,总会有收获