2014-11-05 57 views
8

我需要有一个模式删除,如果出现很长的字符串。但它出现在字符串中是一个难以置信的边缘情况。如果找不到匹配项,替换会做什么? (引擎盖下)

如果我这样做:

str = str.replace("pattern", ""); 

那么它看起来像我创建一个新的字符串(因为Java字符串是不可变的),这将是一种浪费,如果原来的字符串被罚款。我应该首先检查一场比赛,然后只在发现比赛时才进行替换?

+0

'如果找不到匹配项,替换操作会怎样?'Ans;它按原样打印原始字符串。 – 2014-11-05 06:27:10

+1

@AvinashRaj确实。你读完了吗? – ColBeseder 2014-11-05 06:28:37

+1

我发现的一个版本的String.java似乎经过了正则表达式模式匹配器来实现'replace()',即使没有涉及正则表达式。看起来这可能会让事情变慢一些,但是你必须对它进行基准测试,并且JVM的答案可能会有所不同。在任何情况下,由于javadoc没有指定,所以不要**替换为'=='或'!='的结果。 – ajb 2014-11-05 06:46:41

回答

10

简短的回答

检查各种实现方式的文件,没有一个似乎需要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,并可能与以下引用的内容不同步。如果更改影响正确性,请发表评论。

让我们看看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的实现返回相同的字符串。

+0

有趣的观察。 +1 :) – TheLostMind 2014-11-05 12:28:15

2

我还没有找到一个明确的答案(从文档),但我想这一点在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一些基准,以肯定知道如果有任何优势。

1

确定..在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()

现在匹配()方法将在这里返回一个新的匹配。只要注意了matchertext领域将是当前对象(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 
+0

很酷。你有没有参考Java规范? – ColBeseder 2014-11-05 06:35:38

+0

@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

+3

这是对替换(char,char)的引用。这不是问题中使用的方法。替换的javaDoc(CharSequence,CharSequence)在这种情况下没有指定所需的行为。 – Eran 2014-11-05 06:39:15

相关问题