Поток управления

From AsIsWiki
Revision as of 10:04, 4 April 2015 by Alex (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
Форум

Назад | Оглавление | Дальше


Contents

Блоки

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

public static void main(String[] args) {
    int n;
    ...
    {
        int k;  // переменная k определена только в этом блоке
    }
}

В Java нельзя объявлять переменные с одним именем в двух вложенных блоках:

public static void main(String[] args) {
    int n;
    ...
    { 
        int k;
        int n;  // Error! - невозможно переопределить
                // переменную n во внутреннем блоке
    }
}


Условные выражения

Условный оператор в Java имеет следующий вид:

if (условие) {
    оператор
}

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

if (yourSale >= target) {
    performance = "Удовлетворительно";
    bonus = 100;
}

Блок позволяет включать несколько операторов в любую структуру языка Java.

Условие может иметь следующий вид:

if (условие) {
    оператор_1
} else {
    оператор_2
}

Например:

if (yourSales >= target) {
    performance = "Удовлетворительно";
    bonus = 100 + 0.01 * (yourSales - target);
} else {
    performance = "Неудовлетворительно";
    bonus = 0;
}

Часть else не является обязательной. Она объединяется с ближайшим оператором if. В следующем примере, оператор else соответствует второму оператору if:

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

Иногда встречаются структуры типа if ... else if ... :

if (yourSales >= 2 * target) {
    performance = "Великолепно";
    bonus = 1000;
} else { 
    if (yourSales >= 1.5 * target) {
        performance = "Хорошо";
        bonus = 500;
    } else {
        if (yourSales >= target) {
            performance = "Удовлетворительно";
            bonus = 100;
        } else {
            System.out.println("Вы уволены.");
        }
    }
}


Неопределенные циклы

Цикл while выполняет группу операторов пока условие равно true:

while (условие) {
    оператор
}

Тело цикла не будет выполнено ни разу, если его условие изначально равно false.

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

import java.util.*;

public class Retirement {

    public static void main(String[] args) {

        // Чтение входных данных
        Scanner in = new Scanner(System.in);

        System.out.print("Какая сумма вам необходима: ");
        double goal = in.nextDouble();

        System.out.print("Сколько вы можете вносить в год: ");
        double payment = in.nextDouble();

        System.out.print("Процентная ставка: ");
        double interestRate = in.nextDouble();

        double balance = 0;
        int years = 0;

        // Баланс обновляется до тех пор,
        // пока не будет достигнута требуемая сумма
        while (balance < goal) {
            // Добавление ежегодного взноса и процентов
            balance += payment;
            double interest = balance * interestRate / 100;
            balance += interest;
            years++;
        }

        System.out.println("Вы можете уйти на отдых через " + years + " лет.");
    }
}

Условие цикла while проверяется в самом начале. Т.е. возможна ситуация, при которой тело цикла не будет выполнено никогда. Чтобы тело выполнилось хотя бы раз, проверку условия нужно перенести в конец. Это можно выполнить с помощью цикла do/while:

import java.util.*;

public class Retirement2 {

    public static void main(String[] args) {

        // Чтение входных данных
        Scanner in = new Scanner(System.in);

        System.out.print("Сколько вы можете вносить в год: ");
        double payment = in.nextDouble();

        System.out.print("Процентная ставка: ");
        double interestRate = in.nextDouble();

        double balance = 0;
        int years = 0;
        String input;

        // Обновлять баланс, пока пользователь вводит N
        do {
            // Добавление ежегодного взноса и процентов
            balance += payment;
            double interest = balance * interestRate / 100;
            balance += interest;
            years++;

            // Вывод текущего баланса
            System.out.printf("Через %d, у вас будет %,.2f%n", year, balance);

            // Запрос, готов ли пользователь прекратить работу
            System.out.print("Уходите на отдых? (Y/N) ");
            input = in.next();

        } while (input.equals("N"));
    }
}


Определенные циклы

В цикле for число повторений контролируется переменной, выполняющей роль счетчика и обновляемой на каждой итерации. Следующий пример выводит на экран числа от 1 до 10:

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

Первый элемент оператора for выполняет инициализацию счетчика, второй формулирует условие выполнения тела цикла, а третий определяет способ обновления счетчика.

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

Цикл с убывающим счетчиком:

for (int i = 10; i > 0; --i) {
    System.out.println("Обратный отсчет ... " + i);
}
System.out.println("Старт!");

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

for (double x = 0; x != 10; x += 0.1) {
    ...
}

В этом цикле переменная x изменит свое значение с 9.999999999999998 на 10.099999999999998 (т.к. для числа 0.1 не существует двоичного представления).

Область видимости переменных, объявленных в операторе for, простирается до конца цикла:

for (int i = 1; i <= 10; i++) {
    ...
}
// Здесь переменная i больше не определена

Если значение счетчика необходимо использовать вне цикла, то эту переменную надо объявлять до начала цикла:

int i;

for (i = 1; i <= 10; i++) {
    ...
}
// Здесь переменная i по-прежнему доступна

Ниже показана взаимозаменяемость циклов for и while:

for (int i = 10; i > 0; i--) {
    System.out.println("Обратный отсчет ... " + i);
}

int i = 10;

while (i > 0) {
    System.out.println("Обратный отсчет ... " + i);
    i--;
}

Следующая программа вычисляет вероятность выигрыша в лотерее. Например, если нужно угадать 6 номеров из 50, то количество возможных вариантов равно:

50 * 49 * 48 * 47 * 46 * 45
---------------------------
   1 * 2 * 3 * 4 * 5 * 6

шанс выиграть равен 1 из 15890700

В общем случае, если нужно угадать k номеров из n, количество возможных вариантов равно следующему выражению:

n * (n - 1) * (n - 2) * ... * (n - k + 1)
-----------------------------------------
                   k!

Выражение вычисляется с помощью цикла for:

int lotteryOdds = 1;

for (int i = 1; i <= k; i++) {
    lotteryOdds = lotteryOdds * (n - i + 1) / i;
}

Программа расчета вероятности выигрыша в лотерее:

import java.util.*;

public class LotteryOdds {

    public static void main(String[] args) {
        
        Scanner in = new Scanner(System.in);

        System.out.print("Сколько номеров? ");
        int k = in.nextInt();

        System.out.print("Наибольший номер? ");
        int n = in.nextInt();

        /*
         * Вычисление выражения
         * n * (n - 1) * (n - 2) * ... * (n - k + 1)
         * -----------------------------------------
         *            1 * 2 * 3 * ... * k
         */

        int lotteryOdds = 1;

        for (int i = 1; i <= k; i++) {
            lotteryOdds = lotteryOdds * (n - i + 1) / i;
        }

        System.out.println("Ваши шансы 1 из " + lotteryOdds);
    }
}


Многовариантное ветвление - оператор switch

Оператор 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:
        // неверный выбор
        ...
        break;
}

Выполнение начинается с метки case = choice, и продолжается до ближайшего оператора break или до конца оператора switch. Если ни одна метка не совпадает со значением переменной, выполняется раздел default (если он предусмотрен).

Метка case должна быть целочисленной, строки и вещественные числа проверять нельзя:

String input = ... ;

switch (input) {  // ошибка
    case "A":     // ошибка
        ...
        break;
    ...
}


Прерывание потока управления

Donald Knuth в своей статье "Structured Programming with goto statements" пишет о вреде использования оператора goto. Но, в некоторых случаях требуется преждевременный выход из цикла. Для поддержки такого стиля программирования в java введен оператор break с меткой. Например, для выхода из цикла можно использовать break без метки:

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

Выход из цикла произойдет, если (years <= 100) или (balance >= goal).

То же самое можно выполнить без break:

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

Проверка условия (balance < goal) в данном варианте программы проверяется дважды.

Оператор break с меткой обеспечивает выход из вложенных циклов:

Scanner in = new Scanner(System.in);
int n;

read_data:
while ( ... ) {  // этот цикл помечен
    ...
    for ( ... ) {  // этот цикл не помечен
        System.out.print("Введите число >= 0: ");
        n = in.nextInt();
        if (n < 0) {
            break read_data;  // прерывание помеченного цикла
        }
        ...
    }
}

// Это условие выполняется сразу после break read_data;
if (n < 0) {  // проверка на наличие недопустимой ситуации
    // обработка недопустимой ситуации
} else {
    // действия в результате нормального выполнения операции
}

Оператор break с меткой выполняет переход в конец помеченного блока.

Метку можно связать с любым оператором или блоком, например:

label:
{
    ...
    if (условие) break label;  // выход из блока
}
// при выполнении оператора break управление передается в эту точку

Оператор continue передает управление в начало текущего цикла:

while (sum < goal) {
    String input = JOptionPane.showInputDialog("Введите число: ");
    n = integer.ParseInt(input);
    if (n < 0) {
        continue;  // переход в начало цикла
    }
    sum += n;
}

Если оператор continue используется в цикле for, то он передает управление в начало цикла и увеличивает счетчик:

for (count = 0; count < 100; count++) {
    String input = JOptionPane.showInputDialog("Ввод числа: ");
    n = Integer.parseInt(input);
    if (n < 0) {
        continue;  // переход в начало цикла, инкремент счетчика
    }
    sum += n;
}

Оператор continue с меткой, передает управление заголовку цикла, помеченного этой меткой.

Любые действия, выполняемые с операторами break и continue, можно запрограммировать без их использования.



Форум

Назад | Оглавление | Дальше

Personal tools
Namespaces

Variants
Actions
Navigation
Tools