【发布时间】:2014-07-30 01:59:12
【问题描述】:
String 类有一些我不明白为什么要这样实现的方法... replace 就是其中之一。
public String replace(CharSequence target, CharSequence replacement) {
return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
}
与更简单、更高效(快速!)的方法相比,是否有一些显着优势?
public static String replace(String string, String searchFor, String replaceWith) {
StringBuilder result=new StringBuilder();
int index=0;
int beginIndex=0;
while((index=string.indexOf(searchFor, index))!=-1){
result.append(string.substring(beginIndex, index)+replaceWith);
index+=searchFor.length();
beginIndex=index;
}
result.append(string.substring(beginIndex, string.length()));
return result.toString();
}
Java 7 的统计数据:
1,000,000 次迭代
在“a.b.c”中将“b”替换为“x”
结果:“a.x.c”
时代:
string.replace: 485ms
string.replaceAll:490ms
优化替换 = 180ms
Java 7 split 方法等代码经过大量优化,尽可能避免模式编译/正则表达式处理:
public String[] split(String regex, int limit) {
/* fastpath if the regex is a
(1)one-char String and this character is not one of the
RegEx's meta characters ".$|()[{^?*+\\", or
(2)two-char String and the first char is the backslash and
the second is not the ascii digit or ascii letter.
*/
char ch = 0;
if (((regex.value.length == 1 &&
".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
(regex.length() == 2 &&
regex.charAt(0) == '\\' &&
(((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
((ch-'a')|('z'-ch)) < 0 &&
((ch-'A')|('Z'-ch)) < 0)) &&
(ch < Character.MIN_HIGH_SURROGATE ||
ch > Character.MAX_LOW_SURROGATE))
{
int off = 0;
int next = 0;
boolean limited = limit > 0;
ArrayList<String> list = new ArrayList<>();
while ((next = indexOf(ch, off)) != -1) {
if (!limited || list.size() < limit - 1) {
list.add(substring(off, next));
off = next + 1;
} else { // last one
//assert (list.size() == limit - 1);
list.add(substring(off, value.length));
off = value.length;
break;
}
}
// If no match was found, return this
if (off == 0)
return new String[]{this};
// Add remaining segment
if (!limited || list.size() < limit)
list.add(substring(off, value.length));
// Construct result
int resultSize = list.size();
if (limit == 0)
while (resultSize > 0 && list.get(resultSize - 1).length() == 0)
resultSize--;
String[] result = new String[resultSize];
return list.subList(0, resultSize).toArray(result);
}
return Pattern.compile(regex).split(this, limit);
}
遵循replace方法的逻辑:
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
拆分实现应该是:
public String[] split(String regex, int limit) {
return Pattern.compile(regex).split(this, limit);
}
性能损失与替换方法上的损失相差不远。出于某种原因,Oracle 在某些方法上提供了 fastpath 方法,而不是在其他方法上。
【问题讨论】:
-
"Java原生方法实现的原因是什么?"
-
他们的
replace()使用他们的replaceAll()。那里有什么问题?为什么要复制代码进行替换? -
replace方法做高效replaceAll(即不涉及regex)
-
@HenryKeiter - 但
replace不进行正则表达式处理。 -
我的猜测是,在某一时刻,他们正在重新设计所有毛茸茸的 String 函数以解决一些变化(可能在用 CharSequence 替换 String 时),并且使用通用代码更容易/更安全可能而不是自定义编码每个功能。
标签: java string methods jvm implementation