Java中StringTokenizer类与String.split方法的性能

在我的软件中,我需要将string拆分成单词。 目前我有超过1900万个文件,每个文件超过30个字。

以下两种方式中的哪一种是最好的方法(就性能而言)?

StringTokenizer sTokenize = new StringTokenizer(s," "); while (sTokenize.hasMoreTokens()) { 

要么

 String[] splitS = s.split(" "); for(int i =0; i < splitS.length; i++) 

如果你的数据已经在数据库中,你需要parsingstring,我会build议反复使用indexOf。 其速度比任何一种解决scheme都快

但是,从数据库获取数据仍然可能要昂贵得多。

 StringBuilder sb = new StringBuilder(); for (int i = 100000; i < 100000 + 60; i++) sb.append(i).append(' '); String sample = sb.toString(); int runs = 100000; for (int i = 0; i < 5; i++) { { long start = System.nanoTime(); for (int r = 0; r < runs; r++) { StringTokenizer st = new StringTokenizer(sample); List<String> list = new ArrayList<String>(); while (st.hasMoreTokens()) list.add(st.nextToken()); } long time = System.nanoTime() - start; System.out.printf("StringTokenizer took an average of %.1f us%n", time / runs / 1000.0); } { long start = System.nanoTime(); Pattern spacePattern = Pattern.compile(" "); for (int r = 0; r < runs; r++) { List<String> list = Arrays.asList(spacePattern.split(sample, 0)); } long time = System.nanoTime() - start; System.out.printf("Pattern.split took an average of %.1f us%n", time / runs / 1000.0); } { long start = System.nanoTime(); for (int r = 0; r < runs; r++) { List<String> list = new ArrayList<String>(); int pos = 0, end; while ((end = sample.indexOf(' ', pos)) >= 0) { list.add(sample.substring(pos, end)); pos = end + 1; } } long time = System.nanoTime() - start; System.out.printf("indexOf loop took an average of %.1f us%n", time / runs / 1000.0); } } 

版画

 StringTokenizer took an average of 5.8 us Pattern.split took an average of 4.8 us indexOf loop took an average of 1.8 us StringTokenizer took an average of 4.9 us Pattern.split took an average of 3.7 us indexOf loop took an average of 1.7 us StringTokenizer took an average of 5.2 us Pattern.split took an average of 3.9 us indexOf loop took an average of 1.8 us StringTokenizer took an average of 5.1 us Pattern.split took an average of 4.1 us indexOf loop took an average of 1.6 us StringTokenizer took an average of 5.0 us Pattern.split took an average of 3.8 us indexOf loop took an average of 1.6 us 

打开一个文件的成本大约是8毫秒。 由于文件非常小,您的caching可能会将性能提高2-5倍。 即使如此,它将花费大约10个小时打开文件。 使用split与StringTokenizer的成本每个远小于0.01 ms。 分析1900万x 30字*每个字8个字母大约需要10秒(大约每2秒1GB)

如果你想提高性能,我build议你有更less的文件。 例如使用数据库。 如果你不想使用SQL数据库,我build议使用这些http://nosql-database.org/

在Java 7中分割只是为了这个input调用indexOf, 请参阅源代码 。 拆分应该非常快,接近indexOf的重复调用。

Java API规范build议使用split 。 请参阅StringTokenizer的文档 。

另一件重要的事情,就我注意到,没有logging的是,要求StringTokenizer返回分隔符和标记string(通过使用构造函数StringTokenizer(String str, String delim, boolean returnDelims) )也减less了处理时间。 所以,如果你正在寻找性能,我会build议使用像这样的东西:

 private static final String DELIM = "#"; public void splitIt(String input) { StringTokenizer st = new StringTokenizer(input, DELIM, true); while (st.hasMoreTokens()) { String next = getNext(st); System.out.println(next); } } private String getNext(StringTokenizer st){ String value = st.nextToken(); if (DELIM.equals(value)) value = null; else if (st.hasMoreTokens()) st.nextToken(); return value; } 

尽pipegetNext()方法引入了开销,但是为您丢弃了分隔符,根据我的基准testing,它仍然快了50%。

使用拆分。

StringTokenizer是一个遗留的类,为了兼容性的原因被保留下来,尽pipe在新的代码中它的使用是不鼓励的。 build议任何寻求这种function的人使用拆分方法。

那里有19,000,000份文件需要做什么? 你是否必须定期在所有文件中分词? 或者这是一个单枪杀的问题?

如果一次只显示/请求一个文档,只有30个字,这是一个很小的问题,任何方法都可以工作。

如果一次只能处理所有的文档,只有30个字,这是一个非常小的问题,无论如何你更可能是IO界限。

运行微(而在这种情况下,甚至纳米)的基准,有很多影响你的结果。 JIT优化和垃圾回收等等。

为了从微观基准中获得有意义的结果,请查看jmh库。 它具有优秀的样本捆绑如何运行良好的基准。

不pipe它的遗留状态如何,我希望StringTokenizerString.split()更快,因为它不使用正则expression式:它只是直接扫描input,就像你通过indexOf() 。 事实上, String.split()每次调用时都要编译正则expression式,所以它不像直接使用正则expression式那样高效。

这可能是一个合理的基准使用1.6.0

 http://www.javamex.com/tutorials/regular_expressions/splitting_tokenisation_performance.shtml#.V6-CZvnhCM8 

性能明智的StringTokeniser比分裂更好。 检查下面的代码,

在这里输入图像说明

但根据Java文档,它的使用是不鼓励的。 在这里检查