Scanner vs. StringTokenizer vs. String.Split
我刚刚了解了 Java 的 Scanner 类,现在我想知道它如何与 StringTokenizer 和 String.Split 进行比较/竞争。 我知道 StringTokenizer 和 String.Split 只适用于字符串,那么为什么我要对字符串使用 Scanner 呢? Scanner 只是为了提供一站式分割服务吗?
I just learned about Java's Scanner class and now I'm wondering how it compares/competes with the StringTokenizer and String.Split. I know that the StringTokenizer and String.Split only work on Strings, so why would I want to use the Scanner for a String? Is Scanner just intended to be one-stop-shopping for spliting?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
他们本质上是课程的马。
Scanner
专为需要解析字符串、提取不同类型数据的情况而设计。 它非常灵活,但可以说并没有为您提供最简单的 API 来简单地获取由特定表达式分隔的字符串数组。String.split()
和Pattern.split()
为您提供了执行后者的简单语法,但这基本上就是它们所做的全部。 如果您想解析结果字符串,或者根据特定标记更改分隔符,它们将无法帮助您。StringTokenizer
比String.split()
更具限制性,而且使用起来也有点繁琐。 它本质上是为了提取由固定子字符串分隔的标记而设计的。 由于此限制,它的速度大约是String.split()
的两倍。 (请参阅我的String.split()
和的比较StringTokenizer
。)它也早于正则表达式 API,String.split()
是正则表达式 API 的一部分。从我的计时中您会注意到,
String.split()
仍然可以在典型机器上在几毫秒内标记数千个字符串。 此外,它比StringTokenizer
还具有优势,它以字符串数组的形式提供输出,这通常是您想要的。 大多数时候,使用由StringTokenizer
提供的Enumeration
过于“语法繁琐”。 从这个角度来看,现在的StringTokenizer
有点浪费空间,你还不如直接使用String.split()
。They're essentially horses for courses.
Scanner
is designed for cases where you need to parse a string, pulling out data of different types. It's very flexible, but arguably doesn't give you the simplest API for simply getting an array of strings delimited by a particular expression.String.split()
andPattern.split()
give you an easy syntax for doing the latter, but that's essentially all that they do. If you want to parse the resulting strings, or change the delimiter halfway through depending on a particular token, they won't help you with that.StringTokenizer
is even more restrictive thanString.split()
, and also a bit fiddlier to use. It is essentially designed for pulling out tokens delimited by fixed substrings. Because of this restriction, it's about twice as fast asString.split()
. (See my comparison ofString.split()
andStringTokenizer
.) It also predates the regular expressions API, of whichString.split()
is a part.You'll note from my timings that
String.split()
can still tokenize thousands of strings in a few milliseconds on a typical machine. In addition, it has the advantage overStringTokenizer
that it gives you the output as a string array, which is usually what you want. Using anEnumeration
, as provided byStringTokenizer
, is too "syntactically fussy" most of the time. From this point of view,StringTokenizer
is a bit of a waste of space nowadays, and you may as well just useString.split()
.让我们首先消除
StringTokenizer
< /a>. 它已经过时了,甚至不支持正则表达式。 其文档指出:所以我们赶紧把它扔掉吧。 剩下
split()
和扫描仪
。 他们之间有什么区别?一方面,
split()
只是返回一个数组,这使得使用 foreach 循环变得很容易:Scanner
的构建更像是一个流:或者
(它有一个相当大型 API,所以不要认为它总是局限于如此简单的事情。)
当您在开始解析之前没有(或无法获取)所有输入时,这种流式界面对于解析简单的文本文件或控制台输入非常有用。
就我个人而言,我记得唯一一次使用 Scanner 是在学校项目中,当时我必须从命令行获取用户输入。 它使此类操作变得容易。 但是,如果我有一个想要拆分的
String
,那么使用split()
几乎是理所当然的事情。Let's start by eliminating
StringTokenizer
. It is getting old and doesn't even support regular expressions. Its documentation states:So let's throw it out right away. That leaves
split()
andScanner
. What's the difference between them?For one thing,
split()
simply returns an array, which makes it easy to use a foreach loop:Scanner
is built more like a stream:or
(It has a rather large API, so don't think that it's always restricted to such simple things.)
This stream-style interface can be useful for parsing simple text files or console input, when you don't have (or can't get) all the input before starting to parse.
Personally, the only time I can remember using
Scanner
is for school projects, when I had to get user input from the command line. It makes that sort of operation easy. But if I have aString
that I want to split up, it's almost a no-brainer to go withsplit()
.StringTokenizer 一直都在那里。 它是最快的,但类似枚举的习惯用法可能看起来不如其他习惯用法那么优雅。
split 在 JDK 1.4 上出现。 比 tokenizer 慢,但更易于使用,因为它可以从 String 类调用。
Scanner 出现在 JDK 1.5 上。 它是最灵活的,填补了 Java API 上长期存在的空白,支持著名的 Cs scanf 函数系列的等效项。
StringTokenizer was always there. It is the fastest of all, but the enumeration-like idiom might not look as elegant as the others.
split came to existence on JDK 1.4. Slower than tokenizer but easier to use, since it is callable from the String class.
Scanner came to be on JDK 1.5. It is the most flexible and fills a long standing gap on the Java API to support an equivalent of the famous Cs scanf function family.
Split 很慢,但没有 Scanner 慢。 StringTokenizer 比 split 更快。 然而,我发现我可以通过牺牲一些灵活性来获得双倍的速度,以获得速度提升,这是我在 JFastParser https://github.com/hughperkins/jfastparser
对包含一百万个双精度数的字符串进行测试:
Split is slow, but not as slow as Scanner. StringTokenizer is faster than split. However, I found that I could obtain double the speed, by trading some flexibility, to get a speed-boost, which I did at JFastParser https://github.com/hughperkins/jfastparser
Testing on a string containing one million doubles:
如果您有一个想要标记的 String 对象,请优先使用 String 的 split StringTokenizer 方法。 如果您要解析来自程序外部的源(例如文件或用户)的文本数据,那么扫描程序就可以派上用场。
If you have a String object you want to tokenize, favor using String's split method over a StringTokenizer. If you're parsing text data from a source outside your program, like from a file, or from the user, that's where a Scanner comes in handy.
String.split似乎比StringTokenizer慢得多。 拆分的唯一优点是您可以获得令牌数组。 您还可以在 split 中使用任何正则表达式。
org.apache.commons.lang.StringUtils 有一个 split 方法,它的工作速度比任何两个可视化都要快得多。 StringTokenizer 或 String.split。
但三者的 CPU 利用率几乎相同。 所以我们还需要一种 CPU 密集程度较低的方法,但我仍然找不到。
String.split seems to be much slower than StringTokenizer. The only advantage with split is that you get an array of the tokens. Also you can use any regular expressions in split.
org.apache.commons.lang.StringUtils has a split method which works much more faster than any of two viz. StringTokenizer or String.split.
But the CPU utilization for all the three is nearly the same. So we also need a method which is less CPU intensive, which I am still not able to find.
我最近做了一些关于 String.split() 在性能高度敏感的情况下性能不佳的实验。 您可能会发现这很有用。
Java 的 String.split() 和 Replace() 的隐藏弊端
要点是 String.split() 每次都会编译正则表达式模式,因此与使用预编译的 Pattern 对象相比,会减慢您的程序速度并直接使用它来操作字符串。
I recently did some experiments about the bad performance of String.split() in highly performance sensitive situations. You may find this useful.
Hidden evils of Java's String.split() and replace()
The gist is that String.split() compiles a Regular Expression pattern each time and can thus slow down your program, compared to if you use a precompiled Pattern object and use it directly to operate on a String.
对于默认场景,我也建议 Pattern.split() ,但如果您需要最大性能(特别是在 Android 上,我测试的所有解决方案都非常慢)并且您只需要按单个字符拆分,我现在使用我自己的方法:
使用 "abc".toCharArray() 获取字符串的字符数组。 例如:
For the default scenarios I would suggest Pattern.split() as well but if you need maximum performance (especially on Android all solutions I tested are quite slow) and you only need to split by a single char, I now use my own method:
Use "abc".toCharArray() to get the char array for a String. For example:
一个重要的区别是 String.split() 和 Scanner 都可以生成空字符串,但 StringTokenizer 永远不会这样做。
例如:
输出:
这是因为 String.split() 和 Scanner.useDelimiter() 的分隔符不仅仅是一个字符串,而是一个正则表达式。 我们可以将上面示例中的分隔符“”替换为“+”,使它们的行为类似于 StringTokenizer。
One important difference is that both String.split() and Scanner can produce empty strings but StringTokenizer never does it.
For example:
Output:
This is because the delimiter for String.split() and Scanner.useDelimiter() is not just a string, but a regular expression. We can replace the delimiter " " with " +" in the example above to make them behave like StringTokenizer.
String.split() 工作得很好,但有它自己的边界,就像如果你想根据单管或双管 (|) 符号分割字符串,如下所示,它不起作用。 在这种情况下,您可以使用 StringTokenizer。
ABC|IJK
String.split() works very good but has its own boundaries, like if you wanted to split a string as shown below based on single or double pipe (|) symbol, it doesn't work. In this situation you can use StringTokenizer.
ABC|IJK