2011-02-08 13 views
18

acabo encontrado un fallo en algún código que no he escrito y estoy un poco sorprendido:¿No deberían los patrones "estáticos" ser siempre estáticos?

Pattern pattern = Pattern.compile("\\d{1,2}.\\d{1,2}.\\d{4}"); 
Matcher matcher = pattern.matcher(s); 

A pesar de que este código no mal en los datos de entrada obtenemos (porque se trata de encontrar fechas en el formato 17.01.2011 y vuelva cosas como 10396/2011 y luego se estrelló debido a que no puede analizar la fecha, pero que realmente no es el punto de esta pregunta;) me pregunto:

  • no es uno de los puntos de Pa ttern.compile para ser una optimización de velocidad (por pre-compilación de expresiones regulares)?

  • no debería todo el patrón "estático" ser siempre ¿compilado en el patrón estático?

Hay tantos ejemplos, todos alrededor de la web, donde el mismo patrón siempre se vuelve a compilar utilizando Pattern.compile que empiezo a preguntarme si estoy viendo cosas o no.

no es (suponiendo que la cadena es estática y por lo tanto no construye dinámicamente):

static Pattern pattern = Pattern.compile("\\d{1,2}.\\d{1,2}.\\d{4}"); 

siempre preferible más de una referencia patrón no estática?

+4

El error en el patrón es que '.' coincide con cualquier cosa. Use '\ .' (o mejor' \\. '; La primera barra invertida es para Java) para arreglar eso. –

+0

@Donal Fellows: muchas gracias, sé que sé, solo quería pegar el código roto mientras lo leía. Para mí hay ** dos ** WTF en este código: primero que la compilación de patrones no es estática y luego que es una especie de problema * regexp-ahora-tienes-dos-problemas * :) – Gugussee

+1

Todo las respuestas que dicen que compilar estáticamente es mejor son correctas. Pero hay un poco de optimización prematura aquí. Si ve muchos ejemplos en la web usando Pattern.compile no estáticamente, es probable que sea porque simplemente no es un cuello de botella muy a menudo, y puede ser un poco más fácil de leer o mantener de esa manera. Mida siempre antes de optimizar, de lo contrario, puede descubrir que el tiempo dedicado simplemente a explorar el problema fue mayor que todo el tiempo de CPU que su programa pasará en Pattern.compile juntos :-). – Avi

Respuesta

23
  1. Sí, el objetivo de precompilar un Pattern es hacerlo solo una vez.
  2. Realmente depende de cómo va a usarlo, pero, en general, los patrones precompilados almacenados en los campos static deberían estar bien. (A diferencia de Matcher s, que no están en hebras y por lo tanto no debería realmente ser almacenados en campos en absoluto, estática o no.)

La única advertencia con la compilación de los patrones en inicializadores estáticos es que si el patrón doesn' t compilar y el inicializador estático arroja una excepción, la fuente del error puede ser bastante molesta para rastrear. Es un problema menor de mantenimiento pero podría valer la pena mencionarlo.

+0

usando un buen IDE seguramente ayuda aquí. .. IntelliJ IDEA señalará claramente los errores en el patrón que no se compilarían (incluso en el código fuente incompleto). – SyntaxT3rr0r

+0

@ SyntaxT3rr0r Esa es una característica muy buena. (Por cierto, no me olvidé de su pregunta de agente-GC, me acabo de dar cuenta de que olvidé cómo codificar en C, por lo que me lleva un poco más de tiempo encontrar una solución de trabajo.) – biziclop

+0

http: // stackoverflow.com/questions/1360113/is-java-regex-thread-safe –

11

primero, el error en el patrón se debe a que el punto (.) Coincide con todo. (.) Si desea hacer coincidir puntos que tiene que escapar de ella en expresiones regulares:

Pattern pattern = Pattern.compile("\\d{1,2}\\.\\d{1,2}\\.\\d{4}");

En segundo lugar, Pattern.compile() es un método pesado. Siempre se recomienda inicializar el patrón estático (me refiero a los patrones que no se cambian o no se generan sobre la marcha) solo una vez. Una de las formas populares de lograr esto es poner el Pattern.compile() en el inicializador estático.

Puede usar otro enfoque. Por ejemplo, utilizando un patrón singleton o usando framework que crea objetos singleton (como Spring).

+0

Sé que es porque el punto coincide con todo;) Creo que voy a ir con la estática inicializador en este caso: usar el patrón singleton de Spring para crear una instancia de un patrón parece un poco extremo :) – Gugussee

+0

Claro, no sugiero que uses Spring solo para crear la instancia de patrón. Acabo de decir que hay soluciones distintas de la inicialización estática. Quiero decir que si ya está utilizando la primavera en su proyecto, puede poner todos los patrones en un solo bean y recuperarlos cuando lo necesite. – AlexR

+3

@AlexR ¿Cómo la creación de instancias del 'Patrón' en un inicializador estático, como' static {} ', difiere de la declaración del' Pattern' como un campo estático, como 'private static final Pattern pattern = Pattern.compile()'? –

3

Sí, compilar el Patrón en cada uso es un desperdicio, y su definición estática daría como resultado un mejor rendimiento. Ver this SO thread para una discusión similar.

+0

gracias por el enlace – Gugussee

0

Los patrones estáticos permanecerían en la memoria mientras se cargue la clase.

Si le preocupa la memoria y quiere un descartable Pattern que utiliza de vez en cuando y que puede ser recogido cuando termina con él, entonces puede usar un Pattern no estático.

0

Es una compensación clásica de tiempo vs. memoria. Si está compilando un patrón solo una vez, no lo pegue en un campo estático. Si midió que compilar Patrones es lento, precompórelo y póngalo en un campo estático.

Cuestiones relacionadas