Сканер против StringTokenizer против String.Расщеплять



Я только что узнал о классе сканера Java, и теперь мне интересно, как он сравнивает/конкурирует с StringTokenizer и String.Расщеплять. Я знаю, что StringTokenizer и String.Сплит работает только на строках, так почему я хочу использовать сканер для строки? Сканер просто предназначен для того, чтобы быть одной остановкой для расщепления?

646   10  

10 ответов:

они по существу лошади для курсов.

  • Scanner предназначен для случаев, когда вам нужно разобрать строку, вытаскивая данные разных типов. Он очень гибкий, но, возможно, не дает вам самый простой API для простого получения массива строк, разделенных определенным выражением.
  • String.split() и Pattern.split() даст вам простой синтаксис для выполнения последнего, но это по сути все, что они делают. Если вы хотите проанализировать полученные строки, или изменить разделитель на полпути в зависимости от конкретного маркера, они не помогут вам в этом.
  • StringTokenizer является еще более ограничительным, чем String.split(), а также немного скрипач, чтобы использовать. Он по существу предназначен для извлечения токенов, разделенных фиксированными подстроками. Из-за этого ограничения, это примерно в два раза быстрее String.split(). (Смотрите мой сравнение String.split() и StringTokenizer.) Он также предшествует API регулярных выражений, из которых String.split() это часть.

вы заметите из моих таймингов, что String.split() еще можно разметить тысячи строк за несколько миллисекунд на обычной машине. Кроме того, он имеет преимущество перед StringTokenizer что он дает вам выход в виде строкового массива, который обычно является тем, что вы хотите. ИспользуяEnumeration, предусмотренных StringTokenizer, слишком "синтаксически суетливый" большую часть времени. С этой точки зрения, StringTokenizer это немного пустая трата пространства в настоящее время, и вы можете также просто используйте String.split().

давайте начнем с устранения 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();
    ...
}

большой API, так что не думайте, что это всегда ограничивается такими простыми вещами.)

этот поток-стиль интерфейс может быть полезен для разбора простых текстовых файлов или консольного ввода, когда вы не имеете (или не можете получить) все входные данные перед началом разбора.

лично, единственный раз, когда я могу вспомнить использование Scanner для школьных проектов, когда я должен был получить пользовательский ввод из командной строки. Это делает такую операцию легкой. Но если у меня есть String что я хочу разделиться, это почти без проблем, чтобы пойти с split().

StringTokenizer всегда был там. Это самый быстрый из всех, но перечисление, как идиома может выглядеть не так элегантно, как другие.

Сплит появился на JDK 1.4. Медленнее, чем токенизатор, но проще в использовании, так как он вызывается из класса String.

сканер появился на JDK 1.5. Он является наиболее гибким и заполняет давний пробел в Java API для поддержки эквивалента известного семейства функций Cs scanf.

раскол медленно, но не так медленно, как сканер. StringTokenizer работает быстрее, чем split. Однако я обнаружил, что могу получить двойную скорость, торгуя некоторой гибкостью, чтобы получить ускорение скорости, которое я сделал в JFastParser https://github.com/hughperkins/jfastparser

тестирование на строке, содержащей один миллион дублей:

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

Если у вас есть строковый объект, который вы хотите маркировать, используйте строку split метод над StringTokenizer. Если вы анализируете текстовые данные из источника вне вашей программы, например из файла или от пользователя, Вот где сканер пригодится.

строку.сплит, кажется, гораздо медленнее, чем StringTokenizer. Единственное преимущество split заключается в том, что вы получаете массив токенов. Также вы можете использовать любые регулярные выражения в Сплит. орг.апаш.палата общин.ленг.StringUtils имеет метод разделения, который работает гораздо быстрее, чем любой из двух то есть. StringTokenizer или String.расщеплять. Но загрузка процессора для всех трех почти одинакова. Поэтому нам также нужен метод, который менее интенсивен для процессора, который я все еще не могу найти.

Я недавно сделал несколько экспериментов о плохой производительности строки.split () в высокоэффективных чувствительных ситуациях. Вы можете найти это полезным.

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

суть в том, что строка.split() компилирует шаблон регулярного выражения каждый раз и таким образом может замедлить работу вашей программы, по сравнению с тем, если вы используете предварительно скомпилированный объект шаблона и используете его непосредственно для работы с Строка.

для сценариев по умолчанию я бы предложил шаблон.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;
}

используйте "abc".toCharArray (), чтобы получить массив символов для строки. Например:

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

одно важное отличие заключается в том, что обе строки.split () и сканер могут создавать пустые строки, но 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

Это потому, что разделитель строк.Сплит() и сканер.useDelimiter () - это не просто строка, а регулярное выражение. Мы можем заменить разделитель "" на " + " В приведенном выше примере, чтобы заставить их вести себя как StringTokenizer.

строку.split () работает очень хорошо, но имеет свои собственные границы, например, если вы хотите разделить строку, как показано ниже, на основе одного или двух символов трубы ( | ), это не работает. В этой ситуации вы можете использовать StringTokenizer.

ABC / IJK

Comments

    Ничего не найдено.