Scanner vs. StringTokenizer vs. String.Split

时间:2009-03-27 19:29:22

标签: java java.util.scanner tokenize split

我刚刚学习了Java的Scanner类,现在我想知道它是如何与StringTokenizer和String.Split进行比较/竞争的。我知道StringTokenizer和String.Split只适用于字符串,那么为什么我要将Scanner用于字符串呢?扫描仪是否只是一次性购物分裂?

10 个答案:

答案 0 :(得分:233)

他们基本上是马匹的课程。

  • Scanner适用于需要解析字符串,提取不同类型数据的情况。它非常灵活,但可以说是没有为您提供最简单的API来简单地获取由特定表达式分隔的字符串数组。
  • String.split()Pattern.split()为您提供了一个简单的语法来完成后者,但这基本上就是他们所做的一切。如果您想要解析生成的字符串,或者根据特定令牌中途更改分隔符,他们将无法帮助您。
  • StringTokenizerString.split()更具限制性,而且使用起来也有些笨拙。它主要用于拉出由固定子串分隔的令牌。由于这种限制,它的速度大约是String.split()的两倍。 (请参阅我的comparison of String.split() and StringTokenizer。)它也早于正则表达式API,其中String.split()是其中的一部分。

您会从我的时间中注意到,String.split()仍然可以在典型计算机上将数千个字符串标记为几毫秒。此外,它具有优于StringTokenizer的优势,它可以将输出作为字符串数组提供,这通常是您想要的。使用由Enumeration提供的StringTokenizer,在大多数情况下过于“语法上挑剔”。从这个角度来看,StringTokenizer现在有点浪费空间,你也可以使用String.split()

答案 1 :(得分:57)

让我们从消除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();
    ...
}

(它有一个large API,所以不要认为它总是局限于这么简单的事情。)

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

就个人而言,我唯一能记住使用Scanner的时间用于学校项目,当我必须从命令行获取用户输入时。它使这种操作变得容易。但是,如果我想要分割String,那么与split()一起使用几乎是明智的。

答案 2 :(得分:9)

StringTokenizer总是在那里。它是最快的,但类似枚举的习语可能看起来不像其他的那样优雅。

分裂在JDK 1.4上出现。比tokenizer慢但更容易使用,因为它可以从String类调用。

扫描仪开始使用JDK 1.5。它是最灵活的,填补了Java API的长期缺口,以支持相当于着名的Cs scanf函数系列。

答案 3 :(得分:6)

分割很慢,但不像扫描仪那么慢。 StringTokenizer比split更快。然而,我发现通过交换一些灵活性,我可以获得双倍的速度,以获得速度提升,我在JFastParser https://github.com/hughperkins/jfastparser

测试包含一百万个双打的字符串:

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

答案 4 :(得分:5)

如果您想要标记化String对象,请使用String的split方法而不是StringTokenizer。如果您正在从程序外部的源(例如文件或用户)解析文本数据,那么扫描仪就会派上用场。

答案 5 :(得分:4)

String.split似乎比StringTokenizer慢得多。拆分的唯一优势是你得到一个令牌数组。您还可以在拆分中使用任何正则表达式。     org.apache.commons.lang.StringUtils有一个split方法,它比两个中的任何一个都快得多。 StringTokenizer或String.split。     但是这三者的CPU利用率几乎相同。所以我们还需要一种CPU密集度较低的方法,但我仍然无法找到。

答案 6 :(得分:4)

我最近在高性能敏感的情况下做了一些关于String.split()性能不佳的实验。你可能会觉得这很有用。

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

要点是String.split()每次编译一个正则表达式模式,因此与使用预编译的Pattern对象并直接使用它来操作String相比,可以减慢程序的速度。

答案 7 :(得分:1)

对于默认场景我也建议使用Pattern.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;
}

使用&#34; abc&#34; .toCharArray()获取String的char数组。例如:

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

答案 8 :(得分:1)

一个重要的区别是String.split()和Scanner都可以生成空字符串,但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()的分隔符不仅仅是一个字符串,而是一个正则表达式。我们可以替换分隔符&#34; &#34;用&#34; +&#34;在上面的示例中,使它们的行为类似于StringTokenizer。

答案 9 :(得分:-6)

String.split()工作得很好但有自己的边界,就像你想根据单管或双管(|)符号分割如下所示的字符串,它不起作用。在这种情况下,您可以使用StringTokenizer。

ABC | IJK