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
已弃用,仅可用于向后兼容,因此请勿使用它。
编辑:你总是可以测试两个实现,看看哪个更快。 如果scanner
比split()
更快,我很好奇。 对于给定大小的VS Scanner
,拆分可能会更快,但我无法确定。
你实际上并不需要这里的正则表达式,因为你正在分裂一个固定的字符串。 Apache StringUtils
split会拆分普通字符串。
对于高分割,分割是瓶颈,而不是说文件IO,我发现它比String.split()
快10倍。 但是,我没有针对编译的正则表达式进行测试。
Guava还有一个分离器,以更多的OO方式实现,但我发现它比StringUtils显着慢于高容量分割。