Вопрос

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

Это было полезно?

Решение

По сути, они лошади для курсов.

  • 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. Медленнее, чем токенизатор, но проще в использовании, так как он вызывает из класса строк.

Сканер стал на JDK 1.5. Это самый гибкий и заполняет давний разрыв на Java API, чтобы поддержать эквивалент знаменитого семейства функций CS Scanf.

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

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

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

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

String.split кажется намного медленнее, чем StringTokenizer. Единственное преимущество с разделением - это то, что вы получаете массив токенов. Также вы можете использовать любые регулярные выражения в разделении. org.apache.commons.lang.stringutils имеет разделенный метод, который работает гораздо быстрее, чем любой из двух, а именно. StringTokenizer или String.Split. Но использование процессора для всех трех почти одинакова. Таким образом, нам также нужен метод, который менее интенсивный процессор, который я до сих пор не могу найти.

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

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

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

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

Используйте «ABC» .tchararray (), чтобы получить массив Char для строки. Например:

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

Одно важное отличие состоит в том, что обе string.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

Это связано с тем, что разделитель для string.split () и scanner.usedelimiter () - это не просто строка, а регулярное выражение. Мы можем заменить разделитель «" +"в приведенном выше примере, чтобы они вели себя как StringTokenizer.

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

ABC | IJK

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top