“静态”模式不应该是静态的吗?

时间:2011-02-08 15:53:08

标签: java regex static pattern-matching

我刚刚发现了一些我没写过的代码中的错误,我有点惊讶:

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

尽管此代码在输入数据上严重失败,但我们得到(因为它试图以17.01.2011格式查找日期并返回10396/2011之类的内容然后崩溃,因为它无法解析日期,但真的不是这个问题的重点;)我想知道:

  • 不是 Pattern.compile 的重点之一(通过预编译正则表达式)?

  • 不应该将所有“静态”模式始终编译成静态模式吗?

在网络上有很多例子,其中相同的模式总是使用 Pattern.compile 重新编译,我开始怀疑我是否在看东西。

不是(假设字符串是静态的,因此不是动态构造的):

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

总是优先于非静态模式引用吗?

5 个答案:

答案 0 :(得分:26)

  1. 是的,预编译Pattern的全部意义只是执行一次。
  2. 这实际上取决于你将如何使用它,但一般来说,存储在static字段中的预编译模式应该没问题。 (与Matcher不同,它们不是线程安全的,因此根本不应该存储在字段中,静态或不存在。)
  3. 在静态初始化程序中编译模式的唯一警告是,如果模式不编译并且静态初始化程序抛出异常,则错误的来源可能非常令人讨厌。这是一个小的可维护性问题,但值得一提。

答案 1 :(得分:11)

首先,模式中的错误是因为点(。)匹配所有内容。如果你想匹配点(。)你必须在正则表达式中转义它:

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

其次,Pattern.compile()是一种沉重的方法。始终建议仅初始化静态模式(我指的是未动态更改或未动态生成的模式)。实现此目的的一种流行方法是将Pattern.compile()放入静态初始化程序中。

您可以使用其他方法。例如,使用单例模式或使用创建单例对象的框架(如Spring)。

答案 2 :(得分:3)

是的,在每次使用时编译模式都是浪费,静态定义它会带来更好的性能。有关类似的讨论,请参阅this SO thread

答案 3 :(得分:0)

只要加载了类,静态模式就会保留在内存中。

如果你担心内存并希望暂时使用一次丢弃的Pattern并且在完成后可以收集垃圾,那么你可以使用非静态{{ 1}}。

答案 4 :(得分:0)

这是一个经典的时间与内存的权衡。 如果您只编译一次Pattern,请不要将其粘贴在静态字段中。 如果您测量编译模式很慢,请预编译并将其放在静态字段中。