JavaRush /Java блог /Java Developer /Клас Scanner в Java
Автор
Milan Vucic
Репетитор по программированию в Codementor.io

Клас Scanner в Java

Стаття з групи Java Developer
Привіт! Наше сьогоднішнє заняття буде особливим! До цього під час розв'язання задач і написання програм алгоритм був простим: ми пишемо якийсь код, запускаємо метод main(), програма робить те, що від неї вимагається, і завершує свою роботу. Але тепер усе зміниться! Сьогодні ми навчимося по-справжньому взаємодіяти з програмою: ми навчимо її реагувати на наші дії! Можливо, ти вже зрозумів, до чого ми хилимо. Цю лекцію присвятимо детальному розбору одного з класів мови Java – Scanner. Цей клас стане в пригоді, якщо тобі потрібно буде зчитувати дані, які вводять юзери. Перед тим, як ми перейдемо до вивчення коду, скажи, тобі колись доводилося зустрічатися з таким пристроєм як сканер? Напевно так. Зсередини будова сканера досить складна, але суть його роботи доволі проста: він зчитує ті дані, які користувач у нього вводить (наприклад, паспорт або страховий поліс) і зберігає зчитану інформацію в пам'яті (наприклад, у вигляді зображення). Так от, сьогодні ти створиш свій власний сканер! З документами він, звісно, не впорається, а ось із текстовою інформацією – цілком :) Поїхали! Клас Scanner - 1

Java Scanner Class

Перше і головне, з чим нам потрібно познайомитися, – клас java.util.Scanner. Його функціональність дуже проста. Він, немов справжній сканер, зчитує дані з джерела, яке ти для нього вкажеш. Наприклад, із рядка, з файлу, з консолі. Далі він розпізнає цю інформацію й обробляє потрібним чином. Наведемо найпростіший приклад:

public class Main {

   public static void main(String[] args) {

       Scanner scanner = new Scanner("Тече вода в синє море,\n" +
               "Та не витікає,\n" +
               "Шука козак свою долю,\n" +
               "А долі немає.");
       String s = scanner.nextLine();
       System.out.println(s);
   }
}
Ми створили об'єкт сканера і вказали для нього джерело даних (рядок із текстом). Метод nextLine() звертається до джерела даних (нашого тексту з чотиривіршем), знаходить там наступний рядок, який він ще не зчитував (у нашому випадку – перший) і повертає його. Після чого ми виводимо його в консоль: Виведення в консоль:
Тече вода в синє море,
Ми можемо використовувати метод nextLine() кілька разів і вивести весь шматок поеми:

public class Main {

   public static void main(String[] args) {

       Scanner scanner = new Scanner("Тече вода в синє море,\n" +
               "Та не витікає,\n" +
               "Шука козак свою долю,\n" +
               "А долі немає.");
       String s = scanner.nextLine();
       System.out.println(s);
       s = scanner.nextLine();
       System.out.println(s);
       s = scanner.nextLine();
       System.out.println(s);
       s = scanner.nextLine();
       System.out.println(s);
   }
}
Щоразу наш сканер робитиме один крок уперед і зчитуватиме наступний рядок. Результат роботи програми – виведення в консоль:
Тече вода в синє море, Та не витікає, Шука козак свою долю, А долі немає.
Як ми вже казали, джерелом даних для сканера може бути не тільки рядок, а й, наприклад, консоль. Важлива новина для нас: якщо раніше ми тільки виводили туди дані, тепер будемо вводити дані з клавіатури! Подивимося, що ще вміє клас Scanner:

public class Main {

   public static void main(String[] args) {

       Scanner sc = new Scanner(System.in);
       System.out.println("Введіть число:");

       int number = sc.nextInt();

       System.out.println("Дякую! Ви ввели число " + number);

   }
}
Метод nextInt() зчитує і повертає введене число. У нашій програмі він використовується для того, щоб присвоїти значення змінній number. Це вже більше схоже на справжній сканер! Програма просить користувача ввести в рядок будь-яке число. Після того, як користувач це зробив, програма дякує йому, виводить в консоль результат своєї роботи і завершується. Але у нас залишилася одна серйозна проблема. Користувач може помилитися і ввести щось не те. Ось приклад, коли наша поточна програма перестане працювати:

public class Main {

   public static void main(String[] args) {

       Scanner sc = new Scanner(System.in);
       System.out.println("Введіть число:");

       int number = sc.nextInt();

       System.out.println("Дякую! Ви ввели число " + number);

   }
}
Спробуємо ввести замість числа рядок "JavaRush". Виведення в консоль:
Введіть число: JavaRush Exception in thread "main" java.util.InputMismatchException at java.util.Scanner.throwFor(Scanner.java:864) at java.util.Scanner.next(Scanner.java:1485) at java.util.Scanner.nextInt(Scanner.java:2117) at java.util.Scanner.nextInt(Scanner.java:2076) at Main.main(Main.java:8) Process finished with exit code 1
Ой-ой, усе погано -_- Щоб уникнути схожих ситуацій, нам потрібно придумати спосіб перевірки даних, які вводить користувач. Наприклад, користувач вводить що завгодно, крім числа, – добре б вивести в консоль попередження, що введена інформація не є числом, а якщо все гаразд – вивести текст підтвердження. Але для цього нам треба фактично "зазирнути в майбутнє" – дізнатися, що там далі в нашому потоці. Чи вміє Scanner у Java це робити? Ще як уміє! І для цього в нього є ціла група методів: hasNextInt() – метод перевіряє, чи є наступна порція введених даних числом або ні (повертає, відповідно, true або false). hasNextLine() – перевіряє, чи є наступна порція даних рядком. hasNextByte(), hasNextShort(), hasNextLong(), hasNextFloat(), hasNextDouble() – усі ці методи роблять те саме для інших типів даних. Спробуємо змінити нашу програму для читання числа:

public class Main {

   public static void main(String[] args) {

       Scanner sc = new Scanner(System.in);
       System.out.println("Введіть число:");

       if (sc.hasNextInt()) {
           int number = sc.nextInt();
           System.out.println("Дякую! Ви ввели число " + number);
       } else {
           System.out.println("Вибачте, але це явно не число. Перезапустіть програму і спробуйте знову!");
       }

   }
}
Тепер наша програма перевіряє, чи є наступний введений символ числом або ні. І тільки в разі, якщо є, виводить підтвердження. Якщо ж введення не пройшло перевірку, програма це помічає і просить спробувати знову. По суті, ти можеш спілкуватися з об'єктом Scanner і заздалегідь дізнаватися, який тип даних тобі очікувати. "Гей, сканер, що там далі буде? Число, рядок, чи ще що? Число? А яке – int, short, long?" Така гнучкість дає тобі можливість вибудовувати логіку своєї програми залежно від поведінки користувача. Ще один важливий метод, на який варто звернути увагу – useDelimiter(). У цей метод передається рядок, який ви хочете використовувати як роздільник. Клас Scanner в Java - 2Наприклад, ми несподівано захопилися японською поезією і вирішили зчитати за допомогою сканера кілька хокку великого поета Мацуо Басьо. Навіть якщо три різні вірші передані нам одним кострубатим рядком, ми легко можемо їх розділити і красиво відформатувати:

public class Main {
   public static void main(String[] args) {
       Scanner scan = new Scanner("На голій гілці'" +
               "Ворон сидить самотньо.'" +
               "Осінній вечір." +
               "''***''" +
               "У небі такий місяць,'" +
               "Немов дерево спиляно під корінь:'" +
               "Біліє свіжий зріз." +
               "''***''" +
               "Як розлилася річка!'" +
               "Чапля бреде на коротких ніжках,'" +
               "По коліно у воді.");

       scan.useDelimiter("'");

       while (scan.hasNext()) {
           System.out.println(scan.next());
       }

       scan.close();
   }
}
Ми використовуємо як роздільник рядків метод useDelimeter() класу Scanner: він відповідає за поділ вхідних даних на частини. У нашому випадку для поділу рядків як аргумент передається і використовується одинарна лапка ("'"). Наступний за цією лапкою текст відображається в новому рядку, оскільки в циклі while ми використовуємо метод println() класу System для зчитування даних. Як наслідок, в консолі у нас з'явиться гарне виведення, зовсім як у книжках:
На голій гілці Ворон сидить самотньо. Осінній вечір. *** У небі такий місяць, Немов дерево спиляно під корінь: Біліє свіжий зріз. *** Як розлилася річка! Чапля бреде на коротких ніжках, По коліно у воді.
У цьому ж прикладі є ще один метод, на який потрібно обов'язково звернути увагу – close(). Як і будь-який об'єкт, що працює з потоками введення-виведення, сканер потрібно закрити після завершення своєї роботи, щоб більше не споживати ресурси нашого комп'ютера. Ніколи не забувай про метод close()!

public class Main {

   public static void main(String[] args) {

       Scanner sc = new Scanner(System.in);
       System.out.println("Введіть число:");

       int number = sc.nextInt();

       System.out.println("Дякую! Ви ввели число " + number);
      
       sc.close();// ось тепер ми зробили все правильно!

   }
}
Ось і все! Як бачиш, клас Scanner досить простий у використанні та дуже корисний! :)
Коментарі (2)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Олексій Моцьор Рівень 27 Expert
6 липня 2023
Метод hasNext() перевіряє, чи є у сканера інший токен на вході. Сканер розбиває вхідні дані на токени, використовуючи шаблон роздільника, який за промовчанням відповідає пробілу . Тобто hasNext() перевіряє введення та повертає true , якщо він містить інший непробільний символ.