Освоюємо Java/Керування порядком виконання

Матеріал з Вікіпідручника
Перейти до: навігація, пошук

Java, як і інші мови програмування, підтримує умовні інструкції та цикли, що визначають порядок виконання інструкцій у програмі. В англійській мові для цього поняття застосовують термін control flow — керування течією.

Зміст

Блоки [ред.]

Перед тим як знайомитись з керувальними структурами, спочатку необхідно ознайомитися з блоками. Блок або складена інструкція – це будь-яка кількість простих інструкцій, які оточені парою фігурних дужок. Блок визначає область видимості ваших змінних. Блоки можуть бути вкладені в середину інших блоків. Ви вже зустрічалися з блоками при створенні найпростіших програм у методі main(). Наступний приклад демонструє вкладення блоку у блок методу main:

public static void main(String[] args)
{
  int n;
  . . .
  {
    int k;
    . . .
  } // змінна k визначена лише до цього місця
}

Проте не можна визначати однакові змінні в двох вкладених блоках (на відміну від С++, де це можливо).

public static void main(String[] args)
{
  int n;
  . . .
    {
    int k;
    int n; // помилка! – не можна перевизначити n у внутрішньому блоці
    . . .
    }
}

Умовні інструкції [ред.]

Умовна інструкція в Java має форму:

if (умова) інструкція;

Умова повинна бути оточена дужками і, якщо, умова вірна (true) буде виконана інструкція за умовою, інакше вона не буде виконана, а буде виконана наступна інструкція після умовної інструкції.

Приклад:

        int a=5;
        if (a<100) System.out.println("Число менше ста");

Зазвичай, необхідно виконати не одну інструкцію, в такому разі інструкції розміщають у блоці:

if (умова){
   iнструкція 1;
   …..
   iнструкція n;
} 

В такому разі при істинності умови, виконуються усі інструкції у блоці, якщо умова невірна, то виконується наступна інструкція після закриваючої дужки блоку. Якщо ж необхідно здійснити певну дію в разі не виконання умови, то в такому разі застосовують умовну інструкцію наступного виду:

if (умова) інструкція1 else інструкція2
if (yourSales >= target)
{
   performance = "Satisfactory";
   bonus = 100 + 0.01 * (yourSales - target);
}
else
{
   performance = "Unsatisfactory";
   bonus = 0;
}

Інструкції if можуть іти одна за одною без використання else:

if (x <= 0) if (x == 0) sign = 0; else sign = -1;

Для того, щоб програма була більш читабельна бажано застосовувати фігурні дужки:

if (x <= 0) { if (x == 0) sign = 0; else sign = -1; }

Вони нічого не змінюють, але вираз стає більш зрозумілим. Інструкція чи блок інструкцій виконується лише в разі виконання усіх умов.

Щоправда дану інструкцію можна також переписати ускладнивши умову використавши булевий оператор і (&&):

If (x <= 0&&x==0) sign = 0; else sign=-1;

Можна також використовувати повторюваність інструкцій if….else.

if (yourSales >= 2 * target)
{
  performance = "Excellent";
  bonus = 1000;
}
else if (yourSales >= 1.5 * target)
{
   performance = "Fine";
   bonus = 500;
}
else if (yourSales >= target)
{
   performance = "Satisfactory";
   bonus = 100;
}
else
{
   System.out.println("You're fired");
}

Це дає можливість перевірити ряд умов, якщо попередні умови не виконуються.

Цикли [ред.]

Цикли – це послідовність інструкцій, які можуть повторно виконуватись певну кількість раз в залежності від заданої в програмі умови. Розрізняють цикли з передумовою, з післяумовою та з лічильником.

Цикл while [ред.]

Цикл while (перекладається як «доки») – це цикл з передумовою, тіло якого (тобто інструкція або блок інструкцій) виконується, якщо умова істинна. Якщо умова з самого початку хибна, то цикл не виконається жодного разу.

Загальний вигляд:

while (умова) інструкція;

Якщо немає фігурних дужок, то перша інструкція, яка йде після оголошення циклу, вважається тілом циклу. Всі інші інструкції знаходяться поза циклом. Якщо в циклі повинні виконуватись кілька інструкцій, то необхідно використати фігурні дужки. Вони також можуть використовуватись при одній інструкції заради кращого візуального розуміння коду.

while (умова){
інструкція 1;
….
інструкція N
}

В наступному прикладі демонструється мінігра із вгадуванням числа від 0 до 10, яка створена з використанням циклу while:

import java.util.*;
public class Tmp {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);    // створюємо сканер вводу, 
                                                //   для вводу даних з консолі
        Random generator = new Random(); //створюємо генератор випадкових чисел
        System.out.println("Спробуйте відгадати число від 0 до 10");
        int gn;  
        String notEnd="Y";
 
        while (notEnd.equals("Y")||notEnd.equals("y")){   //поки змінна notEnd рівна “Y” або “y”
 
            gn=generator.nextInt(10); //генерація випадкового числа від 0 до 10;
            System.out.print("Введіть число від 0 до 10: ");
            int number=in.nextInt();  //зчитуємо число з клавіатури
 
            if (gn==number) System.out.print("Вгадали!!!  Спробуєте ще раз? (Y/N)");
            else System.out.print("Не вгадали. Спробуєте ще раз? (Y/N)");
 
            notEnd = in.next();    //отримати відповідь
 
        }
    }
}

Результат виконання:

Спробуйте відгадати число від 0 до 10
Введіть число від 0 до 10: 6
Не вгадали. Спробуєте ще раз? (Y/N)y
Введіть число від 0 до 10: 7
Вгадали!!!  Спробуєте ще раз? (Y/N) n

Програма генерує випадкове число при кожному повторі циклу і пропонує вгадати його. Після вводу користувачем числа - виводить відповідне повідомлення вгадано чи ні. Після цього пропонується здійснити нову спробу. Якщо користувач вводить з клавіатури “Y" або “y”, то гра продовжується, якщо введе щось інше, то завершується.

Для генерації випадкових чисел використано клас Random, що містить методи для генерації випадкових чисел. Зокрема, у нашій програмі використано метод nextInt(), який дозволяє генерувати випадкові числа.

Для зчитування з клавіатури використано клас Scanner, який був доданий в java 5.0, для зручного вводу з клавіатури. Метод nextInt() – читає ціле число, next() – читає цілий рядок з клавіатури.

Для того, щоб переконатися, що користувач хоче продовжити гру використано метод equals() з класу String - Strint1.equals (String2), що перевіряє чи один рядок (String1) тексту рівний іншому (String2).

Цикл do/while [ред.]

Якщо необхідно, щоб умова виконувалася хоча б один раз можна скористатися циклом з післяумовою do/while:

do інструкція while (умова);

Зокрема, в програмі з вгадуванням чисел, більш логічніше було б застосувати саме даний цикл, оскільки необхідне хоча б одне виконання тіла циклу.

import java.util.*;
public class Tmp {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);    // створюємо Сканер, 
                                               //   для вводу даних з консолі
        Random generator = new Random(); //створюємо генератор випадкових чисел
        System.out.println("Спробуйте відгадати число від 0 до 10");
        int gn;  
        String notEnd="Y";
 
        do {
 
            gn=generator.nextInt(10); //генерація випадкового числа від 0 до 10;
            System.out.print("Введіть число від 0 до 10: ");
            int number=in.nextInt();
 
            if (gn==number) System.out.print("Вгадали!!!  Спробуєте ще раз? (Y/N)");
            else System.out.print("Не вгадали. Спробуєте ще раз? (Y/N)");
 
            notEnd = in.next();    
 
        } while(notEnd.equals("Y")||notEnd.equals("y"));
    }
}

Цикл з лічильником for [ред.]

Цикл for – доволі часто вживаний цикл. Він застосовується при необхідності виконати інструкції певну кількість раз з одночасним збільшенням або зменшенням певної змінної. Часто використовується для здійснення перебору певних масивів даних, зокрема, також для сортування масивів. Приклад використання:

for (int i=1; i<=10; i++){
        System.out.println (i); 
}

Наведений вище приклад виведе на консолі в стовпчик числа від 1 до 10. Як бачимо в умові циклу перший слот відводиться для ініціалізації змінної, причому оголосити змінну можна і в іншому місці. Другий слот – для умови, яка перевіряється перед виконанням ітерації, третій слот – вказує як модифікувати змінну-лічильник. Тобто в наведеному прикладі при кожному виконанні ітерації, лічильник "і" буде збільшуватися на одиницю поки не стане рівним десяти.

Найчастіше даний цикл використовується для перебору елементів масиву. Масив – це впорядкований набір даних одного типу. Найпростіший масив можна оголосити та ініціалізувати таким чином: int a[]={1,5,6,1,3};. Для того, щоб звернутися до певного елементу масиву використовуються квадратні дужки з відповідним індексом елементу. Наприклад а[3] – звернення до четвертого елементу масиву (номери елементів відраховуються з нуля). В наступному прикладі створюється масив і послідовно виводяться його елементи:

public class MyArray {
 public static void main(String[] args)
 {
    int a[]={1,5,6,1,3}; // створюємо масив і заповнюємо його числами
   // int j;
    int size=5;
    System.out.println ("Елементи масиву:");
    for (int j=0;j<5;j++){
        System.out.println("а["+j+"]="+a[j]);
    }
 }
}

Результат виконання:

Елементи масиву:
а[0]=1
а[1]=5
а[2]=6
а[3]=1
а[4]=3

Цикл «for each» [ред.]

Починаючи з java SE 5.0 в мові з’явився новий цикл, призначення якого є перебір елементів масиву або подібних до масиву типів даних (колекції).

Наприклад, вивести елементи масиву, можна таким чином:

for (int element : a)
    System.out.println(element);

Використання даного циклу, дозволяє уникнути проблем пов’язаних з помилками при заданні умови в класичному циклі for. В інших мовах програмування цикл такого виду так і називається foreach, проте, щоб уникнути необхідності значних змін в пакетах, в java пішли простішим шляхом і перевантажили цикл for.

Інструкції, що порушують порядок виконання [ред.]

В java відсутня інструкція goto, яка дозволяла переходити в будь-яке місце в програмі. Її використання давно вважається поганим стилем програмування, оскільки робить текст програми заплутаним. Про це, зокрема, писав ще Дональд Кнут і він же зазначав, що інколи все таки корисно її застосовувати, щоб припинити виконання певного методу, циклу чи блоку і вийти за їхні межі. Для цієї мети в java існують спеціальні інструкції. Зокрема, інструкцію break можна використати для передчасного виходу з циклу.

while (years <= 100)
{
 balance += payment;
 double interest = balance * interestRate / 100;
 balance += interest;
 if (balance >= goal) break;
   years++;
}

Таким чином додано дві умови для виходу з циклу. Хоча даний фрагмент можна також переписати наступним чином:

while (years <= 100 && balance < goal)
{
 balance += payment;
 double interest = balance * interestRate / 100;
 balance += interest;
 if (balance < goal)
   years++;
}

Якщо ми використовуємо вкладені цикли (один цикл в іншому), то інструкція break припинить цикл, в якому вона знаходиться. Якщо вона знаходиться у внутрішньому циклі, то він припинить своє виконання, а зовнішній же цикл буде виконуватись і дальше. Якщо потрібно повністю припинити виконання і внутрішнього і зовнішнього, то використовується інструкція break з міткою.

Scanner in = new Scanner(System.in);
int n;
read_data:
while (. . .) // this loop statement is tagged with the label
{
   . . .
   for (. . .) // this inner loop is not labeled
  {
    System.out.print("Enter a number >= 0: ");
    n = in.nextInt();
   if (n < 0) // should never happen—can't go on
   break read_data;
   // break out of read_data loop
   . . .
   }
}
// наступна інструкція буде виконана зразу ж після інструкції break з міткою
if (n < 0) // check for bad situation
{
// deal with bad situation
}
else
{
// carry out normal processing
}

Після використання break з міткою, часто виникає необхідність перевірити чому саме цикл припинив виконання, що і робиться в кінці наведеного вище фрагменті коду програми.

Якщо ж нам потрібно виходити з циклу, а лише припинити певну його ітерацію, то для цієї використовується інструкція continue, яка переносить порядок виконання до заголовку інструкції.

Scanner in = new Scanner(System.in);
while (sum < goal)
{
 System.out.print("Enter a number: ");
 n = in.nextInt();
 if (n < 0) continue;
     sum += n; // not executed if n < 0
}

Щоправда завжди можна обійтися без даних інструкцій змінивши логіку програми. Деякі з програмістів уникають використовувати інструкції break та continue.

Множинний вибір [ред.]

Інструкція if/else може бути доволі громіздкою, якщо необхідно здійснити множинний вибір з багатьох альтернатив. Тож як і в С/C++ в java існує інструкція switch, яка здійснити вибір з багатьох варіантів. Щоправда вона дещо незграбна і деякі програмісти вважають за краще уникати її використання.

Наприклад, якщо Ви організовуєте певне меню і пропонуєте користувачу вибрати, номер конкретного пункту, то можна використати наступний код:

Scanner in = new Scanner(System.in);
System.out.print("Select an option (1, 2, 3, 4) ");
int choice = in.nextInt();
switch (choice)
{
case 1:
. . .
break;
case 2:
. . .
break;
case 3:
. . .
break;
case 4:
. . .
break;
default:
// bad input
. . .
break;
}

Якщо пропустити інструкцію break, то всі інші інструкції будуть також виконані. Тобто якщо справдиться умова першого варіанту, то будуть здійснені ще й дії вказані для виконання у всіх інших варіантах.

Крім того case мітка повинна бути цілим числом або нумерованою константою. Ми не можемо перевіряти на рівність рядки таким чином. Так наступний код буде помилковим:

String input = . . .;
switch (input)          // ПОМИЛКА
{
case "A":                //ПОМИЛКА
. . .
break;
. . .
}

Вступ в класи та методи · Масиви