我需要有一個模式刪除,如果出現很長的字符串。但它出現在字符串中是一個難以置信的邊緣情況。如果找不到匹配項,替換會做什麼? (引擎蓋下)
如果我這樣做:
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