Управление порядком выполнения операций

Как вы уже догадываетесь, команды (операции) выполняются друг за другом. Запись операций идет слева направо, сверху вниз. Как уже говорилось, каждая операция оканчивается знаком «;» (бывают исключения и мы их увидим).
Перед тем, как погрузиться в мир команд управления, давайте немного расширим наши возможности по выводу данных. Вот как будет выглядеть команда для вывода символов без перехода на другую строку. Например вывести символ «*».

Причем важно отметить, что курсор не будет переходить на следующую строку. А команда для перехода на следующую строку выглядит так:

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

Существует иной вариант решения

Вы конечно заметили, что наш «квадрат» не совсем квадратный — он больше прямоугольник из-за того, что по вертикали строки больше. Но будем называть его квадратом, т.к. количество символов по вертикали и горизонтали одинаковое.
Как я только что говорил, наша программа в обоих вариантах не самая удачная. Первый вариант длинный и обладает следующим недостатком — если мы захотим сделать квадрат например 7×7, то нам придется добавлять много строк.
Второй вариант конечно короче. Но у него есть тот же недостаток — для рисования квадрата другого размера нам придется все равно менять программу. Да и код выглядит пока страшненько.
Думаю, достаточно очевидно, что требуется конструкция цикла. Для большинства языков программирования таких конструкций бывает несколько. Давайте их и рассмотрим.

 

Операторы циклов

В Java существует три способа организации цикла.

1. Цикл for

Цикл for использует следующую форму записи

for(<инициализация>; <условие>; <последействие>) операция;

Давайте сразу рассмотрим в качестве примера использования цикла for нашу задачу — нарисовать квадрат.

Внутри скобок у слова for мы видим три разделенных точкой с запятой части.
int i=0 — этот оператор не должен нас удивить — мы объявили переменную «i» целого типа и присвоили ей значение 0. Этот оператор будет выполняться ТОЛЬКО ОДИН раз в начале цикла.
i<10 — это условия будет проверяться ПЕРЕД КАЖДЫМ циклом. Если условие является истинным (возвращает true) — цикл выполняется. Если false — цикл заканчивается. Выражение может быть достаточно сложным, но мы этим воспользуемся позже.
i++ — этот оператор выполняется ПОСЛЕ КАЖДОГО цикла.

Все достаточно очевидно — мы выводим квадрат со стороной в 10 символов. Переменная «i» в данном случае исполняет роль счетчика — при каждом проходе цикла она увеличивается на 1, сравнивается со значением 10 и если меньше — выполняется операция печати строки из 10 символов.
Как видим, наша программа все-таки не так хороша. При желании вывести квадрат со стороной в 20 символов, нам придется менять значение 10 на 20 и еще изменить строку в печатью — заменить 10 символов «*» на 20.
Давайте сначала попробуем написать программу, которая выводит в ряд столько «звездочек», сколько мы захотим. Это несложно. Вот так:

Обратите внимание — мы ввели новую переменную «count» и используем ее в цикле. Сейчас этот шаг может показаться не совсем понятным и нужным, но на самом деле чуть позже мы увидим, почему это удобно. Давайте разберем наш код по шагам. Итак:

int count = 10;

Этот оператор вводит переменную «count» и присваивает ей значение 10. Именно столько символов мы хотим напечатать. Если потребуется изменить количество символов, то будет достаточно просто поменять 10 на что-то другое.

Этот цикл напечатает 10 символов «*» в одну строку. Есть отличие между командами System.out.print и System.out.println. Первая выводит символы и не переходит на следующую строку, вторая — напечатает символы и курсор перейдет на следующую строку.
В нашем случае мы напечатаем 10 символов и курсор останется на этой же строке. Если мы захотим напечатать что-то еще, то печать начнется на той же строке. И наконец:

System.out.println();

Эта команда просто переводит курсор на следующую строку

 

Если собрать наши программы LoopForOne и LoopForTwo вместе, то мы увидим, что в них есть все, что нам нужно — первая умеет печатать нужной количество строк, вторая — нужную нам строку.
Давайте попробуем провернуть это действие. Но сначала нам надо познакомиться еще с одним видом оператора — составной оператор. В другой литературе он может называться как-то иначе — я не могу точно сказать, как он должен называться по науке.
Его идея очень проста — заключив несколько операций в фигурные скобки, их можно рассматривать как один. Давайте опять посмотрим пример.

Если запустить это пример, то мы увидим, что он выводит 10 строк и в каждой строке только один символ. Давайте более внимательно посмотрим на наш цикл for. Теперь мы после него «открыли» фигурную скобку

А после двух операций (печати символа и перехода на другую строку) — «закрыли». Т.е. теперь внутри цикла выполняется не один оператор, как в предыдущей программе, а два. Как вы уже наверно догадались, в цикле будут выполнятся ВСЕ операции, которые находятся внутри фигурных скобок.
Обратите внимание на два момента:
1. После фигурных скобок точка с запятой не ставится.
2. Достаточно часто даже одна операция в цикле заключается в фигурные скобки — это делает код однообразным и часто облегчает его чтение и понимание.
С учетом второго замечания наша программа LoopForTwo может выглядеть вот так.

Думаю, вы обратили внимание, что я делаю отступы в программе. Они помогают легче читать код. Советую вам с самого начала привыкать форматировать текст программы — это быстро войдет в привычку и в будущем пригодится. В NetBeans существует команда форматирования текста открытого в редакторе файла — Alt+Shift+F или через меню Source->Format. Можно выделить кусок текста и отформатировать только его.
Теперь давайте выполним нашу главную задумку — напишем программу, которая рисует квадрат с заданной стороной. Это потребует от нас совместить два цикла — один цикл для строк, другой — для символов в строке. Итак:

Здесь мы видим более сложную конструкцию, состояющую из двух циклов. Причем один «вложен» в другой. Давайте разберем сначала внутренний цикл, который связан с переменной «k».

Его задача очень простая — он печатает строку из count символов. И если мы поместим его еще в один цикл, то он будет послушно печатать строку столько раз, сколько ему будет сказано.
Задача внешнего цикла (с переменной «i») заключается в том, чтобы сначала вызвать цикл для печати строки (с переменной «k») а после этого перейти на следующую строку (операция System.out.println(). Теперь еще раз самое время взглянуть на нашу программу еще раз.

Надеюсь, что вы разобрались. Обратите внимание, что наша переменная count уже начинает нам помогать. Теперь для того, чтобы изменить размеры квадрата, нам надо поменять только ее значение. А циклы уже будут использовать ее значение для своей работы.
Давайте напоследок нарисуем более сложную фигуру — треугольник. Сначала я приведу код программы и вы можете попробовать понять, за счет чего рисуется именно треугольник. А потом можете прочитать мои подсказки.

Если вы внимательно смотрели код, то могли видеть подсказку — в комментарии по поводу k<i+1.
Именно в этом выражении и кроется решение — горизонтальный размер строки зависит от того, какая это строка по счету. У самой первой строки длина будет 1, у второй — 2 и так далее.

 

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

Как видите, первая часть у нас отсутствует — мы ее сделали строчкой выше. А можете так:

Здесь мы убрали третью часть и сделали увеличение переменной внутри цикла. Можно сделать и так:

Цикл for можно вообще сделать пустым — вот таким.

Правда тогда этот цикл будет длиться бесконечно. И он не так уж редко встречается в программах.
Мы очень подробно рассмотрели цикл for, но кроме него есть еще два варианта циклов. Давайте обратимся к ним.

 

2. Цикл с предусловием while

Формат записи этого цикла

while(<условие>) операция;

Пока условие является истинным — цикл выполняется. Давайте сразу напишем простой пример для вывода строки символов произвольной длины.

Как видите с одной цикл пишется проще — там всего лишь одно условие. С другой стороны — мы вынуждены сами менять нашу переменную «i» внутри цикла — кстати нередко об этом забывают и программа входит в бесконечный цикл. Хотя конструкция для бесконечного цикла не такая уж редкая вещь — его просто прерывают специальной конструкцией, о которой мы еще поговорим.
Хотя используя оператор ++ программу можно немного упростить (и даже избавиться от составного оператора в данном случае, но я вам не советую).

Название «с предусловием» должно быть понятно — цикл будет выполняться после проверки условия — т.е. условие будет перед циклом.
Давайте с помощью этого цикла выполним нашу задачу — нарисуем квадрат. А для самостоятельной работы попробуйте нарисовать треугольник.

Если вам не очень нравятся отдельные операторы i++ и k++ — это дело вкуса — можно привести все к виду как в примере LoopWhileTwo.

 

3. Цикл с постусловием do .. while

Формат записи этого цикла

do операция; while(<условие>);

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

И снова мы можем упростить наш цикл используя оператор ++

Думаю, что вам не составило труда понять, почему это оператор с постусловием — условие проверяется ПОСЛЕ цикла. В отличии от оператора while цикл do выполнится как минимум один раз. Даже если условие будет ложным. Можете установить значение count равным -10 и убедиться, что цикл while не выводит ни одного символа, а цикл do выводит один символ.

 

А теперь задачка для очень и очень внимательных. Попробуйте понять, что делает это код (подсказка — вспомните про пустой оператор)

Правда забавно выглядит ? Такое ощущение, что у нас цикл while совмещен с циклом do. Но на самом деле это не совсем так. Давайте немного отформатируем наш текст.

Т.е. мы сделали «ничего» во втором цикле while.

 

4. Операторы управления циклом — break и continue

При выполнении цикла вы можете использовать еще две очень удобные конструкции, которые позволят вам строить интересные конструкции.
Оператор break позволяет прервать цикл, а оператор continue позволяет пропустить остаток операторов в цикле и сразу начать цикл заново.

Оператор break

Оператор break в простой форме позволяет прервать исполнение цикла и перейти к оператору, расположенному сразу после цикла.
Рассмотрим вариант использования оператора break. Напишем несложную программу, которая сосчитает количество чисел, сумма которых не должна первышать 300 и каждое следующее больше предыдущего на 10. Начальное число будет равно 1. У меня получилось 8 чисел (1, 11, 21, 31, 41, 51, 61, 71 — сумма 288).

Как видим, все достаточно просто — при сумме больше 300 мы просто вызываем команду break. И нас «перебрасывает» на оператор System.out.println(«Count=» + count);.
Кроме этого можно обратить внимание на конструкцию оператора for(;;). Если бы мы не использовали оператор break, то цикл стал бесконечным.
В этой части мы пока не будем рассматривать более сложную конструкцию оператора break, которая позволяет не просто выйти из оператора цикла (обращаю ваше внимание, что можно выйти не только из цикла for, но и других циклов), но и указать насколько «высоко» мы хотим выйти — если вы находитесь внутри нескольких циклов. Эту конструкцию предлагаю оставить на более позднее время. Во-первых это не часто используется. А во-вторых — не хочется прямо сейчас слишком усложнять.

 

Оператор continue

Оператор continue позволяет вам не прервать цикл, а перейти на начало цикла не исполняя операции после этого оператора. Например, давайте напечатаем только нечетные числа от 0 до 20. Конечно вы уже можете это сделать и без оператора continue, но попробуем использовать его.

Как видим, все достаточно просто — мы проверяем, является ли число четным и если это так, выполняем оператор continue.
Как и в случае с оператором break есть более сложные варианты использования, но по уже указанным соображениям мы пока не будем о нем говорить.

 

Условный оператор

Появление условного оператора достаточно понятно — не всегда надо выполнять ту или иную операцию. Например, в одном случае надо печатать, а в другом — не надо. Иногда надо печатать один символ, а иногда — другой. Если опять начинать с примеров (я очень люблю примеры — там гораздо все понятнее, чем теоретические рассуждения), то давайте нарисуем наш квадрат, но теперь сделаем его сложнее — мы его сделаем пустым внутри. Вот таким:

Выглядит это конечно не квадратом, но как мы уже говорили — количество символов в строке и количество строк у нас совпадают — в этом заключается «квадратность» нашей фигуры.
Подход к рисованию такой фигуры будет такой же, как и при рисовании заполненного квадрата. но только теперь нам надо в одном случае рисовать символ «*», а в другом — пробел. Во такой » «. Итак, у нас явно возникает потребность в проверке некоторого условия, по которому мы будем рисовать или пробел или «звездочку».

 

Давайте по традиции приведем формат записи условного оператора.

if (<условие>) операция1; else операция2;

Т.е. если условие истинно, то выполняется операция1, иначе — операция2. Есть упрощенная форма:

if (<условие>) операция;

Если условие истинно (возвращает true), то операция выполнится. Если ложное — ничего не выполнится. А точнее будет выполняться следующая операция после условного оператора. Например

Подозреваю, что здесь все достаточно очевидно. Если переменная A больше B, то напечатаем строку «a > b». Иначе — «a <= b». Т.к. я очень люблю расставлять скобки — я бы записал это так

Со скобками мы уже сталкивались — это дает нам возможность исполнять несколько операторов по условию. Давайте сразу приступим к делу — будем рисовать наш квадрат. По сути наша задача заключается в изменении алгоритма печати символа «*». Все остальное можно оставить как есть. Условием печати «*» будет совпадение значение переменных цикла i и k с крайними значениями. А это либо 0, либо count-1 (именно count-1, а не просто count)

Вся идея заключается в нашем сложном условии

k==0 || k==count-1 || i==0 || i==count-1

Если пытаться его читать на человеческом языке, то получится следующее:
«k» равно нулю ИЛИ «k» равно count-1 ИЛИ «i» равное нулю ИЛИ «i» равно count-1

Вуаля. Мы сделали это. И ведь это было не так уж и трудно. Но у нас и фигура была не столь проблематичная. Теперь давайте закрепим наши знания путем создания программ. Итак, сделаем теперь треугольник, который мы сделали для демонстрации циклов for, но с усложнением — сделаем его тоже «полым». Приведу сразу код программы — читайте и пробуйте. Там ничего сложного нет.

А теперь для самостоятельной работы я предлагаю вам нарисовать вот такие фигуры:

Я вам настоятельно советую сделать хотя бы одну фигуру. Самостоятельно. Это только сначала кажется, что все понятно и писать легко и просто — вам просто необходимо сделать самому хоть что-то — иначе можно считать наше знакомство с Java весьма поверхностным.
Как вы думаете, почему в компаниях спрашивают людей с опытом работы ? Ведь на самом деле они тоже не помнят все конструкции назубок и не всегда знают ответ на достаточно простые вопросы. Но эти люди писали код, отлаживали его, запускали, искали ошибки — накопили опыт. Так вот эти программы (пусть и простые) — это ваш опыт. Накапливайте его как можно больше.

 

Множественный выбор

Давайте попробуем написать программу, которая делает несложную, но достаточно нудную операцию — в зависимости от числа (от 1 до 10) выводит его название.

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

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

Запускаем нашу программу и видим слово Unknown — все правильно. Число 50 не входит в наши значения. Теперь подставим число 5. Наша программа выдаст несколько неожиданный результат:

Мы добрались до строки, но дальше мы стали выполнять все операции подряд. Да, эта особенность оператора выбора. Для того, чтобы прервать операции, необходимо использовать оператор break. Вот так должна выглядеть наша программа:

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

Здесь можно видеть, что мы можем выполнить операцию System.out.println(«One or Two»); как для значения 1, так и для значения 2.
Под словом switch может находится переменная целочисленных типов — byte, short, int. Тип long использовать нельзя.
Начиная с версии 1.7 можно использовать тип String (строки), но на это мы еще раз обратим внимание, когда дойдем до работы со строками.

 

Мы рассмотрели все основные конструкции для управления ходом программы. Нас ждут еще некоторые открытия на этом пути, но бОльшая часть пройдена. Так что постарайтесь решить те задачи, которые я предлагал.
Перед тем, как окунуться в изучение объектно-ориентированного программирования (ООП) я предлагаю вам установить IDE NetBeans — чтобы облегчить разработку наших программ. Встречайте Установка IDE NetBeans.