C'est une question assez simple, mais cela vient d'une personne en C/C++ qui entre dans les subtilités de Java.
Je comprends que je peux lancer jUnit et quelques tests de performance pour obtenir une réponse. mais je me demande si c'est là-bas.
Existe-t-il des différences connues entre String.replaceAll () et Matcher.replaceAll () (sur un objet Matcher créé à partir d'un objet Regex.Pattern) en termes de performances?
En outre, quelles sont les différences ish de l'API de haut niveau entre les deux? (Immutabilité, traitement des valeurs NULL, traitement des chaînes vides, préparation du café, etc.)
Selon la documentation de String.replaceAll
, il est indiqué à propos de l’appel de la méthode:
Une invocation de cette méthode du forme
str.replaceAll(regex, repl)
donne exactement le même résultat que le expressionPattern.compile(regex).matcher(str).replaceAll(repl)
Par conséquent, on peut s'attendre à ce que la performance entre l'appel de String.replaceAll
et la création explicite d'un Matcher
et Pattern
soit identique.
Modifier
Comme indiqué dans les commentaires, la différence de performances étant inexistante, il en irait de même pour un appel unique à replaceAll
à partir de String
ou Matcher
. Toutefois, si vous devez effectuer plusieurs appels à replaceAll
, vous vous attendez à ce que cela soit avantageux conservez un Pattern
compilé, de sorte que la compilation relativement coûteuse de modèles d’expression régulière ne soit pas nécessairement effectuée à chaque fois.
Code source de String.replaceAll()
:
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
Le modèle doit d'abord être compilé - si vous l'exécutez plusieurs fois avec le même modèle sur des chaînes courtes, les performances seront bien meilleures si vous réutilisez un modèle compilé.
La principale différence est que si vous conservez le Pattern
utilisé pour produire le Matcher
, vous pouvez éviter de recompiler la regex chaque fois que vous l’utilisez. En passant par String
, vous n’avez pas la possibilité de "mettre en cache" de la sorte.
Si vous avez une expression rationnelle différente à chaque fois, utiliser String
de la classe replaceAll
convient parfaitement. Si vous appliquez la même expression rationnelle à plusieurs chaînes, créez un Pattern
et réutilisez-le.
Immutabilité/sécurité des threads: les patterns compilés sont immuables, les correspondants ne le sont pas. (voir Java Regex Thread Safe? )
Gestion des chaînes vides: replaceAll doit gérer les chaînes vides avec élégance (il ne correspondra pas à un modèle de chaîne d'entrée vide)
Faire du café, etc.: aux dernières nouvelles, ni String, ni Pattern, ni Matcher n’avaient de fonction API pour cela.
edit: en ce qui concerne la gestion des valeurs NULL, la documentation de String et Pattern ne le dit pas explicitement, mais je soupçonne qu’ils lèveraient une exception NullPointerException car ils s’attendent à une chaîne.
La différence est que String.replaceAll () compile l'expression régulière à chaque appel. Il n'y a pas d'équivalent pour la méthode statique Regex.Replace () de .NET, qui met automatiquement en cache la regex compilée. En règle générale, replaceAll () est quelque chose que vous ne faites qu'une fois, mais si vous voulez l'appeler de manière répétée avec la même expression régulière, en particulier dans une boucle, vous devez créer un objet Pattern et utiliser la méthode Matcher.
Vous pouvez également créer Matcher à l'avance et utiliser sa méthode reset () pour le recibler à chaque utilisation:
Matcher m = Pattern.compile(regex).matcher("");
for (String s : targets)
{
System.out.println(m.reset(s).replaceAll(repl));
}
Bien entendu, l’avantage de la réutilisation du Matcher sur les performances n’est comparable à celui de la réutilisation du motif.
L'implémentation de String.replaceAll
vous dit tout ce que vous devez savoir:
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
(Et les docs disent la même chose.)
Bien que je n'ai pas vérifié la mise en cache, je m'attendrais certainement à ce que la compilation d'un modèle une fois et le maintien d'une référence statique à ce dernier soient plus efficaces que d'appeler Pattern.compile
avec le même modèle à chaque fois. S'il y a un cache, ce sera une petite économie d'efficacité - s'il n'y en avait pas, ce pourrait être un grand.
Les autres réponses couvrent suffisamment la partie performance du PO, mais une autre différence entre Matcher::replaceAll
et String::replaceAll
permet également de compiler votre propre Pattern
. Lorsque vous compilez vous-même une Pattern
, il existe des options telles que des indicateurs pour modifier la façon dont la regex est appliquée. Par exemple:
Pattern myPattern = Pattern.compile(myRegex, Pattern.CASE_INSENSITIVE);
La Matcher
appliquera tous les indicateurs que vous avez définis lorsque vous appelez Matcher::replaceAll
.
Vous pouvez également définir d’autres indicateurs. Je voulais surtout souligner que les API Pattern
et Matcher
ont beaucoup d'options, et c'est la raison principale d'aller au-delà du simple String::replaceAll