Ключевой момент: чтение ввода с консоли даёт возможность программе принимать ввод от пользователя
В предыдущем параграфе значение radius было зафиксировано в исходном коде. Чтобы использовать другой радиус, нужно каждый раз менять исходный код и перекомпилировать программу. Очевидно, что это не удобно, поэтому вместо такого подхода, вы можете использовать класс Scanner для консольного ввода.
Java использует System.out для обращения к стандартному устройству вывода и System.in для стандартного устройства ввода. По умолчанию, устройство вывода – это дисплей монитора, а устройство ввода – это клавиатура. Для выполнения консольного вывода, вы просто используете метод println для отображения в консоль простых значений или строк. Консольный ввод не поддерживается напрямую в Java, но вы можете использовать класс Scanner для создания объекта для чтения ввода из System.in. Это делается так:
Scanner input = new Scanner(System.in);
Синтаксис new Scanner(System.in) создаёт объект типа Scanner. Синтаксис Scanner input объявляет, что input является переменной, чей тип – Scanner. Вся строка Scanner input = new Scanner(System.in) создаёт объект Scanner и присваивает его ссылку переменной input. Объект может вызывать свои методы. Вызвать метод объекта означает запросить объект выполнить задачу. Вы можете вызвать метод nextDouble() для чтения значения double следующим образом:
double radius = input.nextDouble();
Инструкция считывает число с клавиатуры и присваивает это число переменной radius. Перепишем программу из предыдущего урока, чтобы она запрашивала радиус у пользователя:
import java.util.Scanner; // Scanner находится в пакете java.util public class ComputeAreaWithConsoleInput { public static void main(String[] args) { // Создаём объект Scanner Scanner input = new Scanner(System.in); // Запрос пользователю на ввод радиуса System.out.print("Введите радиус: "); double radius = input.nextDouble(); // Вычисление площади double area = radius * radius * 3.14159; // Отображение результата System.out.println("Площадь круга радиусом " + radius + " равна " + area); } }
Обратите внимание, что десятичным разделителем, в зависимости от локали вашей системы, может быть точка или запятая. Если у вас возникает ошибка InputMismatchException, то посмотрите чуть ниже.
Строка 10 отображает в консоли надпись «Введите радиус: ». Это называется prompt (подсказка, напоминание), поскольку он направляет пользователя к вводу данных. Если ваша программа ожидает ввода с клавиатуры, она всегда должна говорить пользователю, ввод каких данных от него ожидается.
print или println
Метод print на десятой строке
System.out.print("Введите радиус: ");
идентичен методу println с той лишь разницей, что println переходит к началу новой строки после отображения строки, а print после вывода не переходит к следующей строке.
Строка 8 создаёт объект Scanner. Инструкция на одиннадцатой строке считывает ввод с клавиатуры.
double radius = input.nextDouble();
После того, как пользователь ввёл число и нажал клавишу Ввод (Enter), программа считывает число и присваивает его переменной radius.
Больше подробностей об объектах будет представлено в одной из последующих главах. На текущий момент просто примите, что это то, как получить вход с консоли.
Конкретный импорт
Класс Scanner находится в пакете java.util. Он импортируется на строке 2. Имеется два вида инструкций import: конкретный импорт и импорт с подстановочными символами. Конкретный импорт импортирует определённый единичный класс в инструкции import. Например, следующая инструкция импортирует Scanner из пакета java.util.
import java.util.Scanner;
Импорт с подстановочным символом
Импорт с подстановочным символом импортирует все классы из пакета, используя звёздочку в качестве подстановочного символа. Например, следующая инструкция импортирует все классы из пакета java.util.
import java.uitl.*;
Разница в производительности между импортом одного класса или всех классов в пакете
Информация для классов из импортируемого пакета не считывается во время компиляции или во время выполнения если класс в программе не используется. Инструкция import просто говорит компьютеру, где расположен класс. Нет разницы в производительности между конкретным импортом или импортом с подстановочным символом.
Ещё одна программа, которая даёт пример чтения нескольких значений с клавиатуры. Программа считывает три числа и показывает их среднее арифметическое:
import java.util.Scanner; // Scanner из пакета java.util public class ComputeAverage { public static void main(String[] args) { // Создание объекта Scanner Scanner input = new Scanner(System.in); // Запрос пользователю ввести три числа System.out.print("Введите три числа: "); double number1 = input.nextDouble(); double number2 = input.nextDouble(); double number3 = input.nextDouble(); // Вычисление средней double average = (number1 + number2 + number3) / 3; // Вывод результата System.out.println("Среднее чисел " + number1 + " " + number2 + " " + number3 + " равно " + average); } }
Листинг с номерами строк:
Код для импорта класса Scanner (строка 2) и создание объекта Scanner (строка 8) такие же, как и в предшествующем примере, как и во всех новых программах, которые вы будете писать, для чтения ввода с клавиатуры.
Строка 10 делает запрос пользователю ввести три числа. Числа считываются на строках 11-13. Вы можете ввести три числа разделив их пробелами, а затем нажать кнопку Enter, или нажимать клавишу Enter после каждого числа. Оба варианта показаны в примерах запуска этой программы.
Если вы введёте что-либо кроме числа, то произойдёт ошибка во время выполнения. В одной из последующих глав вы научитесь как обрабатывать ошибки, чтобы программа могла продолжать работать.
Примечание: большинство программа в начальных главах этого сайта выполняют три шага – ввод, обработка и вывод, это также называется IPO (от английских input, process, and output). Ввод – это получение данных от пользователя; обработка – это выработка результата, используя ввод, а вывод – это отображение результатов.
Решение проблемы с ошибкой InputMismatchException
Если при попытке ввести число с плавающей точкой, например, такой строкой программы:
double radius = input.nextDouble();
Вы получаете ошибку:
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.nextDouble(Scanner.java:2413) at ComputeAreaWithConsoleInput.main(ComputeAreaWithConsoleInput.java:10)
Это означает, что локаль* вашей системы в качестве десятичного разделителя ожидает не точку, а запятую (или наоборот).
*Региональный стандарт, региональные настройки (проф. жарг. лока́ль от англ. locale, /lɔ.kal/ или /ləuˈkɑ:l/) — набор параметров, определяющий региональные настройки пользовательского интерфейса, такие как язык, страна, часовой пояс, набор символов и т. п.
Выходов из этой ситуации два:
- использовать десятичный разделитель вашей локали (точку вместо запятой или запятую вместо точки)
- чуть изменить программу – явно указать локаль
Для этого при создании объекта Scanner добавьте .useLocale(Locale.US). Например, объект создавался следующим образом:
Scanner input = new Scanner(System.in);
После дополнения получается такая строка создания объекта:
Scanner input = new Scanner(System.in).useLocale(Locale.US);
Также в начале программы требуется сделать дополнительный импорт:
import java.util.Locale;
К примеру, код программы из этого параграфа, чтобы она начала принимать числа, у которых десятичным разделителем является точка, становится таким:
import java.util.Scanner; // Scanner находится в пакете java.util import java.util.Locale; public class ComputeAreaWithConsoleInput { public static void main(String[] args) { // Создаём объект Scanner Scanner input = new Scanner(System.in).useLocale(Locale.US); // Запрос пользователю на ввод радиуса System.out.print("Введите радиус: "); double radius = input.nextDouble(); // Вычисление площади double area = radius * radius * 3.14159; // Отображение результата System.out.println("Площадь круга радиусом " + radius + " равна " + area); } }
Проверь себя:
- Как вы пишите инструкцию, позволяющее пользователю ввести значение double с клавиатуры?
- Что произойдёт, если вы введёте 5a когда выполняется следующий код?
double radius = input.nextDouble();
- Имеется ли какая-либо разница в производительности между следующими двумя инструкциями импорта?
import java.util.Scanner; import java.util.*;
У меня вопрос: при попытке скомпилировать код выдается ошибка Scanner is already defined in this compilation unit, т.е. сканер уже определен в этом модуле компиляции — в чем ошибка и как исправить?
Здравствуйте! Если в вашем коде есть строка
то вы не можете назвать ваш класс Scanner. То есть
вызовет именно ту ошибку, которую вы написали.
Причина, думаю, очевидна — один класс Scanner уже есть (вы его импортировали) и вы хотите создать второй класс с точно таким же именем.
Решение: просто используйте для своего собственного класса любое другое имя.
Эта ошибка характерна не только для класса Scanner, но и для любого другого — в коде не может использоваться два класса с одинаковыми именами.
Например, код
Вызовет аналогичную ошибку:
Большое спасибо! Разобрался