• Авторизация


Программирование на Java: от ламера - чайнику. Пост №2.1. Операторы и конструкции. Матерные. 13-11-2013 21:19 к комментариям - к полной версии - понравилось!


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

Вместо вступления.

Как вы заметили из предыдущего поста, все данные в программе это числа, символы и строки, логические значения и объекты. Объекты, кроме строк и массивов,  в этом посте рассматриваться не будут - им будет посвящен целый пост.

Поскольку любая программа по сути является всего-навсего обработчиком данных, получаемых откуда-либо, то данные надо как-то обрабатывать. Для этого и призваны из глубин ада всевозможные операции:) А они у нас бывают: арифметические, логические и строковые. Начнем с арифметических - они проще:)

Арифметические операторы.

Математику все помнят?:) Тогда сразу и сходу:

"+" - сложение;

"-" - вычитание;

"*" - умножение;

"/" - деление;

"%" - остаток от деления.

Нет, это не смайлики:) Что делают операции, я думаю, понятно без лишних слов. Остаток от деления - это если вы напишете

int ost = 16%3;

то переменная ost будет равна 1. Я думаю, понятно почему:)

Этим операторам всегда нужно 2 операнда. Не пугайтесь страшного слова, операнд - это то, над чем производится операция:) Например, при сложении операнды - это слогаемые:)

Но есть операторы, работающие с одним операндом. Это операторы инкремента и декремента. Записываются они соответственно как "++" и "--". Суть у них простая: инкремент увеличивает на единичку, а декремент вычитает из числа 1. То есть:

i++//; равнозначен записи i = i + 1;

i--;// равнозначен записи i = i - 1;

Стоит так же заметить, что + может складывать не только числа, но и строки:) Правда, результатом будет не число, а строка. Операция называется конкатенация. Без поллитры не выговоришь, я долго учился:)

Логические побитовые операторы.

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

"&" - побитовая операция И(AND). Правило простое: эта логическая операция даст в результате 1, если ни один из битов не равен 0, то есть когда оба бита 1, в остальных случаях будет 0. Суть очень проста. Берем два числа в бинарной форме. Например, 1010 и 0101. Результатом операции 1110&0101 будет 0100. Почему? Объясняю.

Запишем эти числа друг под другом:

1110

0101

====

0100

А теперь весь фокус: мы работаем исключительно с битами. Как обычно, идем справа налево. Первая пара бит это 0 из первого числа и 1 из второго. Смотрим в правило - среди этих бит есть 0, а значит результат будет 0. Берем вторую пару бит, это 1 из первого числа и 0 из второго. Опять смотрим в правило - опять есть 0, а значит результат снова 0. Третья пара бит 1 и 1. Смотрим в правило - результат 1. И так далее. Побитовое логическое И сходно с умножением: умножая биты в столбик вы получите тот же результат:) Запоминаем, мало ли, пригодится:)

"|" - побитовая операция ИЛИ(OR). Правило такое: результат будет нулевым, только если оба бита нулевые. Возьмем для примера числа 1100 и 0101, запишем их так же друг под другом.

1100

0101

====

1101

А теперь так же попарно смотрим на биты и в правило:) Так же идем справа налево. Первая пара 0 и 1. Результат 1. Вторая пара 0 и 0. Результат 0. Третья пара 1 и 1. Результат 1. Обратите внимание, никакого переноса в старший разряд здесь нет, это сугубо побитовая операция. Побитовое логическое ИЛИ сходно с умножением, только нет типичного "0" пишем, 1 в уме", то есть переноса в старший разряд. 1 | 1 = 1.

"^" - побитовое логическое исключающее ИЛИ(XOR). Страшно? Не пугайтесь, всё нормально:) Правило такое: если биты одинаковы - результат 0, если разные - результат 1. Пример: 1100 и 1010. Пишем в столбик:

1100

1010

====

0110

Принцип тот же: берем пары битов и смотрим в правило:)

Эта троица так же требует 2 операнда, а вот следующий работает только с одним.

"~" - побитовая логическая операция НЕ(NOT) или отрицание. Здесь всё ещё проще: он просто инвертирует все биты в числе, где был 0 - будет 1, где была 1 - будет 0, всё просто. Пример:

1010

====

0101

С ним всё черезвычайно просто.

И снова операторы, которые работают с парой операндов.

"<<" - сдвиг влево. Суть такая: берется число и его биты сдвигаются влево на указанное количество позиций, те, что выходят за границы - теряются, а биты справа заполняются нулями. Непонятно?:) Смотрите пример. Возьмём переменную типа byte, 8-битную. Пусть там будет число 01001101. Применим к нему операцию сдвига влево на 2 бита, что в коде запишется как

 01001101 << 2; 

Число после оператора << как раз и задает на сколько сдвигать. А теперь смотрим в правило и думаем, что у нас должно в итоге получиться:) А получится в итоге 00110100. Не трудно заметить, что все биты съехали влево на 2 позиции. Крайние левые два бита, которые 01 вышли за границы и потерялись, а крайние правые два бита должны были бы остаться пустыми, но они заполнились нулями - правило такое:)

">>" - сдвиг вправо, знаковый. Правило у него такое: все биты числа сдвигаются вправо на указанное количество позиций, те, что выходят за правую границу теряются, но в отличии от сдвига влево, биты которые должны были бы остаться пустыми заполняются не нулями, а содержимым знакового разряда числа, то есть крайнего левого бита. Так при сдвиге числа знак не потеряют. Непонятно? Тогда пример, число возьмем то же: 00110101 и так же сдвинем на 2 бита, но вправо. В коде это запишется так

01001101 >> 2;

А теперь давайте смотреть в правило и думать, что у нас получится:) Получится у нас число 00001101. Как видно, мы потеряли крайние правые 2 бита, которые 01, так как они вышли за правую границу. А поскольку крайний правый бит, он же знаковый, у нас равен 0, то позиции, которые должны были бы остаться пустыми заполняются нулями. А если бы мы сдвигали число 11001101 вправо на два бита, мы бы получили 11110011. Мы так же теряем два крайних правых бита из-за выхода их за правую границу числа, но образовавшиеся пустые позиции мы заполняем не нулями, а единицами, так как старший бит, который знаковый, у нас равен 1.

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

А "=", кстати, оператор присваивания, но мы уже с ним знакомы:)

Совмещенные операторы.

Однако, если говорить об операторе присваивания, то разработчики языка Java, да и не только - такое есть во многих языках программирования, например в С, сделали одну интересную штуку. Видимо, им часто приходилось производить арифметические и логические операции типа var = var +19; или var = var & 8; Заместо 19 и 8 может быть любое число и даже другая переменная. И вот, набравшись пивом, они решили объединить операторы арифметических действий и присваивания. Получились операторы "+=", "-=", "*=", "/=", "%=", "&=", "|=" и "^=", которые эквивалентны соответствующим выражениям:

var1 += var2;// эквивалентно выражению var1 = var1 + var2;

var1 -= var2;// эквивалентно выражению var1 = var1 - var2;

var1 *= var2;// эквивалентно выражению var1 = var1 * var2;

var1 /= var2;// эквивалентно выражению var1 = var1/var2;

var1 %= var2;// эквивалентно выражению var1 = var1 % var2;

var1 &= var2;// эвкивалентно выражению var1 = var1 & var2;

var1 |= var2;// эквивалентно выражению var1 = var1 | var2;

var1 ^= var2;// эквивалентно выражению var1 = var 1 ^ var2;

 

Общее для арифметических и логических побитовых операторов.

У побитовых и арифметических двухоперандных операторов есть одна общая черта - это как они пишутся:)

Есть общий вид для них:

var1 <оператор> var2

Побитовое НЕ запишется так :

var1 = ~var2;

или так:

var1 = ~var1; //если мы хотим инвертировать переменную.

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

Итак, выполнение арифметических операций подчиняется следующим правилам:

1) Выражение вычисляется слева направо.

2) Первыми вычисляются выражения в скобках.

3) Сначала вычисляются умножение и деление, а потом сложение-вычитание.

В программе ниже я приведу пример такого загогулистого выражения и там мы разберем приоритеты. Ну, с операциями почти разобрались. Есть ещё одна группа, но мы их рассмотрим чуть позже. А теперь...

МатерныеСинтаксические конструкции.

Любую программу можно, и нужно, разбить на последовательность определенных действий. Это будет зваться алгоритмом программы. Например, пришли мы в магазин купить бутылку вискаря... Скажем, 12-летний Dewar's, литровый:) Что нам нужно сделать когда мы придём в магазин и найдём стеллаж с виски? Распишем по пунктам:

1) Посмотреть на первую бутылку в стеллаже.

2) Если бутылка не Dewar's - перейти к следующей бутылке.

3) Если бутылка Dewar's, но объём поллитра - перейти к следующей бутылке

4) Если бутылка Dewar's и объём литр - взять её и пойти на кассу.

Всё так, не правда ли? В итоге мы по сути циклически перебираем бутылки и проверяем их на какие-либо условия.

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

Конструкция if...else.

Эта конструкция проверяет условие, если оно выполняется - выполняется один блок кода, если нет - другой. Имеет она вот такой вот вид:

if(условие){

//блок кода, который выполнится, если условие истинно

}

else{

//блок кода, который выполнится, если условие ложно

}

Страшно?:) Не пугайтесь, а давайте разбираться. Блок кода - последовательность строчек кода, которая заключена в фигурные скобки. Тут всё просто. Истинно или ложно - это взято из алгебры логики, о ней чуть ниже. Проще говоря истинно - значит условие выполняется, ложно - значит не выполняется.

Условие задается логической или булевой переменной, тип boolean. Однако, явно лишнюю переменную никто не определяет, а чаще используют операции логического соотношения, как в неравенствах:

"==" - равно, проверяет на равенство две переменных или переменную и число, если они равны - будет значение true - истина, обратите внимание - двойное "равно", а не просто "равно", не перепутайте, иначе проверка на условие будет выполняться некорректно;

"!=" - не равно, проверяет на неравенство две переменных или переменную и число, если они равны - будет значение false - ложь;

"<" - меньше, проверяет меньше ли первый операнд второго, если да - выдает нам true;

">" - больше, проверяет больше ли первый операнд второго, если да - даст нам true;

"<=" - меньше или равно. Тут я думаю, всё понятно;

">=" - больше или равно. Та же басня, всё понятно.

Как это всё работает? Да очень просто:) Например, есть у нас переменная типа int с именем varInt, в которой лежит какое-то число. А нам нужно если это число равно 10 приравнять его нулю, скажем. Тогда наш оператор if запишется так:

if(varInt == 10){

varInt = 0;

}

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

Теперь ещё плюшка - условия можно объединять несколько условий в одно выражение. Это делается с помощью логических операций AND, OR, NOT и XOR. Вы их помните по разделу с логическими побитовыми операторами:) Но здесь операции логические и не побитовые, они работают с логическими значениемя true и false, то есть с типом данных boolean. Различать их как-то надо, а потому они иначе пишутся:

"&&" - логическое И(AND) быстрой оценки;

"||" - логическое ИЛИ(OR) быстрой оценки;

"^" - логическое исключающее ИЛИ(XOR);

"!" - логическое отрицание НЕ(NOT).

А теперь внимание - я вам наврал:) Логические операции И и ИЛИ и их побитовые аналоги пишутся одинаково, однако здесь я привёл другую запись, да ещё и написал странные слова "быстрой оценки". Объясню, что это значит. В операции И если первый операнд равен 0 или false, то и всё выражение автоматически приравнивается к 0 или false, по правилу логического И, а значит вычислять значение второго операнда смысла нет. Такая же плюшка с логическим ИЛИ, если первый операнд имеет значение 1 или true. Логические операции быстрой оценки немного ускоряют работу, не проводя вычисление второго операнда, если происходят ситуации, описанные выше. В логических выражениях хорошим тоном считается использование именно операторов быстрой оценки.

Вы могли заметить, что я фактически приравнял 0 к false, а 1 к true. По сути, так оно и есть, и можно получить правила логических операций из побитовых, если 0 заменить на false, а 1 - на true:) Попробуйте и вы всё поймёте:)

А теперь пример. Та же переменная varInt, но теперь мы приравниваем её нулю только если она лежит в определенном интервале значений, а если нет - производим её инкремент. Возьмем интервал от 10 до 30. Тогда в коде это запишется так:

if(varInt > 10 && varInt < 30){

varInt = 0;

}

else{

varInt++;

}

Мы объединили два условия в одном. Проще всего понять условие, если прочитать его по-русски, а ещё лучше - вслух:) Фактически, этот кусок кода можно прочитать так: "Если переменная varInt больше 10 и меньше 30, то приравнять её к 0, иначе - увеличить на 1".

Кстати, операторы if можно вкладывать один в другой. Например, предыдущий кусок кода можно было бы переписать так:
if(varInt > 10){

if(varInt < 30){

varInt = 0;

}//конец блока проверки условия "меньше 30"

else varInt++;

}//конец блока проверки условия "больше 10"

else{

varInt++;

}

Этот кусок кода читается чуть иначе: "Если varInt больше 10, то если varInt меньше 30, то приравнять его к 0, иначе увеличить на 1". Кусок становится не особо удобен для чтения, поэтому если есть возможность лучше объединять условия, а не вкладывать операторы if.

Кстати, тут есть хитрость: оператор else привязывается к ближайшему в коде концу блока кода от оператора if. То есть, else varInt++; привязывается к проверке условия "меньше 30", а else {varInt++;} привязан к проверке условия "больше 10". Тут надо уметь грамотно расставлять скобки:)

Ещё вы могли заметить, что я написал else varInt++; без скобок и закидать меня тапочками:) Но не стоит. Если после ключевых слов if или else идёт только одна строчка кода, оканчивающаяся на ";",  то скобки можно не расставлять. По сути получается, что фигурные скобки превращают некую последовательность команд, которая между ними заключена в одну команду для таких вот условий:) Маскировка:)

Ещё есть такое ключевое слово, как elseif. Вот догадайтесь, что оно делает, а я пока покурю пойду:)

Догадались? Нет? Тогда смотрите. Оператор elseif используется, когда если одно условие не выполняется нужно проверить другое. В общем виде это выглядит так:

if(условие1){

//блок кода, который должен выполнится при истинности условия 1

}

elseif(условие2){

//блок кода, который должен выполниться при выполнении условия 2 и невыполнении условия 1

}

Вот такие пироги:)

Последнее что хотелось бы добавить об операторе if это его тернарная форма. Не надо выпадать в осадок, тернарный - значит тройной. Кстати, операторы, работающие с 2 операндами называются бинарными, а те, что работают с одним операндом - унарные. Вот подумайте на досуге, какие из вышеперечисленных операторов будут бинарными, а какие - унарными:) Такая вот домашка:)

Однако, вернёмся к тернарной форме if. Пишется она так в общем виде:

(условие) ? выражение1 : выражение2;

Что это значит? Если в теории - выполняется проверка условия, если оно истинно - выполняется выражение 1, если ложно - выражение 2. Объясню на примере. Например, есть у нас две переменные типа int с именами а и b. Мы создаем третью переменную того же типа с именем с, а присвоить ей надо максимальное значение из переменных a и b. То есть, если а больше - с присвоить значение а, если b больше - присвоить с значение b. Можно написать стандартный оператор if и выглядеть он будет вот так:

int a = 10;

int b = 20;

int c;

if(a > b) c = a;

else c = b;

А можно применить тернарную форму оператора if и сократить размер кода:

int a = 10;

int b = 20;

int c = (a > b) ? a : b;

Эти два фрагмента кода идентичны по выполняемым действиям, но выглядят по разному. Кстати, вопрос - чему будет равна переменная с?:)

 

Оператор switch.

Ещё один оператор, влияющий на логику выполнения программы. Общий вид у него такой:

switch(переменная){

case значение0:{

//блок кода 0

break;

}

case значение1:{

//блок кода 1

break;

}

default:{

//блок кода по умолчанию

break;

}

Что делает этот оператор? Всё очень просто: он сравнивает значение данной ему переменной с указанными после слов case значениями и в случае совпадения - выполняет соответствующий блок кода. Код под ключевым словом default выполняется, если ни одно из значений case не совпало со значением переменной. А блоков case может быть сколько угодно:)

Оператор break прерывает выполнение кода и выходит из оператора switch, передавая управление на строчку кода за блоком switch. Он почти всегда обязателен, иначе выполнение кода продолжится, то есть нашел он одно совпадение, выполнил код под соответсвущей меткой case, а потом пошёл выполнять блоки кода под следующими метками case, пока не выйдет они не кончатся или пока не нарвется на break. Однако, отсутствие оператора break можно использовать и во благо, например, если для определенных значений нужно выполнить одни и те же операции. Тогда эти блоки case запишутся так:

case значение0:

case значение1:

case значение2:{

//выполняем нужные нам операции

break;

}

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

Однако ОЧЕНЬ ВАЖНО не забывать в блоках case после всех операций ставить оператор break, иначе программа будет работать не так, как нам надо; если у вас на несколько вариантов значения переменной одно и то же действие - он нужен только в единственном экземпляре.

 

Засим пока что всё. Воскуривайте, вдумывайтесь, что не понятно - пишите в комментах:)

Скоро вторая часть:) В ней поведем разговор о массивах, ещё несколько управляющих конструкций и узнаем ещё кое-что важное о переменных:)

вверх^ к полной версии понравилось! в evernote
Комментарии (7):
Блииинн.. сколько умных слов и цыфарок.. мне чтоб это осилить и понять - явно надо сосредоточиться и читать не в таком состоянии после созерцания красивостей) не об умных вещах щас мысли, ох, не об умных))
Yuri_Prime 17-11-2013-03:44 удалить
Ответ на комментарий Isida_Morgenstern # Это надо сосредоточиться, сконцентрироваться и прочее:) Тут главное понять, что все эти страшные вещи делают и запомнить так, как тебе удобнее и понятнее, а потом уже будет проще:)
Ответ на комментарий Yuri_Prime # Yuri_Prime, вооооот. Страшное слово - запомнить.. А еще мотивация нужна) Если я буду знать, зачем это помнить - я это запомню, я щас немецкий учу, мотивация зачем - хочу. А что мы с помощью этого всего количества буковок делаем? Программируем на джава? а что программируем? Джава - это язык такой программирования? /капец, зачем я все это выясняю, я больше чем уверена, что не пойму ничего/
Yuri_Prime 17-11-2013-03:53 удалить
Ответ на комментарий Isida_Morgenstern # Это пока просто теория. Суть в том, что на этих страшных буковках и циферках построены все программы:) Когда запомнишь какая что делает и когда научишься разбивать описываемую программу на последовательность действий, условий, повторений - тогда будешь программировать уже что хочешь:)
Ответ на комментарий Yuri_Prime # Yuri_Prime, о, то есть, как бы как русский алфавит для написания слов, так и это, только для программирования.
Yuri_Prime 17-11-2013-19:23 удалить
Ответ на комментарий Isida_Morgenstern # Isida_Morgenstern, Да именно так по сути:)
Ответ на комментарий Yuri_Prime # Yuri_Prime, о, ну тогда главное, смысл, я уловила, остальное дело техники - зашить дырявую память)


Комментарии (7): вверх^

Вы сейчас не можете прокомментировать это сообщение.

Дневник Программирование на Java: от ламера - чайнику. Пост №2.1. Операторы и конструкции. Матерные. | Yuri_Prime - Записки Yuri_Prime | Лента друзей Yuri_Prime / Полная версия Добавить в друзья Страницы: раньше»