Zasadniczo są to konie na kursy.
Scanner
jest przeznaczony do przypadków, w których musisz przeanalizować ciąg, wyciągając dane różnych typów. Jest bardzo elastyczny, ale prawdopodobnie nie zapewnia najprostszego interfejsu API do prostego pobierania tablicy ciągów oddzielonych określonym wyrażeniem.
String.split()
i Pattern.split()
podam prostą składnię do zrobienia tego drugiego, ale to właściwie wszystko, co robią. Jeśli chcesz przeanalizować otrzymane ciągi lub zmienić ogranicznik w połowie, w zależności od konkretnego tokenu, nie pomogą Ci w tym.
StringTokenizer
jest jeszcze bardziej restrykcyjny String.split()
, a także nieco bardziej skomplikowany w użyciu. Zasadniczo jest przeznaczony do wyciągania tokenów oddzielonych ustalonymi podciągami. Z powodu tego ograniczenia jest około dwa razy szybszy niż String.split()
. (Zobacz moje porównanie String.split()
iStringTokenizer
.) Jest to również starsze od API wyrażeń regularnych, którego String.split()
jest częścią.
Z moich czasów zauważysz, że na typowej maszynie String.split()
wciąż można tokenizować tysiące łańcuchów w ciągu kilku milisekund . Ponadto ma tę zaletę StringTokenizer
, że daje wynik w postaci tablicy ciągów, co zwykle jest tym, czego chcesz. Używanie an Enumeration
, jak zapewnia StringTokenizer
, jest przez większość czasu zbyt „skomplikowane składniowo”. Z tego punktu widzenia StringTokenizer
w dzisiejszych czasach jest to trochę marnowanie miejsca i równie dobrze możesz po prostu użyć String.split()
.
StringTokenizer
nadal najlepszy zakład, ponieważString.split()
po prostu zabraknie mi pamięci?Zacznijmy od wyeliminowania
StringTokenizer
. Starzeje się i nie obsługuje nawet wyrażeń regularnych. Jego dokumentacja stwierdza:Więc wyrzućmy to od razu. To pozostawia
split()
iScanner
. Jaka jest między nimi różnica?Po pierwsze,
split()
po prostu zwraca tablicę, co ułatwia korzystanie z pętli foreach:Scanner
jest zbudowany bardziej jak strumień:lub
(Ma dość duże API , więc nie myśl, że zawsze ogranicza się do tak prostych rzeczy).
Ten interfejs w stylu strumieniowym może być przydatny do analizowania prostych plików tekstowych lub danych wejściowych konsoli, gdy nie masz (lub nie możesz uzyskać) wszystkich danych wejściowych przed rozpoczęciem analizowania.
Osobiście pamiętam tylko jeden raz, kiedy korzystałem
Scanner
z projektów szkolnych, kiedy musiałem uzyskać dane wejściowe użytkownika z wiersza poleceń. To sprawia, że tego rodzaju operacja jest łatwa. Ale jeśli mam cośString
, z czym chcę się rozstać, to prawie nie ma sensusplit()
.źródło
Scanner
wykrywałem znaki nowego wiersza w danymString
. Ponieważ znaki nowego wiersza mogą się różnić w zależności od platformy (spójrz naPattern
javadoc!), A ciąg wejściowy NIE gwarantuje zgodnościSystem.lineSeparator()
, uważam, że jestScanner
bardziej odpowiedni, ponieważ już wie, jakich znaków nowego wiersza szukać podczas wywoływanianextLine()
. PonieważString.split
będę musiał podać poprawny wzorzec wyrażenia regularnego, aby wykryć separatory wierszy, których nie znajduję w żadnej standardowej lokalizacji (najlepsze, co mogę zrobić, to skopiować je zeScanner
źródła klasy).StringTokenizer był zawsze obecny. Jest najszybszy ze wszystkich, ale idiom przypominający wyliczenie może nie wyglądać tak elegancko jak inne.
split powstał na JDK 1.4. Wolniejszy niż tokenizer, ale łatwiejszy w użyciu, ponieważ można go wywołać z klasy String.
Skaner pojawił się na JDK 1.5. Jest najbardziej elastycznym i wypełnia istniejącą od dawna lukę w Java API, wspierając odpowiednik słynnej rodziny funkcji scanf Cs.
źródło
Jeśli masz obiekt String, który chcesz tokenizować, preferuj użycie metody split String zamiast StringTokenizer. Jeśli analizujesz dane tekstowe ze źródła spoza programu, na przykład z pliku lub od użytkownika, przydaje się skaner.
źródło
Split jest wolny, ale nie tak wolny jak Scanner. StringTokenizer jest szybszy niż split. Jednak odkryłem, że mogę uzyskać dwukrotnie większą prędkość, handlując pewną elastycznością, aby uzyskać przyspieszenie, co zrobiłem na JFastParser https://github.com/hughperkins/jfastparser
Testowanie na łańcuchu zawierającym milion podwójnych:
źródło
String.split wydaje się być znacznie wolniejszy niż StringTokenizer. Jedyną zaletą podziału jest to, że otrzymujesz tablicę tokenów. Możesz także użyć wyrażeń regularnych w podziale. org.apache.commons.lang.StringUtils ma metodę podziału, która działa znacznie szybciej niż dowolne z dwóch, a mianowicie. StringTokenizer lub String.split. Ale wykorzystanie procesora dla wszystkich trzech jest prawie takie samo. Potrzebujemy więc metody mniej obciążającej procesor, której nadal nie mogę znaleźć.
źródło
Niedawno przeprowadziłem kilka eksperymentów dotyczących złej wydajności metody String.split () w sytuacjach o dużej wrażliwości na wydajność. Może ci się to przydać.
http://eblog.chrononsystems.com/hidden-evils-of-javas-stringsplit-and-stringr
Istota jest taka, że String.split () kompiluje za każdym razem wzorzec wyrażenia regularnego i może w ten sposób spowolnić działanie programu w porównaniu do sytuacji, gdy używasz prekompilowanego obiektu Pattern i używasz go bezpośrednio do operacji na łańcuchu.
źródło
W przypadku domyślnych scenariuszy sugerowałbym również Pattern.split (), ale jeśli potrzebujesz maksymalnej wydajności (szczególnie na Androidzie wszystkie testowane przeze mnie rozwiązania są dość wolne) i wystarczy podzielić je tylko jednym znakiem, teraz używam własnej metody:
Użyj „abc” .toCharArray (), aby pobrać tablicę znaków dla ciągu znaków. Na przykład:
źródło
Jedną ważną różnicą jest to, że zarówno String.split (), jak i Scanner mogą tworzyć puste ciągi, ale StringTokenizer nigdy tego nie robi.
Na przykład:
Wynik:
Dzieje się tak, ponieważ separator dla String.split () i Scanner.useDelimiter () nie jest tylko łańcuchem, ale wyrażeniem regularnym. W powyższym przykładzie możemy zamienić separator „” na „+”, aby zachowywały się jak StringTokenizer.
źródło
String.split () działa bardzo dobrze, ale ma swoje własne granice, na przykład jeśli chcesz podzielić ciąg, jak pokazano poniżej, w oparciu o symbol pojedynczej lub podwójnej kreski (|), nie działa. W takiej sytuacji możesz użyć StringTokenizer.
ABC | IJK
źródło