Java 的 Scanner vs String.split() vs StringTokenizer;我应该使用哪个?
Posted
技术标签:
【中文标题】Java 的 Scanner vs String.split() vs StringTokenizer;我应该使用哪个?【英文标题】:Java's Scanner vs String.split() vs StringTokenizer; which should I use? 【发布时间】:2010-10-18 17:02:23 【问题描述】:我目前正在使用split()
扫描一个文件,其中每一行都有由'~'
分隔的字符串数。我在某处读到 Scanner
在性能方面可以更好地处理长文件,所以我想检查一下。
我的问题是:我是否必须创建两个 Scanner
实例?也就是说,一个读取一行,另一个基于该行获取分隔符的标记?如果我必须这样做,我怀疑我是否会从使用它中获得任何好处。也许我在这里遗漏了什么?
【问题讨论】:
【参考方案1】:在单线程模型中围绕这些指标做了一些指标,这是我得到的结果。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~ 分词器 | String.Split() |而+子字符串 |扫描仪 | ScannerWithCompiledPattern ~ ~ 4.0 毫秒 | 5.1 毫秒 | 1.2 毫秒 | 0.5 毫秒 | 0.1 毫秒 ~ ~ 4.4 毫秒 | 4.8 毫秒 | 1.1 毫秒 | 0.1 毫秒 | 0.1 毫秒 ~ ~ 3.5 毫秒 | 4.7 毫秒 | 1.2 毫秒 | 0.1 毫秒 | 0.1 毫秒 ~ ~ 3.5 毫秒 | 4.7 毫秒 | 1.1 毫秒 | 0.1 毫秒 | 0.1 毫秒 ~ ~ 3.5 毫秒 | 4.7 毫秒 | 1.1 毫秒 | 0.1 毫秒 | 0.1 毫秒 ~ ____________________________________________________________________________________________________________结果是 Scanner 提供了最好的性能,现在需要在多线程模式下进行评估!我的一位前辈说 Tokenizer 会导致 CPU 达到峰值,而 String.split 不会。
【讨论】:
【参考方案2】:对于处理行,您可以使用扫描仪,对于从每行获取令牌,您可以使用拆分。
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();
【讨论】:
【参考方案3】:您可以使用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)
,则每次都会重新编译正则表达式。 (扫描器在第一次编译它们时会自动缓存所有正则表达式。)如果你这样做,我不希望看到性能上有太大差异。
【讨论】:
【参考方案4】:我会说split()
是最快的,并且对于您正在做的事情可能已经足够了。虽然它不如scanner
灵活。 StringTokenizer
已弃用,仅用于向后兼容,因此请勿使用。
编辑:您总是可以测试这两种实现,看看哪一种更快。我很好奇scanner
是否会比split()
更快。对于给定大小的 VS Scanner
,拆分可能会更快,但我不能确定。
【讨论】:
我同意 StringTokenizer 可能已被弃用,但我没有在 j2se5 和 java6 的弃用类列表中找到它。为什么? 你是对的,它不是。但从 API 来看:StringTokenizer 是一个遗留类,出于兼容性原因而保留,尽管不鼓励在新代码中使用它。建议任何寻求此功能的人使用 String 的 split 方法或 java.util.regex 包。【参考方案5】:您实际上并不需要正则表达式,因为您在固定字符串上进行拆分。 Apache StringUtils
split 对纯字符串进行拆分。
对于大容量拆分,拆分是瓶颈,而不是文件 IO,我发现这比 String.split()
快 10 倍。但是,我没有针对已编译的正则表达式对其进行测试。
Guava 也有一个拆分器,以更面向对象的方式实现,但我发现它比 StringUtils 大容量拆分慢得多。
【讨论】:
以上是关于Java 的 Scanner vs String.split() vs StringTokenizer;我应该使用哪个?的主要内容,如果未能解决你的问题,请参考以下文章
java - Scanner vs InputStreamReader - Stack Overflow
BufferedReader vs Console vs Scanner