Только начал изучать Java. Дали простенькую задачку, но чтобы при этом программа реагировала на ошибки пользователя.Задача вот:Составить линейную программу, печатающую значение true, если указанное высказывание является истинным, и false — в противном случае: Сумма двух первых цифр заданного четырехзначного числа равна сумме двух его последних цифр. Я сделал так,что изначально число введённое с клавиатуры типа String.Потом переводиться в массив Char. И вот собственно мой вопрос. Возможно ли чтобы после введения в консоли 4 символа массива программа автоматически запускалась (без Enter).
Поскольку не совсем ясно, что именно вы имеете ввиду под запуском программы я отвечу на две возможных интерпретации вопроса.
Если вы предполагаете, что операционная система запустит JVM в момент когда вы напишете последний символ следующей команды:
$ java com.example.Main 4532
то к сожалению это сделать невероятно сложно и сильно зависит от предоставляемых настроек терминала операционной системы и из вашей программы вы не сможете это сделать, поскольку управление вашей программе не передастся до тех пор пока она не будет запущена, а изменить вы хотите именно поведение запуска.
Теперь рассмотрим другой вариант. Допустим вы запускаете свое приложение аргументов, после чего пользователь видит предложение ввести четырехзначное число:
$ java com.example.Main
Enter 4-digit number:
И в этом случае мы рассматриваем задачу запустить обработку входных данных как только пользователь введет 4 цифры.
Короткий ответ звучит как "Да, это возможно". В принципе в программировании любое поведение возможно реализовать. Однако ответ будет не кроссплатформенный, пока вы не позаботитесь об этом, или же не используете библиотеку, которая уже об этом заботится. Например jCurses предоставит необходимый функционал.
Почему я вообще говорю о том, что надо предусматривать конкретную платформу? Дело в том, что System.in соединяется с системным терминалом, который в большинстве случаев по умолчанию реализует буферизацию ввода, то есть передает программе входные данные после ввода enter от пользователя.
Если здоровое любопытство программиста ведет вас к тому, чтобы таки реализовать желаемое вами поведение, давайте напишем наивный (и, стало быть, самый короткий) рабочий вариант, с которого можно начать удовлетворять любопытство.
Сходу я могу написать вместе с вами программу, которая будет реализовывать необходимое вам поведение на unix-подобных системах. Заранее приношу извинения за игнорирование каноничных правил обработки ошибок систем ввода/вывода: я уверен, что вы в состоянии самостоятельно дополнить программу до безопасного варианта.
Начнем с реализации метода считывания n цифр из потока:
private static char[] readInRawMode(int numberOfCharacters, InputStream stream) throws IOException {
char [] result = new char[numberOfCharacters];
InputStreamReader is = new InputStreamReader(stream);
int characterCount = 0;
while (characterCount < numberOfCharacters) {
char aChar = (char) is.read();
if (aChar < '0' || aChar > '9') { //проверим, что это цифра
continue;
}
result[characterCount] = aChar;
characterCount++;
}
return result;
}
Если мы сейчас используем этот метод в программе, например readInRawMode(4, System.in)
, то вызов is.read()
заблокируется до тех пор, пока пользователь не нажмет enter
. Для того чтобы избежать этого поведения, нам нужно перевести текущий системый терминал в режим raw
перед вызовом метода и вернуть его в режим cooked
после завершения метода обработки. В режиме raw
терминал не повторяет символы вводимые пользователем на экране (как при введении пароля в терминале) и мы должны сделать это самостоятельно. Более того, в raw терминал перестанет реагировать на спец символы включая символ перевода каретки и enter
от пользователя также будет игнорироваться и не отображаться до тех пор пока он не введет необходимое количество цифр. Это как раз то поведение которое нас устраивает.
Собирая все описанное вместе мы получим что то вроде подобного:
package com.alex;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
System.out.print("Enter 4-digit number : ");
char [] input = interactiveRead();
System.out.println();
System.out.println("User input: " + Arrays.toString(input));
}
private static char[] interactiveRead() throws IOException, InterruptedException {
String[] raw = {"/bin/sh", "-c", "stty raw </dev/tty"}; //команда перевода текущего терминала в режим raw
String[] cooked = {"/bin/sh", "-c", "stty cooked </dev/tty"}; //команда перевода текущего терминала в режим cooked
Process p = Runtime.getRuntime().exec(raw);
p.waitFor();//ожидаем перевода терминала
try {
return readInRawMode(4, System.in);
} finally {
p = Runtime.getRuntime().exec(cooked); //возвращаем терминал к изначальному виду вне зависимости от ошибок
p.waitFor();
}
}
private static char[] readInRawMode(int numberOfCharacters, InputStream stream) throws IOException {
char [] result = new char[numberOfCharacters];
InputStreamReader is = new InputStreamReader(stream);
int characterCount = 0;
while (characterCount < numberOfCharacters) {
char aChar = (char) is.read();
if (aChar < '0' || aChar > '9') {
continue;
}
System.out.print(aChar); // повторяем "правильный" символ на экране, чтобы пользователь понял что он все делает правильно
result[characterCount] = aChar;
characterCount++;
}
return result;
}
}
В действительноси, в большинстве случаев нет смысла писать сложную логику "богатого" взаимодействия пользователя с терминалом. Это дает сильное усложнение логики приложения (то, что мы описали только что недостаточно: необходимо позаботиться об ошибках выполнения и управляющих комманд таких как ^C в терминале), а профит минимальный: в современном мире пользователи предпочитают графические интерфейсы, а люди привыкшие работать с терминалом и так поймут что происходит и что именно нужно вводить: это люди технического склада ума.
Также хочу заметить, что написанное приложение заточено на запуск из терминала руками и только тогда оно будет корректно работать. В случае запуска через IDE ее родной терминал не переведется в необходимый режим, поскольку используется не стандартный системный терминал, а его обертка, которая также реализует буферизацию. Надеюсь это делает еще более понятной сложно написания универсального решения для вашей задачи.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
У меня задача написать свой механизм блокировок LockИ я нашел уже готовый самописный пример, упрощенной версии этого механизма: