February 18, 2020

Программирование в Java 2

// Ввод с консоли

Для считывания данных который ввел пользователь нужно использовать технологию Scanner.

Для начала технологию, нужно подключить, для этого перед объявлением класса прописываем такую строчку:

import java.util.Scanner;

При помощи этой строчки импортируется, все не обходимое для работы со сканером.

Далее внутри метода нужно создать объект сканнера (про объекты поговорим позже)

Scanner Имя = new Scanner(System.in);

В качестве имени для объекта сканера часто используют in, но вы можете назвать как захотите.

Scanner in = new Scanner(System.in);

Теперь давайте попробуем считать и записать данные в переменную

String input = in.nextLine();

В переменную input запишется строка, которую введет пользователь.

(конструкция не совсем понятная, позже вы детально поймете, каждый символ, а пока просто запомните)

Чтобы разобраться как работает ввод данных, попробуйте считать данные и вывести на экран.

Напишем не большую программу, спросим имя и поздороваемся.

Вот исходный код:

Также вы можете разобрать код в онлайн редакторе.

Для начала мы импортируем сканер (1 строчка)
Внутри main, создаем объект сканера для доступа к методу nextLine(), который обеспечивает считывание вводных данных (5 строчка)
Просим ввести имя (7 строчка)
Создаем переменную типа string и записываем в нее считанные данные, которые ввел пользователь (на этом моменте программа остановится и не продолжится, пока пользователь не введет данные) (8 строчка)
И выводим Hello и через пробел имя (которое мы считали) (10 строчка)

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

На 8-ой строчке мы создали переменную и присвоили ей in.nextLine(); при помощи объекта через точку можно подключатся к его методам(функциям), если вы работаете в IDE, то после того как вы набрали in. должно высветится подсказка с возможными методами, давайте их разбирать:

Для работы со строками можно использовать два метода

next();
nextLine();

Оба метода считывают строчку, но next() - считает до первого пробела (ввод не остановится если вы поставите пробел, но считается все до первого пробела), а
nextLine() - считывает вместе с пробелами.

Можно записать только в переменную типа string

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

Вот методы для int и double

nextInt();
nextDouble();

Позже вы познакомитесь с другими типами данных, вот методы для их чтения

nextByte();
nextShort();
nextLong();
nextFloat();
nextBoolean();

// Арифметические Операции (Выражения)

В программирование очень большая часть состоит из вычислений и выражений.

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

Для выполнения операции нужен оператор. Многие из них вам будут очень хорошо знакомы из математики.

Операторы

Оператор сложения +
вычисляет результат сложения двух значений

Оператор вычитания -
вычисляет результат вычитания одного значения из другого

Оператор умножения *
вычисляет результат умножение одного значения на другое

Оператор деления /
вычисляет результат деление одного значение на другое

Оператор деления по модулю %
вычисляет остаток от деления одного значения на другое

Напомню, что такое остаток при делении. Делим 3 на 2 - на цело делится 1 раз и остается еще 1 - это и есть остаток от деления.

С первыми тремя операторами все не так сложно.

Пример:

System.out.println(2 + 2); // Выведет 4
System.out.println(2 - 2); // Выведет 0
System.out.println(2 * 2); // Выведет 4

С делением не все так гладко

Пример:

Если мы делим на цело, то все нормально

System.out.println(10 / 5); // Выведет 2

А если нет, то появляется проблема

System.out.println(7 / 5); // Выведет 1

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

Деление по модулю, у многих почему-то с этим оператором возникают проблемы, не нужно его боятся, все крайне просто, он вычисляет остаток при делении

System.out.println(7 / 5); // 2

Напишу еще пару примеров

3  % 3   // 0
10 % 5   // 0
5  % 3   // 2
20 % 3   // 2

Приоритет выполнения действий

Все работает как в математике - сначала умножение и деление (добавим сюда еще и деление по модулю), потом сложение и вычитание.

И конечно же мы можем использовать скобки для установки приоритетов.

Еще про операторы

Теперь когда мы познакомились с основными операторами, нужно разобраться какие бывают понятия и классификации.

Операторы делятся по признаку количеству данных над которыми выполняется операция.

Те операторы, которые мы уже рассмотрели называются Бинарным (двойными), так как выполняют вычисление только у двух значений.

Если вам не понятно, почему они работают только с двумя значениями, объясню подробнее.
Есть вот такое выражение 1 + 2 + 3 и вроде как тут три разных значения, о каких двух вообще может идти речь?
Дело в том, что в выражении стоит два оператора сложения - соответсвенно операция выполняется два раза - следовательно, если операторы бинарные - значит у нас 4 значения, внезапно появилось еще одно значение, давайте разберем этот пример по этаппно:

Для начала выполняется 1 + 2, ровно 3
А дальше 3 + 3, вот откуда берется еще одно значение, после вычисления выражения - это больше не выражение, а самостоятельное значение и мы можем с ним работать как и с любыми другими значениями.

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

Давайте с ними знакомится.

Унарный минус -
делает выражение отрицательным (если унарный минус были использован к отрицательному значению - будет положительное и наоборот)

Очень страшное слово (это программирование, привыкайте)
Инкремент (на самом деле ничего сложного, нет) ++
увеличивает значение на 1

И еще одно страшное слово (вы ведь понимаете, что тут не будет ничего сложного?)
Декремент --
вычитает от значение 1

Инкремент и декремент бывает двух видов:
Постфиксный - оператор будет стоят после значения

int a;
a++;
int a;
a--;

Префиксный - оператор будет стоять после значения

int a = 0;
++a;
int a = 0;
--a;

Теперь давайте разбираться на примере

Начнем с префиксного

int a = 0; // создаем переменную со значением 0.
++a; // инкрементируем переменную.
System.out.println(a); // выведется 1.

Переменная a просто увеличилась на 1.

Мы можем инкрементировать внутри конструкции вывода

int a = 0;
System.out.println(++a); // Выведется 1.

Если бы мы использовали декремент, переменная уменьшилась на 1.

Теперь разберемся с постфиксным, он работает немного по другому.

int a = 0;
System.out.println(a++); // Вывод 0.

Выводится 0, дело в том, что операция постфиксной инкрементации имеет приоритет выполнения ниже, чем вывод в консоль. То есть a увеличится на один, после того как выведется.

int a = 0;
System.out.println(a++); // Вывод 0.
System.out.println(a);   // Теперь вывод 1.

Вот еще пример

int a = 0;
System.out.println(a++);   // Вывод 0.
System.out.println(a++);   // Теперь вывод 1.
System.out.println(a++);   // Теперь вывод 2.
System.out.println(a++);   // Теперь вывод 3.
System.out.println(a);     // Теперь вывод 4.
System.out.println(a);     // Теперь вывод 4.

Немного позже мы будем очень активно применять операторы инкремента и декремента.

И последний вид операторов Тернарный он всего один и познакомимся с ним позже.

Также операторы по разному работают с разными типами данных, например если используется + с числовыми типами - это оператор сложения, а если со string, то это оператор слияния строк.
Все выше перечисленные примеры, будут работать только если в унарных операторах используется какое-либо значение числового типа данных (double, int), и если в бинарных операторах используются только числовые типы и два значения одного типа данных.

// Остальные числовые типы данных

Перед темой "Преобразование типов", нужно познакомится с остальными числовыми данными.

Целые, аналогичные int, но с другим возможным диапазоном значений.

// Карточка с целыми

И еще один тип для не целых (дробных)

// Карточка с float

// Преобразование типов данных

Преобразование типа данных - это процесса преобразование одного типа данных в другой.

К примеру:

byte a = 1;
int b = a;

Переменная b расширила диапазон значений переменной a без потери данных.
По сути значение переменной a положили в другую переменную с большим диапазоном значений.

Преобразование без потери данных можно по данной схеме

byte -> short -> int -> long

byte  a = 0;
short b = a;
int   c = b;
long  d = c;

Еще раз вспомним про бинарные операторы
Дело в том, что бинарные операторы сначала приравнивают два значение к общему типу и только после выполняют вычисление.

Вот пример:

int  a = 1;
byte b = 2;

System.out.println(a + b);

Этот код работает так:

Сначала идет проверка, имеют ли один тип два значения
Если да, то числа складываются (тип данных остается прежний)
Если нет, то данные преобразуются к общему типу

Общий тип - будет тот тип, который хранит больший диапазон значений (соответсвенно занимает больше места)

При преобразовании byte и int - общим типом будет - int
Значит значение типа byte - преобразуется в int (а судя из того, что написана выше - если преобразовать меньший тип к большему - потери данных не будет).

В итоге значение будет ровно 3 типа int.

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

Пример:

int a = 128;
byte b = a;

При такой записи компилятор сообщить об ошибке, нельзя автоматически преобразовать в int в byte. Значит нужно преобразовывать явно.

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

int a = 128;
byte b = (byte)a;

System.out.println(b);

Теперь все преобразовалось, но тип данных byte - не может хранить числа больше 127, а в примере записывается 128. Вы удивитесь, но вывод будет равен -128 (минимальное возможно значение типа byte). На вопрос почему именно это число, нужно отвечать отдельной статьей, об этом позже.

Это и был пример явного преобразования с возможной потеряй данных (в данном случае с потерей данных).

Ранее встретился случай, что при делении обрезалась не целая часть, теперь давайте решать эту проблему.

System.out.println(5 / 2);

Ответ будет 2, не целая часть обрезалась. Это происходит из-за того, что делится два значения типа int, так как два значения являются одним типом данных - преобразования не будет, соответсвенно и значение будет типа int, а так как int не может хранить не целые значения, все что после запятой обрезается.

Для решения это проблемы есть несколько вариантов:

Установить одно(или два) из значений тип данных double, чтобы при делении все преобразовалось в double.

System.out.println(5.0 / 2);

Отличная возможность рассказать про особенность double. Если число типа double - имеет нулевое значение после запятой - пишется 0 - значит если мы преобразуем любое целое число в double, к концу будет приписываться точка и ноль.

Преобразовать одно(или два) из значений в double.

System.out.println((double)5 / 2);

В данном случае мы преобразовали значение 5 в double, теперь оно будет иметь вид 5.0

Теперь деление будет работать правильно, выведет 2.5

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

System.out.println((double)(5 / 2));

Вывод будет 2.0, так как сначала вычисляется выражение, и далее значение преобразуется в double.

Есть еще некоторые способы преобразования, продолжим позже.

//Резюме