Frage

Ich habe gerade etwas über die Scannerklasse von Java gelernt und frage mich jetzt, wie es mit dem StringTokenizer und String.split verglichen/konkurriert. Ich weiß, dass der StringTokenizer und String.split nur auf Strings funktionieren. Warum sollte ich den Scanner für eine Zeichenfolge verwenden? Soll Scanner nur ein Stop-Shopping zum Spliting sein?

War es hilfreich?

Lösung

Sie sind im Wesentlichen Pferde für Kurse.

  • Scanner ist für Fälle ausgelegt, in denen Sie eine Zeichenfolge analysieren müssen und Daten unterschiedlicher Typen herausziehen müssen. Es ist sehr flexibel, aber es gibt Ihnen wohl nicht die einfachste API, wenn Sie einfach eine Reihe von Strings durch einen bestimmten Ausdruck abgrenzen.
  • String.split() und Pattern.split() Geben Sie Ihnen eine einfache Syntax für das letztere, aber das ist im Wesentlichen alles, was sie tun. Wenn Sie die resultierenden Saiten analysieren oder den Trennzeichen auf halbem Weg ändern möchten, hilft sie Ihnen dabei nicht.
  • StringTokenizer ist noch restriktiver als String.split(), und auch etwas fummeliger zu verwenden. Es ist im Wesentlichen für das Ausziehen von Token entwickelt, die durch feste Substrings begrenzt sind. Wegen dieser Einschränkung ist es ungefähr doppelt so schnell wie String.split(). (Sieh mein Vergleich von String.split() und StringTokenizer.) Es geht auch vor der regulären Ausdrücke API, deren String.split() ist ein Teil.

Sie werden aus meinen Timings feststellen, dass String.split() kann noch tokenisieren Tausende von Saiten in wenigen Millisekunden auf einer typischen Maschine. Außerdem hat es den Vorteil StringTokenizer Dass es Ihnen die Ausgabe als Zeichenfolgenarray gibt, das ist normalerweise das, was Sie wollen. Mit an ein Enumeration, wie StringTokenizer, ist die meiste Zeit zu "syntaktisch pingelig". Von diesem Standpunkt aus betrachtet, StringTokenizer ist heutzutage ein bisschen Platzverschwendung, und Sie können auch einfach nur nutzen String.split().

Andere Tipps

Beginnen wir zunächst eliminieren StringTokenizer. Es wird alt und unterstützt nicht einmal reguläre Ausdrücke. In seiner Dokumentation heißt es:

StringTokenizer ist eine Legacy -Klasse, die aus Kompatibilitätsgründen beibehalten wird, obwohl ihre Verwendung in neuem Code entmutigt wird. Es wird empfohlen, dass jeder, der diese Funktionalität sucht split Methode von String oder der java.util.regex Paket stattdessen.

Also lass es uns sofort rauswerfen. Das geht split() und Scanner. Was ist der Unterschied zwischen ihnen?

Für eine Sache, split() Gibt einfach ein Array zurück, wodurch es einfach ist, eine Foreach -Schleife zu verwenden:

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

Scanner ist eher wie ein Stream gebaut:

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

oder

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

(Es hat eher eine große API, Denken Sie also nicht, dass es immer auf solche einfachen Dinge beschränkt ist.)

Diese Schnittstelle im Stream-Stil kann nützlich sein, um einfache Textdateien oder Konsoleneingaben zu analysieren, wenn Sie nicht alle Eingaben haben (oder können), bevor Sie anfangen, vor dem Analyse zu beginnen.

Persönlich kann ich mich nur erinnern, wenn ich mich erinnern kann Scanner ist für Schulprojekte, wenn ich Benutzereingaben aus der Befehlszeile erhalten musste. Es erleichtert diese Art von Operation. Aber wenn ich eine habe String Dass ich mich trennen möchte, ist fast ein Kinderspiel, mit dem ich gehen kann split().

StringTokenizer war immer da. Es ist das schnellste von allen, aber die aufzählerische Idiom sieht möglicherweise nicht so elegant aus wie die anderen.

Split bestand auf JDK 1.4. Langsamer als Tokenizer, aber einfacher zu bedienen, da es aus der String -Klasse abgerufen werden kann.

Der Scanner war auf JDK 1.5. Es ist am flexibelsten und füllt eine langjährige Lücke auf der Java -API, um ein Äquivalent der berühmten CS -Scanf -Funktionsfamilie zu unterstützen.

Split ist langsam, aber nicht so langsam wie Scanner. StringTokenizer ist schneller als geteilt. Ich stellte jedoch fest, dass ich doppelt so viel Geschwindigkeit erhalten konnte, indem ich etwas Flexibilität tauscht, um einen Geschwindigkeitsanleihen zu erhalten, den ich bei JastParser gemacht habe https://github.com/hughperkins/jfastParser

Testen an einer Zeichenfolge mit einer Million Doppel:

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

Wenn Sie ein String -Objekt haben, das Sie tokenisieren möchten, bevorzugen Sie mit String's String's Teilt Methode über einen StringTokenizer. Wenn Sie Textdaten von einer Quelle außerhalb Ihres Programms wie aus einer Datei oder vom Benutzer analysieren, ist hier ein Scanner praktisch.

String.Split scheint viel langsamer zu sein als StringTokenizer. Der einzige Vorteil bei Split ist, dass Sie eine Reihe der Token erhalten. Sie können auch alle regulären Ausdrücke in Split verwenden. org.apache.commons.lang.Stringutils hat eine Split -Methode, die viel schneller funktioniert als zweier von zwei. StringTokenizer oder String.split. Die CPU -Nutzung für alle drei ist jedoch fast gleich. Wir brauchen also auch eine Methode, die weniger CPU -intensiv ist, die ich immer noch nicht finden kann.

Ich habe kürzlich einige Experimente über die schlechte Leistung von String.split () in hoch leistungsempfindlichen Situationen durchgeführt. Möglicherweise finden Sie dies nützlich.

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

Der GIST ist, dass String.split () jedes Mal ein reguläres Ausdrucksmuster kompiliert und somit Ihr Programm verlangsamen kann, verglichen mit einem vorkompilierten Musterobjekt und direkt, um es mit einer Zeichenfolge zu bedienen.

Für die Standardszenarien würde ich Muster.Split () auch vorschlagen, aber wenn Sie maximale Leistung benötigen (insbesondere bei Android, sind alle von mir getesteten Lösungen ziemlich langsam) und Sie müssen nur durch ein einzelnes Zeichen aufgeteilt werden, verwende ich jetzt meine eigene Methode:

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;
}

Verwenden Sie "ABC" .TOCHARARAY (), um das Zeichenarray für eine Zeichenfolge zu erhalten. Zum Beispiel:

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

One important difference is that both String.split() and Scanner can produce empty strings but StringTokenizer never does it.

For example:

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());

Output:

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

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() 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

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top