使用性能基准评估主要答案,确认当前选择的答案会在后台进行昂贵的正则表达式操作
迄今为止,提供的答案有 3 种主要样式(忽略 JavaScript 答案;)):
- 使用 String.replace(charsToDelete, "");它在后台使用正则表达式
- 使用 Lambda
- 使用简单的 Java 实现
就代码大小而言,显然 String.replace 是最简洁的。简单的 Java 实现比 Lambda 更小更干净(恕我直言)(不要误会 - 我经常在适当的地方使用 Lambda)
执行速度从快到慢依次为:简单的 Java 实现、Lambda,然后是 String.replace()(调用正则表达式)。
到目前为止,最快的实现是简单的 Java 实现调整,以便将 StringBuilder 缓冲区预分配到最大可能的结果长度,然后简单地将不在“要删除的字符”字符串中的字符附加到缓冲区。这避免了长度大于 16 个字符的字符串(StringBuilder 的默认分配)会发生的任何重新分配,并且避免了从发生的字符串副本中删除字符的“向左滑动”性能损失是 Lambda 实现。
下面的代码运行一个简单的基准测试,运行每个实现 1,000,000 次并记录经过的时间。
每次运行的确切结果都会有所不同,但执行顺序永远不会改变:
Start simple Java implementation
Time: 157 ms
Start Lambda implementation
Time: 253 ms
Start String.replace implementation
Time: 634 ms
Lambda 实现(从 Kaplan 的答案中复制)可能会更慢,因为它会将所有字符“左移一位”到被删除字符的右侧。对于需要删除大量字符的较长字符串,这显然会变得更糟。 Lambda 实现本身也可能存在一些开销。
String.replace 实现,使用正则表达式并在每次调用时执行正则表达式“编译”。对此的优化是直接使用正则表达式并缓存已编译的模式以避免每次编译的成本。
package com.sample;
import java.util.function.BiFunction;
import java.util.stream.IntStream;
public class Main {
static public String deleteCharsSimple(String fromString, String charsToDelete)
{
StringBuilder buf = new StringBuilder(fromString.length()); // Preallocate to max possible result length
for(int i = 0; i < fromString.length(); i++)
if (charsToDelete.indexOf(fromString.charAt(i)) < 0)
buf.append(fromString.charAt(i)); // char not in chars to delete so add it
return buf.toString();
}
static public String deleteCharsLambda(String fromString1, String charsToDelete)
{
BiFunction<String, String, String> deleteChars = (fromString, chars) -> {
StringBuilder buf = new StringBuilder(fromString);
IntStream.range(0, buf.length()).forEach(i -> {
while (i < buf.length() && chars.indexOf(buf.charAt(i)) >= 0)
buf.deleteCharAt(i);
});
return (buf.toString());
};
return deleteChars.apply(fromString1, charsToDelete);
}
static public String deleteCharsReplace(String fromString, String charsToDelete)
{
return fromString.replace(charsToDelete, "");
}
public static void main(String[] args)
{
String str = "XXXTextX XXto modifyX";
String charsToDelete = "X"; // Should only be one char as per OP's requirement
long start, end;
System.out.println("Start simple");
start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++)
deleteCharsSimple(str, charsToDelete);
end = System.currentTimeMillis();
System.out.println("Time: " + (end - start));
System.out.println("Start lambda");
start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++)
deleteCharsLambda(str, charsToDelete);
end = System.currentTimeMillis();
System.out.println("Time: " + (end - start));
System.out.println("Start replace");
start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++)
deleteCharsReplace(str, charsToDelete);
end = System.currentTimeMillis();
System.out.println("Time: " + (end - start));
}
}