Оценка основных ответов с помощью теста производительности, который подтверждает опасения, что текущий выбранный ответ делает дорогостоящие операции регулярного выражения под капотом
На сегодняшний день предоставленные ответы представлены в 3 основных стилях (без учета ответа JavaScript;)):
- Использовать String.replace (charsToDelete, ""); который использует регулярные выражения под капотом
- Используйте лямбду
- Используйте простую реализацию Java
С точки зрения размера кода, String.replace является наиболее кратким. Простая реализация Java немного меньше и чище (IMHO), чем лямбда (не поймите меня неправильно - я часто использую лямбды там, где они уместны)
Скорость выполнения была в порядке от самой быстрой до самой медленной: простая реализация 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.
Реализация 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));
}
}