我刚刚了解了Java的扫描仪课程,现在我想知道它如何与StringTokenizer和String.split进行比较/竞争。我知道弦乐器和字符串。Split仅适用于字符串,那么为什么要将扫描仪用于字符串呢?扫描仪只是打算是一站式购物吗?

有帮助吗?

解决方案

他们本质上是课程的马。

  • Scanner 设计用于您需要解析字符串并拔出不同类型的数据的情况。它非常灵活,但是可以说,它并不能为您提供最简单的API,简单地获得特定表达式界定的一系列字符串。
  • String.split()Pattern.split() 给您简单的语法来完成后者,但这实际上是他们所做的一切。如果您想解析生成的字符串,或者根据特定的令牌将定界线更改为中间,它们将不会为您提供帮助。
  • StringTokenizer 比限制比 String.split(), ,也有点麻烦。它基本设计用于拉出固定子字符串划界的令牌。由于这种限制,它的速度大约是 String.split(). 。 (见我 相对比 String.split()StringTokenizer。)它也早于正则表达式API String.split() 是一部分。

你会从我的时间里注意到 String.split() 仍然可以令牌 数千弦数毫秒 在典型的机器上。此外,它具有优势 StringTokenizer 它可以将输出作为字符串数组,通常是您想要的。使用 Enumeration, ,按照 StringTokenizer, ,大部分时间都太“句法上挑剔”。从这个角度来看, StringTokenizer 如今有点浪费空间,您也可以使用 String.split().

其他提示

让我们从消除开始 StringTokenizer. 。它已经变老了,甚至不支持正则表达式。其文档指出:

StringTokenizer 是一个遗留类,由于兼容原因而被保留,尽管其使用在新代码中不建议使用。建议任何寻求此功能的人使用 split 的方法 String 或者 java.util.regex 软件包。

因此,让我们立即将其扔出去。那离开 split()Scanner. 。它们有什么区别?

一件事 split() 只需返回一个阵列,这使使用foreach循环变得易于使用:

for (String token : input.split("\\s+") { ... }

Scanner 建造更像流:

while (myScanner.hasNext()) {
    String token = myScanner.next();
    ...
}

或者

while (myScanner.hasNextDouble()) {
    double token = myScanner.nextDouble();
    ...
}

(它有一个 大型API, ,所以不要认为它总是限于如此简单的事情。)

当您没有(或无法获取)在开始解析之前,此流式接口对于解析简单的文本文件或控制台输入可能很有用。

就个人而言,我唯一能记得使用的时间 Scanner 是用于学校项目的,当我必须从命令行获得用户输入时。它使这种操作变得容易。但是如果我有一个 String 我想分裂,这几乎是一个不费吹灰之力的 split().

StringTokenizer总是在那里。它是最快的,但是枚举般的成语看起来不像其他统一性那么优雅。

JDK 1.4出现了分裂。比令牌较慢,但更易于使用,因为它可以从字符串类中调用。

扫描仪开始使用JDK 1.5。它是最灵活的,在Java API上填补了长时间的空白,以支持相当于著名的CS SCANF功能系列。

分裂很慢,但不像扫描仪那样慢。 StringTokenizer比拆分更快。但是,我发现我可以通过交易一些灵活性来获得两倍的速度,以获得速度提升,我在Jfastparser上做了这一点 https://github.com/hughperkins/jfastparser

在包含100万双的字符串上进行测试:

Scanner: 10642 ms
Split: 715 ms
StringTokenizer: 544ms
JFastParser: 290ms

如果您有一个要令牌的字符串对象,请使用字符串的优惠 分裂 通过StringTokenizer的方法。如果您是从程序外部的源中解析文本数据,例如文件或用户,那就是扫描仪派上用场的地方。

String.split似乎比StringTokenizer慢得多。 Split的唯一优点是您获得了代币的数组。另外,您可以在Split中使用任何正则表达式。 org.apache.commons.lang.stringutils具有一种拆分方法,其工作速度比两个viz中的任何一个要快得多。 StringTokenizer或String.split。但是所有三个的CPU利用率几乎相同。因此,我们还需要一种较少密集型的方法,我仍然找不到。

最近,我做了一些实验,以了解string.split()在高度敏感的情况下的不良性能。您可能会发现这有用。

http://eblog.chrononsystems.com/hidden-evils-of-javas-stringsplit--and-stringr

要点是string.split()每次都会编译正则表达式模式,因此与使用预编译的模式对象相比,可以放慢程序的速度,并直接使用它来在字符串上操作。

对于默认场景,我也建议使用模式。Split(),但是如果您需要最大的性能(尤其是在Android上,我测试的所有解决方案都非常慢),您只需要用单个char拆分,我现在使用我自己的方法:

public static ArrayList<String> splitBySingleChar(final char[] s,
        final char splitChar) {
    final ArrayList<String> result = new ArrayList<String>();
    final int length = s.length;
    int offset = 0;
    int count = 0;
    for (int i = 0; i < length; i++) {
        if (s[i] == splitChar) {
            if (count > 0) {
                result.add(new String(s, offset, count));
            }
            offset = i + 1;
            count = 0;
        } else {
            count++;
        }
    }
    if (count > 0) {
        result.add(new String(s, offset, count));
    }
    return result;
}

使用“ abc” .tochararray()获取字符串的字符阵列。例如:

String s = "     a bb   ccc  dddd eeeee  ffffff    ggggggg ";
ArrayList<String> result = splitBySingleChar(s.toCharArray(), ' ');

一个重要的区别是String.split()和扫描仪都可以产生空字符串,但是StringTokenizer从未这样做。

例如:

String str = "ab cd  ef";

StringTokenizer st = new StringTokenizer(str, " ");
for (int i = 0; st.hasMoreTokens(); i++) System.out.println("#" + i + ": " + st.nextToken());

String[] split = str.split(" ");
for (int i = 0; i < split.length; i++) System.out.println("#" + i + ": " + split[i]);

Scanner sc = new Scanner(str).useDelimiter(" ");
for (int i = 0; sc.hasNext(); i++) System.out.println("#" + i + ": " + sc.next());

输出:

//StringTokenizer
#0: ab
#1: cd
#2: ef
//String.split()
#0: ab
#1: cd
#2: 
#3: ef
//Scanner
#0: ab
#1: cd
#2: 
#3: ef

这是因为String.split()和scanner.usedelimiter()的定界符不仅是字符串,而且是正则表达式。在上面的示例中,我们可以用“ +”替换定界符“”,以使其像StringTokenizer一样行为。

string.split()的工作非常好,但是具有自己的边界,例如,如果您想根据单管或双管(|)符号分开字符串,则它不起作用。在这种情况下,您可以使用StringTokenizer。

ABC | ijk

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top