Pattern.split比String.split慢

时间:2015-04-01 14:12:15

标签: java regex string split

有两种方法:

private static void normalSplit(String base){
    base.split("\\.");
}

private static final Pattern p = Pattern.compile("\\.");

private static void patternSplit(String base){
    //use the static field above
    p.split(base);

}

我在主方法中测试它们是这样的:

public static void main(String[] args) throws Exception{
    long start = System.currentTimeMillis();
    String longstr = "a.b.c.d.e.f.g.h.i.j";//use any long string you like
    for(int i=0;i<300000;i++){
        normalSplit(longstr);//switch to patternSplit to see the difference
    }
    System.out.println((System.currentTimeMillis()-start)/1000.0);
}

直觉上,我认为String.split最终会调用Pattern.compile.split(经过大量的额外工作)来做真实的事情。我可以提前构造Pattern对象(它是线程安全的)并加速分裂。

但事实是,使用预先构建的模式比直接调用String.split 慢得多。我在它们上尝试了一个长度为50个字符的字符串(使用MyEclipse),直接调用只消耗了使用预构建的Pattern对象的一半时间。

有人可以告诉我为什么会这样吗?

3 个答案:

答案 0 :(得分:4)

这可能取决于Java的实际实现。我使用的是OpenJDK 7,这里String.split确实调用了Pattern.compile(regex).split(this, limit),但只有在要分割的字符串regex时才更多而不是一个字符。

有关源代码,请参阅here,第2312行。

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.count == 1 &&
       // a bunch of other checks and lots of low-level code
       return list.subList(0, resultSize).toArray(result);
   }
   return Pattern.compile(regex).split(this, limit);
}

当您按"\\."分割时,它正在使用&#34;快速路径&#34;。也就是说,如果你正在使用OpenJDK。

答案 1 :(得分:2)

这是String.split行为的变化,该行为是在Java 7中进行的。这是我们7u40中的have

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) ||
         (regex.length() == 2 &&
          regex.charAt(0) == '\\' &&
          (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
          ((ch-'a')|('z'-ch)) < 0 &&
          ((ch-'A')|('Z'-ch)) < 0)) &&
        (ch < Character.MIN_HIGH_SURROGATE ||
         ch > Character.MAX_LOW_SURROGATE))
    {
        //do stuff
        return list.subList(0, resultSize).toArray(result);
    }
    return Pattern.compile(regex).split(this, limit);
}

这就是6-b14

中的had
public String[] split(String regex, int limit) {
    return Pattern.compile(regex).split(this, limit);
}

答案 2 :(得分:0)

我认为这只能通过JIT优化来解释,String.split内部实现如下:

Pattern.compile(regex).split(this, limit);

并且当它在String.class中时它工作得更快,但是当我在测试中使用相同的代码时:

    for (int i = 0; i < 300000; i++) {
        //base.split("\\.");// switch to patternSplit to see the difference
        //p.split(base);
        Pattern.compile("\\.").split(base, 0);
    }

我得到与p.split(base)

相同的结果