java - online - String replaceAll() vs. Matcher replaceAll()(Diferencias de rendimiento)
regular expression generator for java (7)
Código fuente de String.replaceAll()
:
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
Primero tiene que compilar el patrón: si va a ejecutarlo muchas veces con el mismo patrón en cadenas cortas, el rendimiento será mucho mejor si reutiliza un patrón compilado.
Una pregunta bastante simple, pero esto proviene de una persona de C / C ++ que se adentra en las complejidades de Java.
Entiendo que puedo iniciar jUnit y algunas pruebas de mi propio desempeño para obtener una respuesta; pero me pregunto si esto está ahí fuera.
¿Existen diferencias conocidas entre String.replaceAll () y Matcher.replaceAll () (en un objeto Matcher creado a partir de un Regex.Pattern) en términos de rendimiento?
Además, ¿cuáles son las diferencias API de alto nivel entre ambas? (Inmutabilidad, Manejo de NULLs, Manejo de cadenas vacías, preparación de café, etc.)
Inmutabilidad / seguridad del hilo: Los patrones compilados son inmutables, los Matchers no. (Consulte ¿Es seguro Java Regex Thread? )
Manejo de cadenas vacías: replaceAll debe manejar cadenas vacías correctamente (no coincidirá con un patrón de cadena de entrada vacía)
Haciendo café, etc .: lo último que escuché, ni String ni Pattern ni Matcher tenían ninguna característica API para eso.
editar: como para manejar valores NULL, la documentación para Cadena y Patrón no lo dice explícitamente, pero sospecho que lanzarían una NullPointerException ya que esperan una Cadena.
La diferencia es que String.replaceAll () compila la expresión regular cada vez que se invoca. No hay un equivalente para el método Regex.Replace () estático de .NET, que almacena automáticamente en caché la expresión regular compilada. Por lo general, replaceAll () es algo que solo hace una vez, pero si va a llamarlo repetidamente con la misma expresión regular, especialmente en un bucle, debe crear un objeto Pattern y usar el método Matcher.
También puede crear el Matcher con anticipación y usar su método de reinicio () para reorientarlo para cada uso:
Matcher m = Pattern.compile(regex).matcher("");
for (String s : targets)
{
System.out.println(m.reset(s).replaceAll(repl));
}
El beneficio de rendimiento de reutilizar el Matcher, por supuesto, no es tan grande como el de reutilizar el Patrón.
La implementación de String.replaceAll
le dice todo lo que necesita saber:
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
(Y los documentos dicen lo mismo).
Si bien no he verificado el almacenamiento en caché, ciertamente esperaría que compilar un patrón una vez y mantener una referencia estática sea más eficiente que llamar a Pattern.compile
con el mismo patrón cada vez. Si hay un caché, será un ahorro de eficiencia pequeño; si no lo hay, podría ser uno grande.
La principal diferencia es que si mantiene el Pattern
utilizado para producir el Matcher
, puede evitar recompilar la expresión regular cada vez que la use. Al pasar por String
, no tienes la capacidad de "caché" de esta manera.
Si tiene una expresión regular diferente cada vez, usar replaceAll
la clase String
está bien. Si está aplicando la misma expresión regular a muchas cadenas, cree un Pattern
y reutilícelo.
Las otras respuestas cubren suficientemente la parte de rendimiento del OP, pero otra diferencia entre Matcher::replaceAll
y String::replaceAll
es también una razón para compilar su propio Pattern
. Cuando compila un Pattern
usted mismo, hay opciones como indicadores para modificar cómo se aplica la expresión regular. Por ejemplo:
Pattern myPattern = Pattern.compile(myRegex, Pattern.CASE_INSENSITIVE);
El Matcher
aplicará todos los indicadores que establezca cuando llame a Matcher::replaceAll
.
También hay otros indicadores que puede establecer. En general, solo quería señalar que la API Pattern
and Matcher
tiene muchas opciones, y esa es la razón principal para ir más allá del simple String::replaceAll
De acuerdo con la documentación de String.replaceAll
, tiene lo siguiente que decir acerca de llamar al método:
Una invocación de este método de la forma
str.replaceAll(regex, repl)
produce exactamente el mismo resultado que la expresión
Pattern.compile(regex).matcher(str).replaceAll(repl)
Por lo tanto, se puede esperar que el rendimiento entre invocar a String.replaceAll
y crear explícitamente un Matcher
y un Pattern
sea el mismo.
Editar
Como se ha señalado en los comentarios, la diferencia de rendimiento es inexistente para una única llamada a replaceAll
from String
o Matcher
, sin embargo, si uno necesita realizar múltiples llamadas para replaceAll
, se esperaría que sea beneficioso para mantener un Pattern
compilado, por lo que la compilación de patrón de expresión regular relativamente caro no tiene que realizarse siempre.