TL; DR Використовуйте scanner.skip("\\R")
перед кожним scanner.newLine()
викликом, який виконується після:
scanner.next()
scanner.next*TYPE*()
метод.
Що потрібно знати:
Текст, який представляє кілька рядків, також містить символи, що не друкуються між рядками (ми їх називаємо роздільниками рядків)
- повернення каретки (CR - у рядках-рядках, представлених як
"\r"
)
- рядок (LF - у рядкових літералах, представлених як
"\n"
)
коли ви читаєте дані з консолі, це дозволяє користувачеві вводити свою відповідь, і коли він завершиться, йому потрібно якось підтвердити цей факт. Для цього користувачеві потрібно натиснути клавішу «ввести» / «повернути» на клавіатурі.
Важливо те, що ця клавіша, крім забезпечення розміщення даних користувачів на стандартний вхід (представлений System.in
яким зчитується Scanner
), також надсилає \r\n
після нього роздільні лінії, що залежать від ОС (як для Windows ).
Отже, коли ви запитуєте у користувача такого значення, як age
вводити типи користувачів 42 та натискання, стандартний ввід міститиме "42\r\n"
.
Проблема
Scanner#nextInt
(та інші методи) не дозволяє Сканеру споживати ці роздільники рядків. Він прочитає їх з (як інакше Сканер знав би, що у користувача немає більше цифр, які представляють значення, ніж обличчя білого проміжку?), Який видалить їх зі стандартного вводу, але він також буде кешувати ці роздільники рядків всередині . Що нам потрібно пам’ятати, це те, що всі методи Scanner завжди скануються, починаючи з кешованого тексту. Scanner#nextType
System.in
age
Тепер Scanner#nextLine()
просто збирає та повертає всі символи, поки не знайде роздільники рядків (або кінець потоку). Але оскільки роздільники рядків після зчитування номера з консолі знаходяться негайно в кеші сканера, він повертає порожню рядок, тобто сканер не зміг знайти жодного символу перед цими роздільниками рядків (або в кінці потоку).
BTW nextLine
також споживає ці роздільники ліній.
Рішення
Так що, якщо ви хочете , щоб попросити номера , а потім по всій лінії, уникаючи при цьому , що порожній рядок як результат nextLine
, або
- споживати роздільник ліній, залишений
nextInt
із кешу сканерів
- дзвінок
nextLine
,
- чи більш читаним способом буде IMO , зателефонувавши
skip("\\R")
або skip("\r\n|\r|\n")
дозволити Сканеру пропустити частину, узгоджену роздільником рядків (детальніше про \R
: https://stackoverflow.com/a/31060125 )
- взагалі не використовувати
nextInt
(ні next
, або будь-які nextTYPE
методи). Натомість читайте цілі дані по черзі, використовуючи nextLine
та аналізуйте номери з кожного рядка (якщо один рядок містить лише одне число) до відповідного типу, наприклад int
через Integer.parseInt
.
BTW : методи можуть пропускати роздільники (за замовчуванням всі пробіли, такі як вкладки, роздільники рядків), включаючи кешовані сканером, доки вони не знайдуть наступне значення, що не має роздільника (маркер). Завдяки цьому для введення, як кодScanner#nextType
"42\r\n\r\n321\r\n\r\n\r\nfoobar"
int num1 = sc.nextInt();
int num2 = sc.nextInt();
String name = sc.next();
зможе правильно призначити num1=42
num2=321
name=foobar
.