2009-04-10 9 views
10

Ich verwende derzeit split(), um durch eine Datei zu scannen, in der jede Zeile eine Anzahl von Zeichenfolgen hat, die durch '~' begrenzt sind. Ich habe irgendwo gelesen, dass Scanner einen besseren Job mit einer langen Datei leisten kann, was die Leistung betrifft, also habe ich darüber nachgedacht, es auszuprobieren.Javas Scanner vs String.split() vs StringTokenizer; Was sollte ich verwenden?

Meine Frage ist: Würde ich zwei Instanzen von Scanner erstellen? Das heißt, man liest eine Zeile und eine andere basierend auf der Zeile, um Token für ein Trennzeichen zu erhalten. Wenn ich das tun muss, bezweifle ich, dass ich davon profitieren könnte. Vielleicht vermisse ich hier etwas?

Antwort

3

Ich würde sagen split() ist am schnellsten und wahrscheinlich gut genug für das, was Sie tun. Es ist weniger flexibel als scanner obwohl. StringTokenizer ist veraltet und steht nur aus Gründen der Abwärtskompatibilität zur Verfügung, also verwenden Sie es nicht.

EDIT: Sie könnten immer beide Implementierungen testen, um zu sehen, welche schneller ist. Ich bin selbst neugierig wenn scanner schneller sein könnte als split(). Split kann für eine gegebene Größe schneller sein VS Scanner, aber ich kann mir nicht sicher sein.

+0

Ich stimme zu, dass StringTokenizer möglicherweise veraltet ist, aber ich habe es nicht in der Liste der veralteten Klassen für j2se5 und java6 gefunden. Warum? – gedevan

+0

StringTokenzier ist nicht veraltet ... – Jon

+0

Sie haben Recht, ist es nicht.Aber von der API: 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, stattdessen die Split-Methode von String oder das Paket java.util.regex verwendet. – CookieOfFortune

6

Für die Bearbeitungslinie können Sie Scanner verwenden und um Token von jeder Linie zu erhalten, können Sie Split verwenden.

Scanner scanner = new Scanner(new File(loc)); 
try { 
    while (scanner.hasNextLine()){ 
     String[] tokens = scanner.nextLine().split("~"); 
     // do the processing for tokens here 
    } 
} 
finally { 
    scanner.close(); 
} 
5

Sie können die useDelimiter("~") Methode verwenden Sie durch die Token mit hasNext()/next() in jeder Zeile durchlaufen zu lassen, während sie noch hasNextLine()/nextLine() mit sich durch die Leitungen zu durchlaufen.

EDIT: Wenn Sie vorhaben, einen Leistungsvergleich zu tun, sollten Sie die Regex Pre-kompilieren, wenn Sie die Split tun() Test:

Pattern splitRegex = Pattern.compile("~"); 
while ((line = bufferedReader.readLine()) != null) 
{ 
    String[] tokens = splitRegex.split(line); 
    // etc. 
} 

Wenn Sie String#split(String regex) verwenden, wird die Regex neu kompiliert werden jedes Mal. (Der Scanner speichert automatisch alle Regexes, wenn sie das erste Mal kompiliert werden.) Wenn Sie das tun, würde ich nicht erwarten, dass die Leistung sehr unterschiedlich ist.

2

Sie brauchen hier keine Regex, da Sie sich auf eine feste Zeichenfolge aufteilen. Apache StringUtilssplit teilt sich auf einfache Zeichenfolgen.

Für Splits mit hohem Volumen, bei denen die Aufspaltung der Engpass ist, anstatt Datei-IO, habe ich herausgefunden, dass dies bis zu 10 Mal schneller ist als String.split(). Ich habe es jedoch nicht gegen eine kompilierte Regex getestet.

Guava hat auch einen Splitter, der auf eine OO-Weise implementiert ist, aber ich fand, dass es wesentlich langsamer war als StringUtils für hohe Volumenaufteilungen.

8

Haben einige Metriken um diese in einem einzigen Thread-Modell und hier sind die Ergebnisse, die ich bekommen habe.

 
~~~~~~~~~~~~~~~~~~Time Metrics~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
~ Tokenizer | String.Split() | while+SubString | Scanner | ScannerWithCompiledPattern ~ 
~ 4.0 ms |  5.1 ms  |  1.2 ms  |  0.5 ms |    0.1 ms   ~ 
~ 4.4 ms |  4.8 ms  |  1.1 ms  |  0.1 ms |    0.1 ms   ~ 
~ 3.5 ms |  4.7 ms  |  1.2 ms  |  0.1 ms |    0.1 ms   ~ 
~ 3.5 ms |  4.7 ms  |  1.1 ms  |  0.1 ms |    0.1 ms   ~ 
~ 3.5 ms |  4.7 ms  |  1.1 ms  |  0.1 ms |    0.1 ms   ~ 
____________________________________________________________________________________________________________ 

Das Ergebnis ist, dass Scanner die beste Leistung gibt, jetzt muss das Gleiche im Multithread-Modus ausgewertet werden! Einer meiner Senior sagt, dass der Tokenizer einen CPU-Spike und String.split keinen CPU-Spike liefert.

Verwandte Themen