Java 扫描程序与StringTokenizer与String.Split

Java 扫描程序与StringTokenizer与String.Split,java,java.util.scanner,tokenize,split,Java,Java.util.scanner,Tokenize,Split,我刚刚了解了Java的Scanner类,现在我想知道它如何与StringTokenizer和String.Split进行比较/竞争。我知道StringTokenizer和String.Split只对字符串起作用,那么我为什么要对字符串使用扫描仪呢?扫描器仅仅是用来进行拆分的一站式购物吗?它们本质上是课程的马匹 Scanner专为需要解析字符串、提取不同类型数据的情况而设计。它非常灵活,但可以说它没有提供最简单的API来简单地获取由特定表达式分隔的字符串数组 String.split()和Pat

我刚刚了解了Java的Scanner类,现在我想知道它如何与StringTokenizer和String.Split进行比较/竞争。我知道StringTokenizer和String.Split只对字符串起作用,那么我为什么要对字符串使用扫描仪呢?扫描器仅仅是用来进行拆分的一站式购物吗?

它们本质上是课程的马匹

  • Scanner
    专为需要解析字符串、提取不同类型数据的情况而设计。它非常灵活,但可以说它没有提供最简单的API来简单地获取由特定表达式分隔的字符串数组
  • String.split()
    Pattern.split()
    为您提供了执行后一种操作的简单语法,但它们基本上就是这么做的。如果您想要解析结果字符串,或者根据特定的标记中途更改分隔符,那么它们将不会帮助您
  • StringTokenizer
    String.split()
    更具限制性,使用起来也有点烦躁。它本质上是为提取由固定子字符串分隔的令牌而设计的。由于这个限制,它的速度大约是String.split()的两倍。(请参见my。)它也早于正则表达式API,其中
    String.split()
    是其中的一部分

您将从我的计时中注意到,在典型的机器上,
String.split()
仍然可以在几毫秒内标记数千个字符串。此外,与
StringTokenizer
相比,它的优势在于它将输出作为字符串数组,这通常是您想要的。使用
StringTokenizer
提供的
枚举
,在大多数情况下过于“语法繁琐”。从这个角度来看,
StringTokenizer
现在有点浪费空间,您最好只使用
String.split()

如果您有一个字符串对象要标记,那么最好使用String的方法而不是StringTokenizer。如果您正在解析来自程序外部源的文本数据,例如来自文件或用户的文本数据,那么扫描仪就会派上用场。

StringTokenizer总是在那里。它是最快的,但是枚举式的习语看起来可能没有其他习语那么优雅

split是在JDK1.4上出现的。比标记器慢,但更易于使用,因为它可以从String类调用


扫描仪出现在JDK1.5上。它是最灵活的,填补了Java API上的一个长期空白,可以支持与著名的Cs scanf函数系列相当的功能。

让我们从消除这些功能开始。它越来越旧,甚至不支持正则表达式。其文件规定:

StringTokenizer
是一个遗留类,出于兼容性原因保留它,尽管在新代码中不鼓励使用它。建议寻求此功能的任何人改用
String
split
方法或
java.util.regex

所以让我们马上把它扔掉。那就剩下了。他们之间有什么区别

首先,
split()

for (String token : input.split("\\s+") { ... }
扫描仪
更像一条流:

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

(它有一个相当大的范围,所以不要认为它总是局限于这么简单的事情。)

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


就我个人而言,我能记得的唯一一次使用
Scanner
是在学校项目中,当时我必须从命令行获取用户输入。这样做很容易。但是,如果我有一个
字符串
,我想拆分它,那么使用
split()

字符串几乎不需要动脑筋。split似乎比StringTokenizer慢得多。split的唯一优点是您可以获得一个令牌数组。也可以在split中使用任何正则表达式。 org.apache.commons.lang.StringUtils有一个拆分方法,它比两个viz中的任何一个都快得多。StringTokenizer或String.split。
但这三种处理器的CPU利用率几乎相同。因此,我们还需要一种CPU密集度较低的方法,我仍然无法找到这种方法

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


要点是String.split()每次编译一个正则表达式模式,因此与使用预编译的模式对象直接对字符串进行操作相比,它可以降低程序的速度。

split速度较慢,但不如Scanner慢。StringTokenizer比split更快。然而,我发现,通过交换一些灵活性,我可以获得双倍的速度,以获得速度提升,这是我在JFastParser做的

在包含一百万个双精度的字符串上进行测试:

Scanner: 10642 ms
Split: 715 ms
StringTokenizer: 544ms
JFastParser: 290ms
String.split()工作得很好,但有自己的边界,比如如果您想根据单管或双管(|)符号拆分如下所示的字符串,则它不起作用。在这种情况下,可以使用StringTokenizer


ABC | IJK

对于默认场景,我也建议使用Pattern.split(),但如果您需要最大的性能(特别是在Android上,我测试的所有解决方案都非常慢),并且您只需要按单个字符分割,我现在使用我自己的方法:

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;
}
public static ArrayList splitBySingleChar(final char[]s,
最终字符拆分(字符){
最终ArrayList结果=新建ArrayList();
最终整数长度=s.length;
整数偏移=0;
整数计数=0;
for(int i=0;i0){
添加(新字符串(s、偏移量、计数));
}
抵消
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;
}
String s = "     a bb   ccc  dddd eeeee  ffffff    ggggggg ";
ArrayList<String> result = splitBySingleChar(s.toCharArray(), ' ');
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