2011-02-08 4 views
18

Я просто нашел ошибку в какой-то код, который я не писал, и я немного удивлен:Не должны ли статические шаблоны быть статическими?

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

Несмотря на то, что этот код не плохо на входных данных мы получаем (потому что он пытается найти даты в формате 17.01.2011 и получает обратно вещи, как 10396/2011, а затем разбился, потому что не может разобрать дату, но что на самом деле не суть этого вопроса;) Интересно:

  • не является одним из Pa ttern.compile - оптимизация скорости (путем предварительной компиляции регулярных выражений)?

  • не все «статические» шаблоны должны быть всегда скомпилирован в статический шаблон?

Есть так много примеров, все вокруг в Интернет, где та же картина всегда перекомпилированный с помощью Pattern.compile, что я начинаю задаваться вопросом, если я вижу вещи или нет.

Не (при условии, что строка является статическим и, следовательно, не динамически строится):

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

всегда preferrable над нестатической ссылкой шаблон?

+4

Ошибка в шаблоне заключается в том, что '.' соответствует чему угодно. Используйте '\ .' (или, скорее,' \\. '; Первую обратную косую черту для Java), чтобы исправить это. –

+0

@ Donal Fellows: Большое спасибо, я знаю, что знаю, я просто хотел вставить сломанный код, когда прочитал. Для меня есть ** два ** WTF в этом коде: во-первых, что компиляция шаблона не является статичной, а затем во-вторых, что это своего рода грубая проблема * regexp-now-you-have-two-problems *: – Gugussee

+1

Все ответы, которые говорят, что компиляция статически лучше, верны. Но здесь есть немного преждевременная оптимизация. Если вы видите много примеров в Интернете с использованием шаблона Pattern.compile нестатически, это, вероятно, потому, что он просто не является узким местом очень часто и может быть чуть-чуть легче читать или поддерживать этот путь. Всегда измерьте перед оптимизацией, иначе вы можете обнаружить, что время, потраченное на изучение проблемы, было больше, чем все время процессора, которое ваша программа когда-либо проведет в Pattern.compile, вместе взятые :-). – Avi

ответ

23
  1. Да, цель предварительной компиляции Pattern заключается в том, чтобы сделать это только один раз.
  2. Это действительно зависит от того, как вы собираетесь его использовать, но в целом предварительно скомпилированные шаблоны, хранящиеся в полях static, должны быть в порядке. (В отличие от Matcher с, что не поточно-и, следовательно, не должны действительно быть сохранены в полях на всех, статическое или нет.)

Единственное ограничение при компиляции шаблонов в статических инициализаторах является то, что если шаблон Безразлично» t, а статический инициализатор генерирует исключение, источник ошибки может быть весьма раздражающим для отслеживания. Это небольшая проблема ремонтопригодности, но, возможно, стоит упомянуть.

+0

, используя хорошую IDE, безусловно, помогает здесь. .. IntelliJ IDEA четко укажет на ошибки в шаблоне, которые не будут компилироваться (даже при неполном исходном коде). – SyntaxT3rr0r

+0

@ SyntaxT3rr0r Это довольно крутая функция. (Кстати, я не забыл о вашем вопросе агента-GC, я только что понял, что забыл, как писать код на C, так что потребуется немного больше времени, чтобы придумать рабочее решение.) – biziclop

+0

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

11

Во-первых, ошибка в шаблоне - это потому, что точка (.) Соответствует всем. (.) Если вы хотите, чтобы соответствовать точка Вы должны избежать этого в регулярных выражениях:

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

Во-вторых, Pattern.compile() тяжелый метод. Всегда рекомендуется инициализировать статический шаблон (я имею в виду шаблоны, которые не изменяются или не генерируются «на лету») только один раз. Один из популярных способов добиться этого - положить Pattern.compile() в статический инициализатор.

Вы можете использовать другой подход. Например, используя одноэлементный шаблон или используя фреймворк, который создает одноэлементные объекты (например, Spring).

+0

Я знаю, что это потому, что точка соответствует всем;) Я думаю, что поеду со статическим инициализатор в этом случае: использование одноэлементного шаблона Spring для создания одного экземпляра шаблона кажется немного экстремальным :) – Gugussee

+0

Конечно, я не предлагаю использовать Spring только для создания экземпляра шаблона. Я просто сказал, что есть решения, отличные от статической инициализации. Я имею в виду, что если вы уже используете весну в своем проекте, вы можете поместить все шаблоны в один синглтон и получить их, когда вам нужно. – AlexR

+3

@AlexR Как создать экземпляр 'Pattern' в статическом инициализаторе, таком как' static {} ', отличается от объявления' Pattern' как статического поля, такого как 'private static final Pattern pattern = Pattern.compile()'? –

3

Да, составление шаблона при каждом использовании является расточительным, и его определение статически приведет к повышению производительности. См. this SO thread для аналогичного обсуждения.

+0

спасибо за ссылку – Gugussee

0

Статические шаблоны останутся в памяти, пока класс загружен.

Если вы беспокоитесь о памяти и хотите, чтобы вы выбрали Pattern, который вы используете один раз в то время, и вы можете получить мусор, собранный, когда вы закончите с ним, вы можете использовать нестатический Pattern.

0

Это классическое сочетание времени и памяти. Если вы составляете шаблон только один раз, не вставляйте его в статическом поле. Если вы измерили, что скомпилировать паттерны медленно, предварительно скомпилируйте его и поместите в статическое поле.

Смежные вопросы