如果未找到匹配项,替换会做什么?(在引擎盖下)
我有很长的字符串,如果出现,需要删除一个模式。但是,对于它来说,出现在琴弦中是一个非常罕见的边缘案例。
如果我这样做:
str = str.replace("pattern", "");
然后看起来我正在创建一个新字符串(因为Java字符串是不可变的),如果原始字符串很好,那将是一种浪费。我是否应该先检查匹配项,然后仅在找到匹配项时才替换?
我有很长的字符串,如果出现,需要删除一个模式。但是,对于它来说,出现在琴弦中是一个非常罕见的边缘案例。
如果我这样做:
str = str.replace("pattern", "");
然后看起来我正在创建一个新字符串(因为Java字符串是不可变的),如果原始字符串很好,那将是一种浪费。我是否应该先检查匹配项,然后仅在找到匹配项时才替换?
检查各种实现的文档,如果没有找到匹配项,似乎没有一个要求该方法返回相同的字符串。String.replace(CharSequence, CharSequence)
如果没有文档中的要求,在找不到匹配项的情况下,实现可能会也可能不会优化方法。最好像编写没有优化一样编写代码,以确保它在 JRE 的任何实现或版本上都能正常运行。
特别是,当找不到匹配项时,Oracle 的实现(版本 8-b123)返回相同的 String 对象,而 GNU Classpath(版本 0.95)无论如何都会返回新的 String 对象。
如果您在任何文档中可以找到任何要求 String.replace(CharSequence, CharSequence)
在找不到匹配项时返回同一 String
对象的子句,请发表评论。
下面的长答案是表明,在没有找到匹配项的情况下,不同的实现可能会也可能不会优化。
让我们来看看Oracle的实现和GNU Classpath的方法的实现。String.replace(CharSequence, CharSequence)
注意:截至撰写本文时,这是正确的。虽然链接将来不太可能更改,但链接的内容可能会更改为较新版本的 GNU Classpath,并且可能与下面引用的内容不同步。如果更改影响正确性,请发表评论。
让我们看看GNU Classpath对String.replace(CharSequence,CharSequence)
的实现(引用版本0.95)。
public String replace (CharSequence target, CharSequence replacement)
{
String targetString = target.toString();
String replaceString = replacement.toString();
int targetLength = target.length();
int replaceLength = replacement.length();
int startPos = this.indexOf(targetString);
StringBuilder result = new StringBuilder(this);
while (startPos != -1)
{
// Replace the target with the replacement
result.replace(startPos, startPos + targetLength, replaceString);
// Search for a new occurrence of the target
startPos = result.indexOf(targetString, startPos + replaceLength);
}
return result.toString();
}
让我们检查一下 StringBuilder.toString()
的源代码。由于这决定了返回值,如果复制缓冲区,则我们不需要进一步检查上面的任何代码。StringBuilder.toString()
/**
* Convert this <code>StringBuilder</code> to a <code>String</code>. The
* String is composed of the characters currently in this StringBuilder. Note
* that the result is a copy, and that future modifications to this buffer
* do not affect the String.
*
* @return the characters in this StringBuilder
*/
public String toString()
{
return new String(this);
}
如果文档无法说服您,只需遵循构造函数即可。最终,调用非公共构造函数 String(char[], int, int, boolean),
并将其设置为 ,这意味着新的必须复制缓冲区。String
boolean dont_copy
false
String
589: public String(StringBuilder buffer)
590: {
591: this(buffer.value, 0, buffer.count);
592: }
245: public String(char[] data, int offset, int count)
246: {
247: this(data, offset, count, false);
248: }
594: /**
595: * Special constructor which can share an array when safe to do so.
596: *
597: * @param data the characters to copy
598: * @param offset the location to start from
599: * @param count the number of characters to use
600: * @param dont_copy true if the array is trusted, and need not be copied
601: * @throws NullPointerException if chars is null
602: * @throws StringIndexOutOfBoundsException if bounds check fails
603: */
604: String(char[] data, int offset, int count, boolean dont_copy)
605: {
606: if (offset < 0)
607: throw new StringIndexOutOfBoundsException("offset: " + offset);
608: if (count < 0)
609: throw new StringIndexOutOfBoundsException("count: " + count);
610: // equivalent to: offset + count < 0 || offset + count > data.length
611: if (data.length - offset < count)
612: throw new StringIndexOutOfBoundsException("offset + count: "
613: + (offset + count));
614: if (dont_copy)
615: {
616: value = data;
617: this.offset = offset;
618: }
619: else
620: {
621: value = new char[count];
622: VMSystem.arraycopy(data, offset, value, 0, count);
623: this.offset = 0;
624: }
625: this.count = count;
626: }
这些证据表明 GNU Classpath 的实现不会返回相同的字符串。String.replace(CharSequence, CharSequence)
在Oracle的实现String.replace(CharSequence,CharSequence)
(引用版本8-b123)中,该方法利用类进行替换。Pattern
public String replace(CharSequence target, CharSequence replacement) {
return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
}
Matcher.replaceAll(String)
调用函数,并在找不到匹配项时返回它:toString()
CharSequence
public String replaceAll(String replacement) {
reset();
boolean result = find();
if (result) {
StringBuffer sb = new StringBuffer();
do {
appendReplacement(sb, replacement);
result = find();
} while (result);
appendTail(sb);
return sb.toString();
}
return text.toString();
}
String
实现了 CharSequence
接口,并且由于 String 将自身传递到 中,让我们看一下 String.toString
:Matcher
public String toString() {
return this;
}
由此,我们可以得出结论,当找不到匹配项时,Oracle的实现将返回相同的字符串。
还行。。在Java 8中。这是当您调用 时发生的情况。myString.replace()
public String replace(CharSequence target, CharSequence replacement) {
return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
}
Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
this)
目标字符串被编译为文本模式。并通过将调用字符串实例传递给它来调用它。matcher()
现在,matcher() 方法将在此处返回一个新的匹配器。请注意,的字段将是当前对象 (),即被调用的 String 对象。text
matcher
this
replace()
接下来,我们有以下代码:replaceAll()
boolean result = find();
即
public String replaceAll(String replacement) {
reset();
boolean result = find(); --> returns false.
if (result) {
StringBuffer sb = new StringBuffer();
do {
appendReplacement(sb, replacement);
result = find();
} while (result);
appendTail(sb);
return sb.toString();
}
return text.toString(); --> same String
}
if `find()` returns false, then ,matcher.text is returned which is the original String