最简单的例子是String.split(“something”)方法。
现在,许多这些方法的实际定义是它们都使用正则表达式作为它们的输入参数。这使所有非常强大的构建块。
>每次调用该方法时,它们都会重新编译表达式。因此,它们施加了性能影响。
>我发现在大多数“现实生活”的情况下,这些方法被称为“固定”文本。 split方法的最常见用法更糟:通常使用单个char(通常是“’,a’;’或’&’)来分割。
所以它不仅是默认方法是强大的,他们似乎对他们实际使用的功能强大。在内部,我们开发了一个“fastSplit”方法,拆分固定字符串。我在家里写了一个测试,看看我能做到多快,如果它是一个单一的字符。两者都明显快于“标准”分割方法。
所以我想知道:为什么是Java API选择现在的方式?
什么是好的理由去这里,而不是像split(char)和split(String)和splitRegex(String)。
更新:我一起打了几个电话,看看分割字符串需要多长时间。
简短总结:这是一个很大的区别!
我对每个测试用例做10000000次迭代,总是使用输入
"aap,noot,mies,wim,zus,jet,teun"
并始终使用“,”或“”作为拆分参数。
这是我在我的Linux系统(它是一个Atom D510盒子,所以它有点慢):
fastSplit STRING Test 1 : 11405 milliseconds: Split in several pieces Test 2 : 3018 milliseconds: Split in 2 pieces Test 3 : 4396 milliseconds: Split in 3 pieces homegrown fast splitter based on char Test 4 : 9076 milliseconds: Split in several pieces Test 5 : 2024 milliseconds: Split in 2 pieces Test 6 : 2924 milliseconds: Split in 3 pieces homegrown splitter based on char that always splits in 2 pieces Test 7 : 1230 milliseconds: Split in 2 pieces String.split(regex) Test 8 : 32913 milliseconds: Split in several pieces Test 9 : 30072 milliseconds: Split in 2 pieces Test 10 : 31278 milliseconds: Split in 3 pieces String.split(regex) using precompiled Pattern Test 11 : 26138 milliseconds: Split in several pieces Test 12 : 23612 milliseconds: Split in 2 pieces Test 13 : 24654 milliseconds: Split in 3 pieces StringTokenizer Test 14 : 27616 milliseconds: Split in several pieces Test 15 : 28121 milliseconds: Split in 2 pieces Test 16 : 27739 milliseconds: Split in 3 pieces
正如你可以看到的,如果你有很多“固定字符”拆分做一个很大的不同。
给你们一些洞察力;我目前在Apache日志文件和Hadoop竞技场与一个大网站的数据。所以对我这个东西真的很重要:)
我在这里没有考虑的东西是垃圾收集器。至于我可以告诉编译正则表达式到一个Pattern / Matcher / ..将分配很多对象,需要收集一些时间。所以也许从长远来看,这些版本之间的差异甚至更大….或更小。
我到目前为止的结论:
>只有优化这,如果你有很多字符串来拆分。
>如果你使用regex方法总是预编译如果你重复使用相同的模式。
>忘记(过时)StringTokenizer
>如果你想分割在一个单一的字符,然后使用自定义的方法,特别是如果你只需要拆分成一个特定数量的块(像… 2)。
P.S。我给你所有我自己的分裂的char方法来玩(在许可证下,这个网站上的一切都在:))。我从来没有完全测试他们..玩的开心。
private static String[] stringSplitChar(final String input,final char separator) { int pieces = 0; // First we count how many pieces we will need to store ( = separators + 1 ) int position = 0; do { pieces++; position = input.indexOf(separator,position + 1); } while (position != -1); // Then we allocate memory final String[] result = new String[pieces]; // And start cutting and copying the pieces. int prevIoUsposition = 0; int currentposition = input.indexOf(separator); int piece = 0; final int lastpiece = pieces - 1; while (piece < lastpiece) { result[piece++] = input.substring(prevIoUsposition,currentposition); prevIoUsposition = currentposition + 1; currentposition = input.indexOf(separator,prevIoUsposition); } result[piece] = input.substring(prevIoUsposition); return result; } private static String[] stringSplitChar(final String input,final char separator,final int maxpieces) { if (maxpieces <= 0) { return stringSplitChar(input,separator); } int pieces = maxpieces; // Then we allocate memory final String[] result = new String[pieces]; // And start cutting and copying the pieces. int prevIoUsposition = 0; int currentposition = input.indexOf(separator); int piece = 0; final int lastpiece = pieces - 1; while (currentposition != -1 && piece < lastpiece) { result[piece++] = input.substring(prevIoUsposition,prevIoUsposition); } result[piece] = input.substring(prevIoUsposition); // All remaining array elements are uninitialized and assumed to be null return result; } private static String[] stringChop(final String input,final char separator) { String[] result; // Find the separator. final int separatorIndex = input.indexOf(separator); if (separatorIndex == -1) { result = new String[1]; result[0] = input; } else { result = new String[2]; result[0] = input.substring(0,separatorIndex); result[1] = input.substring(separatorIndex + 1); } return result; }
An invocation of this method of the form
str.split(regex,n)
yields the same result as the expression
Pattern.compile(regex).split(str,n)
也就是说,如果你担心性能,你可以预编译模式,然后重用它:
Pattern p = Pattern.compile(regex); ... String[] tokens1 = p.split(str1); String[] tokens2 = p.split(str2); ...
代替
String[] tokens1 = str1.split(regex); String[] tokens2 = str2.split(regex); ...
我相信这个API设计的主要原因是方便。由于正则表达式包括所有“固定”字符串/字符,它简化了API有一个方法,而不是几个。如果有人担心性能,正则表达式仍然可以如上所示预编译。
我的感觉(我不能回来与任何统计证据)是大多数情况下String.split()用于上下文中的性能不是一个问题。例如。它是一次性的行为,或者性能差异与其他因素相比是可以忽略的。 IMO很少是这样的情况,你在紧缩循环中使用相同的正则表达式数千次拆分字符串,其中性能优化确实有意义。
有趣的是看到一个正则表达式匹配器实现与固定字符串/字符的性能比较与专门的匹配器的性能比较。差异可能不够大,不足以证明单独实现。