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#nextTypeSystem.inage
Тепер 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.