【问题标题】:Java String.split pass in precompiled regex for performance reasons出于性能原因,Java String.split 传入预编译的正则表达式
【发布时间】:2013-02-15 19:03:00
【问题描述】:

正如问题所述,给出以下代码:

public class Foo
{
   public static void main(String[] args)
   {  
         String test = "Cats go meow";  
         String[] tokens = test.split(" ");
   }
}

是否可以按照以下方式在 split 函数中预编译该正则表达式:

public class Foo
{  
   Pattern pattern = Pattern.compile(" ");
   public static void main(String[] args)
   {  
         String test = "Cats go meow";  
         String[] tokens = test.split(pattern);
   }
}

【问题讨论】:

  • split(" ") 更快(见下方评论)
  • @michael_s 我加了评论,请反击。

标签: java regex performance


【解决方案1】:

是的,这是可能的。另外,将pattern设为静态,以便静态方法main可以访问它。

public class Foo
{  
   private static Pattern pattern = Pattern.compile(" ");
   public static void main(String[] args)
   {  
         String test = "Cats go meow";  
         String[] tokens = pattern.split(test);
   }
}

根据String中split方法的docs,可以使用String的split或者Pattern的split,但是String的split编译一个Pattern并调用它的split方法,所以使用Pattern 预编译正则表达式。

【讨论】:

【解决方案2】:

不 - 我认为那是个坏主意!

仔细查看拆分方法的源代码 - 如果字符串只有一个字符(并且不包含正则表达式特殊字符),则实现了一种快捷方式

public String[] split(String regex, int limit) {
    /* fastpath if the regex is a
     (1)one-char String and this character is not one of the
        RegEx's meta characters ".$|()[{^?*+\\", or
     (2)two-char String and the first char is the backslash and
        the second is not the ascii digit or ascii letter.
     */
    char ch = 0;
    if (((regex.value.length == 1 &&
         ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||

所以 - split(" ") 应该快很多。

另一方面,在使用正则表达式时,将它们设为静态最终成员总是一个好主意。

编辑:

对于 String.split,JDK1.7 和 OpenJDK 7 的源代码似乎是相同的——你自己看看: Lines 2312ff.

所以 - 对于更复杂的模式(例如 1 个或多个空格):

   static final Pattern pSpaces = Pattern.compile("[ ]+");

【讨论】:

  • hmm 我会争辩说,while 循环中的 String.split 会使这个声明无效。想反击吗?
  • 我不明白你的意思 - 什么 while 循环?
  • 仅仅因为我的程序没有说明while 循环并不意味着其他程序没有它们。如果我编写了一个必须对一系列行进行标记的解析器,就会有一个 while 循环
  • 那又怎样 - 答案是特定于 split(" ") 的,它比使用 split(pattern) 快得多,其中 pattern 是 Pattern.compile(" ")。是否在循环中无关紧要。无需投票......老实说
  • 是的 - 如果你使用一些花哨的 Open-JDK 也许 - 我只是查看了自 1.4 版以来没有改变的 Oracle-JDK(以前称为 Sun)的源代码 - 好吧 - 没关系- 我们说的是Stringbtw 类的实现
【解决方案3】:
public class Foo
{  
   private static final Pattern pattern = Pattern.compile(" ");
   public static void main(String[] args)
   {  
         String test = "Cats go meow";  
         String[] tokens = pattern.split(test);
   }
}

【讨论】:

  • 还可以考虑将模式设为静态和最终模式。这样可以节省每个实例的编译开销
【解决方案4】:

改用Pattern.split():

String[] tokens = pattern.split(test);

【讨论】:

  • hmm 实际上,这并没有解决模式的预编译问题,因为它是花费“最多”时间的编译步骤
  • @Woot4Moo:我不明白你的最后一句话。一旦你有了Pattern 的实例,正则表达式就已经编译好了,pattern.split() 不需要进一步编译。
  • 我的错误我认为有一种方法可以自己实例化 Pattern。
猜你喜欢
  • 1970-01-01
  • 2012-04-09
  • 1970-01-01
  • 2015-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-30
相关资源
最近更新 更多