Оцінка основних відповідей з показником ефективності, який підтверджує занепокоєння, що поточна обрана відповідь робить дорогими операції з вирівнюванням під кришкою
На сьогодні надані відповіді в трьох основних стилях (ігнорування відповіді на JavaScript;)):
- Використовуйте String.replace (charsToDelete, ""); який використовує регулярний вираз під кришкою
- Використовуйте лямбда
- Використовуйте просту реалізацію Java
Щодо розміру коду чітко, String.replace є найбільш стислим. Проста реалізація Java трохи менша та чистіша (IMHO), ніж Lambda (не помиляйтесь, я використовую Lambdas часто там, де вони підходять)
Швидкість виконання була, для того, щоб найшвидше і повільніше: проста реалізація Java, Lambda, а потім String.replace () (що викликає regex).
На сьогоднішній день найбільш швидкою реалізацією була проста реалізація Java, налаштована таким чином, що вона попередньо розміщує буфер StringBuilder до максимально можливої довжини результату, а потім просто додає символи до буфера, які не знаходяться в рядку "символи для видалення". Це дозволяє уникнути перерозподілу, який відбуватиметься для Strings> 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));
}
}