Java的Scanner vs String.split()vs StringTokenizer; 我应该用哪个?

我目前正在使用split()来扫描一个文件,其中每一行都有'~'分隔的字符串数。 我在某处读到Scanner可以用一个长文件做得更好,性能方面,所以我想考虑一下。

我的问题是:我是否必须创建两个Scanner实例? 也就是说,一个读取一行而另一个基于该行来获取分隔符的标记? 如果我必须这样做,我怀疑我是否会从使用它中获得任何好处。 也许我在这里错过了一些东西?

在单线程模型中有一些关于这些的指标,这是我得到的结果。

 ~~~~~~~~~~~~~~~~~~时间指标~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 ~Tokenenizer |  String.Split()|  while + SubString | 扫描仪|  ScannerWithCompiledPattern~
 ~4.0 ms |  5.1毫秒|  1.2毫秒|  0.5毫秒|  0.1毫秒〜
 ~4.4 ms |  4.8毫秒|  1.1毫秒|  0.1毫秒|  0.1毫秒〜
 ~3.5 ms |  4.7毫秒|  1.2毫秒|  0.1毫秒|  0.1毫秒〜
 ~3.5 ms |  4.7毫秒|  1.1毫秒|  0.1毫秒|  0.1毫秒〜
 ~3.5 ms |  4.7毫秒|  1.1毫秒|  0.1毫秒|  0.1毫秒〜
 ____________________________________________________________________________________________________________

出来的是Scanner提供了最佳性能,现在同样需要在multithreading模式下进行评估! 我的一位资深人士表示,Tokenizer会产生CPU峰值而String.split则没有。

对于处理线,您可以使用扫描仪,并从您可以使用拆分的每一行获取令牌。

 Scanner scanner = new Scanner(new File(loc)); try { while ( scanner.hasNextLine() ){ String[] tokens = scanner.nextLine().split("~"); // do the processing for tokens here } } finally { scanner.close(); } 

您可以使用useDelimiter("~")方法让您使用hasNext()/next()迭代每行上的标记,同时仍然使用hasNextLine()/nextLine()来遍历行本身。

编辑:如果你要进行性能比较,你应该在进行split()测试时预编译正则表达式:

 Pattern splitRegex = Pattern.compile("~"); while ((line = bufferedReader.readLine()) != null) { String[] tokens = splitRegex.split(line); // etc. } 

如果使用String#split(String regex) ,则每次都会重新编译正则表达式。 (扫描程序在第一次编译它们时会自动缓存所有正则表达式。)如果这样做,我不希望看到性能上有太大差异。

我会说split()是最快的,并且可能对你正在做的事情足够好。 但它不如scanner灵活。 StringTokenizer已弃用,仅可用于向后兼容,因此请勿使用它。

编辑:你总是可以测试两个实现,看看哪个更快。 如果scannersplit()更快,我很好奇。 对于给定大小的VS Scanner ,拆分可能会更快,但我无法确定。

你实际上并不需要这里的正则表达式,因为你正在分裂一个固定的字符串。 Apache StringUtils split会拆分普通字符串。

对于高分割,分割是瓶颈,而不是说文件IO,我发现它比String.split()快10倍。 但是,我没有针对编译的正则表达式进行测试。

Guava还有一个分离器,以更多的OO方式实现,但我发现它比StringUtils显着慢于高容量分割。