Сканер Java против String.split () против StringTokenizer; какой я должен использовать? - PullRequest
10 голосов
/ 10 апреля 2009

В настоящее время я использую split() для сканирования файла, в каждой строке которого есть количество строк, ограниченных '~'. Я где-то читал, что Scanner может лучше работать с длинным файлом с точки зрения производительности, поэтому я подумал об этом.

У меня вопрос: нужно ли мне создавать два экземпляра Scanner? То есть один для чтения строки, а другой на основе строки для получения токенов для разделителя? Если мне придется сделать это, я сомневаюсь, что смогу получить какое-либо преимущество от его использования. Может я что-то здесь упускаю?

Ответы [ 5 ]

8 голосов
/ 15 мая 2013

Сделали некоторые метрики вокруг них в однопоточной модели, и вот результаты, которые я получил.

~~~~~~~~~~~~~~~~~~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            ~
____________________________________________________________________________________________________________

В результате сканер дает лучшую производительность, теперь то же самое нужно оценивать в многопоточном режиме! Один из моих старших сказал, что Tokenizer дает всплеск процессора, а String.split нет.

6 голосов
/ 10 апреля 2009

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

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 голосов
/ 10 апреля 2009

Вы можете использовать метод useDelimiter("~"), чтобы позволить вам перебирать токены в каждой строке с помощью hasNext()/next(), в то же время используя hasNextLine()/nextLine() для перебора самих строк.

РЕДАКТИРОВАТЬ: Если вы собираетесь сделать сравнение производительности, вы должны предварительно скомпилировать регулярное выражение при выполнении теста split ():

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

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

3 голосов
/ 10 апреля 2009

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

РЕДАКТИРОВАТЬ: Вы всегда можете проверить обе реализации, чтобы увидеть, какая из них быстрее. Мне любопытно, если бы scanner мог быть быстрее чем split(). Сплит может быть быстрее для данного размера VS Scanner, но я не уверен в этом.

2 голосов
/ 13 июля 2012

Вам на самом деле здесь не нужно регулярное выражение, потому что вы разбиваете на фиксированную строку. Apache StringUtils split выполняет разбиение на простые строки.

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

У Guava также есть сплиттер, реализованный более OO-способом, но я обнаружил, что он значительно медленнее, чем StringUtils для больших объемов сплитов.

...