Рубрики
Без рубрики

Будьте осторожны с методами сканирования в Java

Иногда бывает забавно создать интерактивное приложение со сканером. К сожалению, мы должны быть осторожны с методами сканирования. С пометкой программирование, учебник, java, новички.

Для новых студентов часто бывает интересно писать интерактивные программы с использованием сканера на Java. К сожалению, есть несколько неприятных подводных камней, которые на самом деле не способствуют положительному опыту для этих студентов. В результате я пришел с предупреждением: будьте осторожны с методами сканирования в Java.

Проблема, С Которой Сталкиваются Студенты

Когда я впервые изучал Java, я ни разу не использовал сканер. На самом деле я даже не прикасался к утилите до тех пор, пока у меня за плечами не было двухлетнего опыта работы в отрасли. Но по какой-то причине учебная программа Java в моем нынешнем учебном заведении широко использует сканер, поэтому я решил немного рассказать о подводных камнях некоторых методов Сканера.

В частности, я хочу поговорить об использовании сканера для считывания пользовательского ввода из командной строки. Часто это желательно, потому что мы хотим предложить пользователю ввести некоторые данные, такие как его имя или любимый номер. Затем мы выполняем некоторые забавные вычисления и выводим результаты пользователю. Я приведу вам пример (пользовательский ввод выделен жирным шрифтом).:

Введите свое имя: Джереми Привет, Джереми!

В этом примере мы предложили пользователю ввести свое имя и отправили его обратно. Мы можем сделать это, используя следующий фрагмент кода Java:

Scanner input = new Scanner(System.in);
System.out.print("Enter your name: ");
String name = input.nextLine();
System.out.println("Hi, " + name + "!");

Это не так уж плохо! Но что, если мы захотим попросить номер телефона? К счастью для нас, в API сканера есть целый ряд методов токенизатора, таких как следующая строка () , чтобы получить все, что мы хотим от пользователя, и автоматически преобразовать его в соответствующий тип. Тем не менее, будьте осторожны при их использовании.

Объяснение, Которого Желают Студенты

На этом этапе многие студенты спросят меня:

В чем тут дело? Почему я должен вызывать следующую строку() и анализировать значение вручную, когда я могу просто вызвать соответствующий метод напрямую?

Студенты Повсюду

И их беспокойство совершенно обоснованно! Я бы никогда никого не попросил делать больше работы, чем нужно, так в чем же тут дело?

Проблемы

Что ж, как выясняется, если вы начнете использовать такие методы, как следующая строка() , не обращая особого внимания на то, что вы анализируете, вы столкнетесь с несколькими проблемами.

Возможно, наиболее очевидной проблемой являются проблемы с набором текста. Например, допустим, мы запрашиваем у пользователя номер, и он дает нам имя. Без надлежащей обработки ошибок наше решение наверняка выйдет из строя. Тем не менее, такого рода проблемы не так уж сложно обнаружить или решить. В конце концов, как только пользователь введет неверный текст, решение выйдет из строя с полезной ошибкой.

Вместо этого существует гораздо более гнусная проблема, которую, согласятся даже опытные программисты, трудно устранить, и она возникает, когда мы начинаем смешивать использование различных методов сканирования. Взгляните на следующий пример и посмотрите, сможете ли вы понять, что произойдет, если мы предоставим программе номер 25 и мое имя.

Scanner input = new Scanner(System.in);
System.out.print("Enter your age: ");
int age = input.nextInt();
System.out.print("Enter your name: ");
String name = input.nextLine();
System.out.println("Your name is " + name + " and you are " + age);

Не слишком углубляясь в решение, среднестатистический человек сказал бы, что это решение печатает “Вас зовут Джереми, и вам 25 лет”. И, честно говоря, я их за это совсем не виню. Логика есть, но результатов нет. К счастью, я не оставлю тебя в подвешенном состоянии!

Охота на насекомых

Если вы уже продвинулись вперед и сами протестировали это решение, вы наверняка заметили, что происходит что-то странное. Для начала, наш вывод неверен. Вместо “Вас зовут Джереми, и вам 25” на выходе будет написано “Вас зовут, и вам 25”. Сразу же мы заметим, что имя отсутствует в выводе, что означает, что переменная имя , вероятно, хранит пустую строку.

Что еще хуже, когда мы действительно запустим решение, мы увидим, что нам будет предложено ввести данные только один раз. После того, как мы введем наш возраст, весь сценарий будет выведен на экран следующим образом (ввод пользователем выделен жирным шрифтом):

Введите свой возраст: 25 Введите свое имя: Вас зовут, и вам 25 лет

На этом этапе мы будем ломать голову, задаваясь вопросом, как вызов nextLine() сразу же вернул пустую строку. К счастью, у меня есть ответ!

Escape-последовательности

Всякий раз, когда мы запрашиваем у пользователя ввод, он получает эту причудливую строку, в которой он может сбросить текст и нажать enter . Следите за этой последней частью, потому что это очень важно.

Этот текст состоит из символов, все из которых имеют базовое числовое значение. Например, буква “а” имеет числовое значение 97, в то время как число “7” имеет числовое значение 55 — как ни странно. К счастью, нет необходимости запоминать все эти значения. Вместо этого проверьте таблицу ASCII для получения списка из первых 256 символов.

Если мы просмотрим эту таблицу, то заметим, что есть несколько немного странных символов. Например, весь первый столбец этой таблицы содержит список escape-последовательностей. Эти символы служат особой цели, которая не всегда четко видна на экране.

Как выясняется, существует несколько таких escape-последовательностей, которые отвечают за обозначение окончаний строк в тексте: 10 (Перевод строки) и 13 (Возврат каретки). В зависимости от системы, для обозначения конца строки может использоваться любая комбинация этих двух escape-последовательностей.

Мошеннические Новые Линии

В качестве аргумента мы предположим, что наша система помечает новые строки символом перевода строки. В Java символ перевода строки может быть записан с помощью ‘\n’. Другими словами, каждый раз, когда мы нажимаем клавишу ввода, мы можем представить, как один из этих символов пробирается в наш текст.

Теперь, когда мы знаем о последовательностях побега, почему бы нам не попробовать еще раз поохотиться на жуков? Следите за строкой, где мы объявляем переменную возраста. Вот тут-то и начинает проявляться ошибка.

Scanner input = new Scanner(System.in);
System.out.print("Enter your age: ");
int age = input.nextInt();
System.out.print("Enter your name: ");
String name = input.nextLine();
System.out.println("Your name is " + name + " and you are " + age);

Вы выяснили, где может быть ошибка? Я дам тебе подсказку. Метод nextInt() заботится только о том, чтобы захватить следующий номер. Другими словами, он оставляет позади наш мошеннический символ новой строки (‘\n’).

После того, как мы вызовем nextInt() , мы предложим пользователю ввести свое имя. В этот момент мы вызываем следующую строку() , которая выполняется до следующего символа новой строки. К сожалению, мы оставили один позади, когда вызвали nextInt() . В результате следующая строка() не нужно ждать, пока мы введем какой-либо текст. Он просто возвращает пустую строку.

Если это неясно, я рекомендую попробовать разместить этот фрагмент кода над списком возрастов, разделенных пробелами. Например, ознакомьтесь со следующей расшифровкой (ввод пользователем выделен жирным шрифтом):

Введите свой возраст: 20 19 31 15 Введите свое имя: Ваше имя 19 31 15 и тебе 20 лет

Как мы видим, возраст установлен на первое число в списке (в данном случае “20”), и программа никогда не запрашивает имя. Вместо этого оставшаяся часть входного буфера (в данном случае ” 19 31 15\n”) считывается в виде строки и сохраняется как имя.

В следующем разделе мы поговорим о том, как справиться с новой линией, которая осталась позади.

Работа по исправлению

К счастью, есть несколько исправлений этой проблемы. Один полагается на то, чтобы исправить нашу ошибку, а другой – на устранение основной причины нашей проблемы.

Поскольку мы знаем, что оставили позади новую линию, все, что нам нужно сделать, это использовать ее. Другими словами, мы можем сделать пустой вызов следующей строки() , прежде чем вызывать ее как обычно:

Scanner input = new Scanner(System.in);
System.out.print("Enter your age: ");
int age = input.nextInt();
System.out.print("Enter your name: ");
input.nextLine();
String name = input.nextLine();
System.out.println("Your name is " + name + " and you are " + age);

Обратите внимание, как мы добавили вызов следующая строка() чуть выше точки, где мы храним имя. Теперь, когда мы оставим этот символ “\n”, мы наведем порядок в строке 5. Затем мы сможем двигаться дальше по нашей жизни в строке 6.

В качестве альтернативы мы можем полностью устранить эту проблему, заменив наш вызов nextInt() вызовом nextLine() . Затем нам нужно будет разобрать строку, чтобы получить нужное нам целое число:

Scanner input = new Scanner(System.in);
System.out.print("Enter your age: ");
int age = Integer.parseInt(input.nextLine());
System.out.print("Enter your name: ");
String name = input.nextLine();
System.out.println("Your name is " + name + " and you are " + age);

Вместо того чтобы убирать за собой, мы можем использовать всю строку за один раз и разобрать ее вручную. Лично я предпочитаю этот вариант, но оба работают просто отлично. В любом случае, мы полностью устранили эту неприятную ошибку сканера.

Открытый форум

Итак, мораль этой истории такова: будьте осторожны с API сканера. Хотя многие методы существуют для вашего удобства, их смешивание может привести к некоторым неприятным ошибкам, которые трудно отследить. Конечно, вам решать, что вы будете делать с этими новыми знаниями.

Во всяком случае, на этом пока все! Если вам понравилась эта статья или у вас есть какие-то отзывы, дайте мне знать в комментариях. Кроме того, если у вас есть какие-либо собственные советы или рекомендации по работе со сканером на Java, не стесняйтесь делиться.

И если вы чувствуете себя особенно щедрым, подпишитесь на мой сайт , Кодер-отступник.

Оригинал: “https://dev.to/renegadecoder94/be-careful-with-scanner-methods-in-java-460m”