Ocena głównych odpowiedzi za pomocą wskaźnika wydajności, który potwierdza obawy, że obecnie wybrana odpowiedź powoduje, że kosztowne operacje wyrażenia regularnego są pod maską
Do tej pory dostarczone odpowiedzi są dostępne w 3 głównych stylach (ignorując odpowiedź JavaScript;)):
- Użyj String.replace (charsToDelete, „”); który używa wyrażenia regularnego pod maską
- Użyj Lambda
- Użyj prostej implementacji Java
Jeśli chodzi o rozmiar kodu, String.replace jest najbardziej zwięzły. Prosta implementacja Java jest nieco mniejsza i czystsza (IMHO) niż Lambda (nie zrozum mnie źle - często używam Lambdas tam, gdzie są odpowiednie)
Szybkość wykonywania była w kolejności od najszybszej do najwolniejszej: prosta implementacja Java, Lambda, a następnie String.replace () (która wywołuje wyrażenie regularne).
Zdecydowanie najszybszą implementacją była dostrojona prosta implementacja Java, która wstępnie przypisuje bufor StringBuilder do maksymalnej możliwej długości wyniku, a następnie po prostu dołącza znaki do bufora, które nie znajdują się w ciągu „znaków do usunięcia”. Pozwala to uniknąć wszelkich realokacji, które wystąpiłyby dla ciągów o długości> 16 znaków (domyślny przydział dla StringBuilder) i uniknięto trafienia wydajnościowego „przesuń w lewo” usuwania znaków z kopii ciągu znaków, który jest implementacją Lambda.
Poniższy kod uruchamia prosty test porównawczy, uruchamiając każdą implementację 1 000 000 razy i rejestruje upływ czasu.
Dokładne wyniki różnią się przy każdym uruchomieniu, ale kolejność wydajności nigdy się nie zmienia:
Start simple Java implementation
Time: 157 ms
Start Lambda implementation
Time: 253 ms
Start String.replace implementation
Time: 634 ms
Implementacja Lambda (skopiowana z odpowiedzi Kaplana) może być wolniejsza, ponieważ wykonuje „przesunięcie w lewo o jeden” spośród wszystkich znaków na prawo od usuwanej postaci. Oczywiście pogorszy się to w przypadku dłuższych ciągów znaków z dużą ilością znaków wymagających usunięcia. Również w samej implementacji Lambda mogą występować pewne koszty ogólne.
Implementacja String.replace używa wyrażenia regularnego i wykonuje „kompilację” wyrażenia regularnego przy każdym wywołaniu. Optymalizacja tego polega na bezpośrednim użyciu wyrażenia regularnego i buforowaniu skompilowanego wzorca, aby uniknąć kosztu kompilacji za każdym razem.
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));
}
}