Évaluation des principales réponses avec un repère de performance qui confirme les inquiétudes selon lesquelles la réponse actuellement choisie rend les opérations de regex coûteuses sous le capot
À ce jour, les réponses fournies se déclinent en 3 styles principaux (en ignorant la réponse JavaScript;)):
- Utilisez String.replace (charsToDelete, ""); qui utilise des regex sous le capot
- Utilisez Lambda
- Utilisez une implémentation Java simple
En termes de taille de code, String.replace est clairement le plus laconique. L'implémentation Java simple est légèrement plus petite et plus propre (à mon humble avis) que la Lambda (ne vous méprenez pas - j'utilise souvent Lambdas là où elles sont appropriées)
La vitesse d'exécution était, dans l'ordre du plus rapide au plus lent: implémentation Java simple, Lambda puis String.replace () (qui invoque l'expression régulière).
De loin, l'implémentation la plus rapide a été l'implémentation Java simple, réglée de manière à préallouer le tampon StringBuilder à la longueur de résultat maximale possible, puis à simplement ajouter des caractères au tampon qui ne se trouvent pas dans la chaîne "caractères à supprimer". Cela évite toute réallocation qui se produirait pour des chaînes de plus de 16 caractères (l'allocation par défaut pour StringBuilder) et cela évite le hit de performance "slide left" de supprimer des caractères d'une copie de la chaîne qui se produit est l'implémentation Lambda.
Le code ci-dessous exécute un test de référence simple, exécutant chaque implémentation 1 000 000 fois et enregistre le temps écoulé.
Les résultats exacts varient à chaque exécution, mais l'ordre des performances ne change jamais:
Start simple Java implementation
Time: 157 ms
Start Lambda implementation
Time: 253 ms
Start String.replace implementation
Time: 634 ms
L'implémentation Lambda (telle que copiée à partir de la réponse de Kaplan) peut être plus lente car elle effectue un "décalage à gauche d'un" de tous les caractères à droite du caractère supprimé. Cela empirerait évidemment pour les chaînes plus longues avec beaucoup de caractères à supprimer. Il peut également y avoir des frais généraux dans l'implémentation de Lambda elle-même.
L'implémentation String.replace utilise regex et effectue une "compilation" regex à chaque appel. Une optimisation de ceci serait d'utiliser directement l'expression régulière et de mettre en cache le modèle compilé pour éviter le coût de le compiler à chaque fois.
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));
}
}