String类下的replace()和replaceAll()方法解析

### 问题
在java java.lang.String类中,针对字符串或字符替换有如下方法,这些方法有哪些区别呢?

```java
java.lang.String.replace(char, char)
java.lang.String.replace(CharSequence, CharSequence)
java.lang.String.replaceAll(String, String)
java.lang.String.replaceFirst(String, String)
```

### 源码解析

*话不多说,从源码入手(注:代码为JDK8源码)*
#### replace(char, char)

```java
public String replace(char oldChar, char newChar) {
	if (oldChar != newChar) {
		int len = value.length;
		int i = -1;
		char[] val = value; /* avoid getfield opcode */

		while (++i < len) {
			if (val[i] == oldChar) {
				break;
			}
		}
		if (i < len) {
			char buf[] = new char[len];
			for (int j = 0; j < i; j++) {
				buf[j] = val[j];
			}
			while (i < len) {
				char c = val[i];
				buf[i] = (c == oldChar) ? newChar : c;
				i++;
			}
			return new String(buf, true);
		}
	}
	return this;
}
```

**说明:**通过源码看到,对于char型数据的replace,大概流程就是遍历String的value数组,依次替换新旧字符,最后返回一个新的String实例,如果新旧字符相同或者没有找到旧字符,直接返回原字符串的引用。

> 这里有一个小细节,此replace首先进行`avoid getfield opcode `操作,主要原因是:在一个方法中需要大量引用实例域变量的时候,使用方法中的局部变量代替引用可以减少**getfield**操作的次数,提高性能。见【 [String 源码"avoid getfield opcode"作用](https://blog.csdn.net/gaopu12345/article/details/52084218 "String 源码"avoid getfield opcode"作用")】

#### replace(CharSequence, CharSequence)

```java
public String replace(CharSequence target, CharSequence replacement) {
	return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
			this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
}
```

**说明:** 可以看到,对于`java.lang.CharSequence`型(`java.lang.String`是其子类)数据,replace方法内部使用了正则表达式类处理,对匹配到的所有字符串都替换,需要注意的是,方法忽略了正则表达式元数据和特殊字符,所以不可以使用正则表达式语法。对于`java.util.regex.Pattern.compile(String regex, int flags)`方法,`Pattern.LITERAL`模式表示忽略参数`regex`中的正则表达式元字符和转义字符,将其当成普通文本处理,而`java.util.regex.Matcher.quoteReplacement(String)`方法表示忽略斜线(“\”)和美元符号(“$”)的特殊含义。

#### replaceAll(String, String)
```java
public String replaceAll(String regex, String replacement) {
	return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
```
**说明:**此方法和java.lang.String.replace(CharSequence, CharSequence)方法一样使用了正则表达式类处理,同样对匹配的字符串全局替换,不过其没有对参数`regex`、`replacement`做特殊处理,参数可以使用正则表达式语法。`regex`和`replacement`都需要注意正则语法的正确性,会抛出正则异常。

#### replaceFirst(String, String)
```java
public String replaceFirst(String regex, String replacement) {
	return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
}
```
**说明:**此方法和`replaceAll(String, String)`类似,不过只替换首次匹配到的字符串。

### 总结
- replace(char, char) : 参数是字符,新字符全部替换旧字符

- replace(CharSequence, CharSequence) : 参数是CharSequence型,不支持正则表达式,新旧字符串全部替换

- replaceAll(String, String) : 参数是String型,支持正则表达式,替换全部匹配到的字符串

- replaceFirst(String, String) : 参数是String型,支持正则表达式,替换首次匹配到的字符串

- [注]:正则表达式中存在贪心匹配与否的问题,默认为贪心匹配,使用`?`表示不贪心匹配。

- 简单测试
代码:
```java
public void replaceTest() {
	String test = "AA[A]BA";
	System.out.println(test.replace('A', '='));
	System.out.println(test.replace("[A]", "="));
	System.out.println(test.replaceAll("[A]", "="));
	System.out.println(test.replaceFirst("[A]", "="));
	System.out.println(test.replaceAll("[A]", "$"));
}
```
输出:
		==[=]B=
		AA=BA
		==[=]B=
		=A[A]BA
		抛异常:`java.lang.IllegalArgumentException: Illegal group reference: group index is missing`

:unamused:



------------
> 本文由 [叶不空](https://yebukong.com "叶不空") 创作,采用 [知识共享署名 4.0 国际许可协议](https://creativecommons.org/licenses/by/4.0/ "知识共享署名 4.0 国际许可协议")进行许可,转载请附上链接!
> 本文链接: [https://yebukong.com/article/1105158438217842689.html](https://yebukong.com/article/1105158438217842689.html "String类下的replace()和replaceAll()方法解析")
                        
(°ο°)评论插件未能完成加载!