KarmaHacker
30 уровень

BufferedReader vs Scanner

Статья из группы Архив info.javarush
участников
Решал сегодня задачу level22.lesson09.task01. В условии нужно считать слова разделенные пробелом, состоящие из несколько строк. Смотря комментарии к этой задачи удивился, что люди считывают строки в основном через BufferedReader. При этом у них возникает куча проблем, строку нужно разделять на слова при помощи split() с переносом строки тоже возникают трудности. Подобные вопросы возникали у меня и на более ранних задачах. В связи с этим вопрос: почему у ДжаваРашевцев такая не любовь к Scanner`у? Это всеобщее заблуждение или я чего-то не знаю? Ведь Scanner отлично справляется, если нам нужно считать не строку целиком, а именно слова разделенные пробелами и на разных строках. Не надо вставлять ни каких костылей в виде сплитов и думать о переносе строк.
Комментарии (10)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
hidden #2729207
Уровень 47
1 сентября 2021, 04:29
Сканер небезопасен для многопоточного использования без внешней синхронизации.
bridennis
Уровень 35
8 декабря 2016, 10:30
На вкус и цвет — товарищей нет, но…

Если Вы сравните две такие реализации:

1) используем BufferedReader

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("c:/Denis/wwwroot/1.txt")))) {
            List<String> chunks = new ArrayList<>();
            String line;
            while ((line = reader.readLine()) != null) {
                for (String chunk : line.split("\\s")) {
                    chunks.add(chunk);
                }
            }
            reader.close();
            System.out.println(chunks);
        } catch (IOException e) {
        }


2) используем Scanner

        try (Scanner reader = new Scanner(new InputStreamReader(new FileInputStream("c:/Denis/wwwroot/1.txt")))) {
            List<String> chunks = new ArrayList<>();
            while (reader.hasNext()) {
                chunks.add(reader.next());
            }
            reader.close();
            System.out.println(chunks);
        } catch (IOException e) {
        }


то первая, естественно, всегда будет работать быстрее (хотя вторая компактнее).
Если мы перепишем Scanner на работу со строками:

3) используем Scanner со строками

        try (Scanner reader = new Scanner(new InputStreamReader(new FileInputStream("c:/Denis/wwwroot/1.txt")))) {
            List<String> chunks = new ArrayList<>();
            while (reader.hasNextLine()) {
                for (String chunk : reader.nextLine().split("\\s")) {
                    chunks.add(chunk);
                }
            }
            reader.close();
            System.out.println(chunks);
        } catch (IOException e) {
        }


то, чт
Yuri_0504
Уровень 11
8 декабря 2016, 12:43
С чего вы взяли, что BufferedReader будет быстрее?
Scanner надо просто уметь пользоваться и сразу все станет компактно:
Scanner scanner = new Scanner(new FileReader(fileName)).useDelimiter("\\s+");

        StringBuilder builder = new StringBuilder();
        while (scanner.hasNext()) {
            builder.append(scanner.next());
Yuri_0504
Уровень 11
8 декабря 2016, 12:50
Ведь Scanner отлично справляется, если нам нужно считать не строку целиком, а именно слова разделенные пробелами и на разных строках. Не надо вставлять ни каких костылей в виде сплитов и думать о переносе строк.
Все верно написано, а не пользуются потому как в лекциях он не рассматривается, а доп.лекции или доки никто не читает (за редким исключением)
Joysi
Уровень 41
8 декабря 2016, 16:02
Плюс далее по курсу будет работа с различными потоками (Stream) — вот и с азов приучают :)
KarmaHacker
Уровень 30
8 декабря 2016, 17:06
Спасибо, за ответ! Понятно, что для разных задач — разные инструменты. Нужно знать их, понимать и уметь применять в правильной ситуации :)
bridennis
Уровень 35
8 декабря 2016, 19:03
С чего вы взяли, что BufferedReader будет быстрее?
Взял мой пример с BufferedReader и ваш, замерил время, с BufferedReader — в два раза быстрее.

Но! Еще раз повторю свою заключительную мысль, здесь дело не в этом (BufferedReader или Scanner), а в том, как вы производите считывание. Чем меньше вы обращаетесь к файлу, тем быстрее будет работать ваш код и компактность здесь ни причем.
Я в BufferedReader считываю построчно, вы (в вашем примере) кусками по whiteSpaces, что значительно медленнее, так что выигрывает именно в этом случае 3-ий вариант (построчный Scanner).

P.S.
Вы меня немного смутили указанием .useDelimiter("\\s+"), всегда считал, что этот паттерн идет в Scanner по умолчанию, перепроверил, действительно, я был прав: "\\p{javaWhitespace}+"
Так что .useDelimiter("\\s+") в вашем примере излишне.
Yuri_0504
Уровень 11
8 декабря 2016, 22:27
Да, вы правы BufferedReader будет быстрее, хотя они оба читают в буфер, размер буфера у BufferedReader по умолчанию больше (8192 против 1024) и его можно задавать, со Scanner так не получится сделать. Если работать с большими массивами данных в потоках, то BufferdReader будет предпочтительней.

P.S. привел для примера первый попавшийся код. Суть в том что в Scanner можно задать разделитель изначально и получать уже преобразованную информацию. По-идее 2 и 3-й варианты вашего кода будут работать с одинаковой скоростью, так как в любом случае используется один буфер в 1024 байта.
Alexey Gutorov
Уровень 17
7 сентября 2020, 05:33
В какой-то из лекций было прямо указано, что Scanner устарел и вообще отстой, так что им не пользуемся
Hardy
Уровень 32
6 декабря 2020, 15:46
Цитата из урока : https://javarush.com/quests/lectures/questsyntax.level03.lecture07 последний абзац: — Использовать Scanner довольно удобно, но от этого не очень много пользы. Дело в том, что в будущем (и в учебе, и на работе) ты будешь часто использовать объекты BufferedReader и InputStreamReader и очень-очень редко объект типа Scanner. В данной ситуации он удобен, но в будущем толку от него мало. Так что мы пользоваться им не будем.