我需要有一个模式删除,如果出现很长的字符串。但它出现在字符串中是一个难以置信的边缘情况。如果找不到匹配项,替换会做什么? (引擎盖下)
如果我这样做:
str = str.replace("pattern", "");
那么它看起来像我创建一个新的字符串(因为Java字符串是不可变的),这将是一种浪费,如果原来的字符串被罚款。我应该首先检查一场比赛,然后只在发现比赛时才进行替换?
我需要有一个模式删除,如果出现很长的字符串。但它出现在字符串中是一个难以置信的边缘情况。如果找不到匹配项,替换会做什么? (引擎盖下)
如果我这样做:
str = str.replace("pattern", "");
那么它看起来像我创建一个新的字符串(因为Java字符串是不可变的),这将是一种浪费,如果原来的字符串被罚款。我应该首先检查一场比赛,然后只在发现比赛时才进行替换?
检查各种实现方式的文件,没有一个似乎需要String.replace(CharSequence, CharSequence)
方法如果找不到匹配,则返回相同的字符串。
没有从文档的要求,执行可能会或可能不会优化没有发现匹配的情况下的方法。最好编写代码,就好像没有优化一样,以确保它在任何实现或版本的JRE上正确运行。
特别是,当发现不匹配,Oracle的执行(版本8-B123)返回相同的字符串对象,而GNU类路径(0.95版本),而不管返回一个新的字符串对象。
如果你能找到任何需要String.replace(CharSequence, CharSequence)
返回时,没有找到匹配的相同String
对象的文档的任何条款,请发表评论。
下面长的答案是要表明,不同的实现可能会或可能不会进行优化,其中没有找到匹配的情况。
让我们看看Oracle的实现和GNU Classpath的实现方法String.replace(CharSequence, CharSequence)
。
注意:这是在撰写时是正确的。虽然链接未来可能不会改变,但链接内容可能会更改为较新版本的GNU Classpath,并可能与以下引用的内容不同步。如果更改影响正确性,请发表评论。
让我们看看GNU Classpath的实现String.replace(CharSequence, CharSequence)
(引用版本0.95)。我们检查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
的构造函数进行操作。最终调用非公开构造函数String(char[], int, int, boolean)
,将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
接口,并且因为字符串通过自己进入Matcher
,让我们看看String.toString
:
public String toString() {
return this;
}
由此,我们可以得出结论:当没有找到匹配项时,Oracle的实现返回相同的字符串。
有趣的观察。 +1 :) – TheLostMind 2014-11-05 12:28:15
我还没有找到一个明确的答案(从文档),但我想这一点在Oracle JRE7,发现replace
返回参考相同的字符串。
这里是我用于测试的代码:
public class NoReplace {
public static void main(String[]args) {
String a = "hello";
/* Test: replacement with no match */
String b = a.replace("X", "H");
/* a and b are still the same string? */
System.out.println(b == a); // true
/* Sanity: replacement WITH a match */
String c = a.replace("h", "H");
/* a and c are still the same string? */
System.out.println(c == a); // false
}
}
但我很希望看到的replace
VS contains
一些基准,以肯定知道如果有任何优势。
确定..在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)
目标串被编译为文字图案。并且通过将调用stringInstance传递给它来调用matcher()
。
现在匹配()方法将在这里返回一个新的匹配。只要注意了matcher
的text
领域将是当前对象(this
)即在其replace()
被称为String对象。
接下来,在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
很酷。你有没有参考Java规范? – ColBeseder 2014-11-05 06:35:38
@ColBeseder - [here](http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replace(char,%20char))是Oracle doc的参考。 – TheLostMind 2014-11-05 06:36:44
这是对替换(char,char)的引用。这不是问题中使用的方法。替换的javaDoc(CharSequence,CharSequence)在这种情况下没有指定所需的行为。 – Eran 2014-11-05 06:39:15
'如果找不到匹配项,替换操作会怎样?'Ans;它按原样打印原始字符串。 – 2014-11-05 06:27:10
@AvinashRaj确实。你读完了吗? – ColBeseder 2014-11-05 06:28:37
我发现的一个版本的String.java似乎经过了正则表达式模式匹配器来实现'replace()',即使没有涉及正则表达式。看起来这可能会让事情变慢一些,但是你必须对它进行基准测试,并且JVM的答案可能会有所不同。在任何情况下,由于javadoc没有指定,所以不要**替换为'=='或'!='的结果。 – ajb 2014-11-05 06:46:41