Кен Арнольд Джеймс Гослинг

Вид материалаДокументы

Содержание


6.3. Оператор switch
Normal = 1
6.4. Цикл while и do-while
6.5. Оператор for
Подобный материал:
1   ...   32   33   34   35   36   37   38   39   ...   81

6.3. Оператор switch


Оператор switch вычисляет целочисленное выражение и в соответствии с полученным результатом ищет метку case в блоке. Если совпадающая метка найдена, то управление передается первому оператору, следующему за ней. Если метка не обнаружена, то следующим будет выполняться оператор, находящийся за меткой default. Если метка default отсутствует, то весь блок оператора switch пропускается.

Приведенный ниже пример выводит информацию о состоянии объекта. При этом уровень детализации выбирается пользователем. Затем производится вывод более скупых данных:

public static final int TERSE = 0,

NORMAL = 1,

BLATHERING = 2;


// ...


public int Verbosity = TERSE;


public void dumpState()

throws UnexpectedStateException

{

switch (Verbosity) {

case BLATHERING:

System.out.println(stateDetails);

System.out.println(stateDetails);

// ПРОХОД


case NORMAL:

System.out.println(basicState);

// ПРОХОД

case TERSE:

System.out.println(summaryState);

break;


default:

throw new UnexpectedStateException(Verbosity);

}

}

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

Комментарий ПРОХОД означает, что программа проходит через соответствующую метку, а выполнение продолжается со следующего за ней оператора. Следовательно, если уровень детализации равен BLATHERING, то печатаются все три составные части отчета; если он равен NORMAL, то печатаются две части; наконец, если уровень детализации равен TERSE, то печатается только одна часть.

Метка case или default не приводит к прерыванию работы оператора switch и не нарушает хода выполнения программы. Именно по этой причине мы вставили оператор break после завершения вывода для уровня TERSE. Без break выполнение программы было бы продолжено операторами, следующими за меткой default, что каждый раз приводило бы к возбуждению исключения.

Проход к следующему условию case может оказаться полезным при некоторых обстоятельствах, однако в большинстве случаев в конце фрагмента, соответствующего метке case, должен находиться оператор break. Хороший стиль программирования требует, чтобы намеренный проход к следующей метке case сопровождался каким-нибудь комментарием наподобие того, что приведен в примере.

Проход чаще всего применяется для использования нескольких меток case с одним фрагментом программы. В следующем примере он используется для перевода шестнадцатеричной записи цифры в значение типа int:

public int hexValue(char ch) throws NonDigitException {

switch (ch) {

case '0': case '1': case '2': case '3': case '4':

case '5': case '6': case '7': case '8': case '9':

return (ch - '0');


case 'a': case 'b': case 'c':

case 'd': case 'e': case 'f':

return (ch - 'a') + 10;


case 'A': case 'B': case 'C':

case 'D': case 'E': case 'F':

return (ch - 'A') + 10;


default:

throw new NonDigitException(ch);

}

}

Операторы break в данном случае не нужны, потому что операторы return осуществляют выход из метода и не позволяют пройти к следующему оператору.

Последнюю группу операторов внутри switch следует завершать оператором break, return или throw, как это делалось для всех предыдущих условий. Это уменьшает вероятность того, что при добавлении в будущем нового условия case произойдет случайный проход к нему из того фрагмента, который когда-то завершал оператор switch.

Все метки case должны быть постоянными выражениями, то есть содержать только литералы и поля static final, инициализированные константами. В каждом отдельном операторе switch значения меток case должны быть различными. Допускается присутствие не более одной метки default.

Упражнение 6.2

Перепишите метод из упражнения 6.1 с использованием оператора switch.

6.4. Цикл while и do-while


Цикл while выглядит следующим образом:

while (логическое выражение)

оператор

В начале работы оператора вычисляется логическое выражение, и если оно равно true, то выполняется оператор (который, разумеется, может представлять собой блок); это происходит до тех пор, пока логическое выражение не станет равным false.

Цикл while выполняется ноль или более раз, поскольку логическое выражение может оказаться равным false при его первом вычислении.

Иногда бывает нужно, чтобы тело цикла заведомо было выполнено хотя бы один раз, и поэтому в языке Java также предусмотрена конструкция do-while:

do-while:

do

оператор

while (логическое выражение);

Здесь логическое выражение вычисляется после оператора. Цикл выполняется, пока выражение остается равным true. Оператор, являющийся телом цикла do-while, почти всегда представляет собой блок.

6.5. Оператор for


Оператор for используется для выполнения цикла по значениям из определенного диапазона. Он выглядит следующим образом:

for (инициализация; логическое выражение; приращение)

оператор

Такая запись эквивалентна

{

инициализация;

while (логическое выражение) {

оператор

приращение;

}

}

за тем исключением, что приращение всегда выполняется, если в теле цикла встречается оператор continue (см. раздел “Оператор continue”).

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

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

for ( i = 0, j = arr.length - 1; j >>= 0; i++, j--) {

// ...

}

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

Приведем пример цикла, который вычисляет наименьший показатель (exp), такой, что 10 в степени exp превосходит заданную величину:

public static int tenPower(int value) {

int exp, v;

for (exp = 0, v = value - 1; v >> 0; exp++, v /= 10)

continue;

return exp;

}

В данном случае в цикле одновременно изменяются две переменные: показатель степени (exp) и значение 10exp (v). Эти переменные являются взаимосвязанными. В подобных случаях разделенный запятыми список является корректным способом обеспечения синхронизации значений.

Тело цикла представляет собой простой оператор continue, начинающий следующую итерацию цикла. В теле цикла вам ничего не приходится делать — все происходит в проверяемом условии и в выражении-итерации. Использованный в данном примере оператор continue — одна из возможностей создать пустое тело цикла; вместо него можно было оставить отдельную строку, состоящую из одной точкой с запятой, или создать пустой блок в фигурных скобках. Просто ограничиться точкой с запятой в конце строки с оператором for было бы довольно опасно — если точка с запятой будет случайно удалена, то оператор, следующий за for, превратится в тело цикла.

Все выражения в заголовке цикла for являются необязательными. Если пропустить инициализацию или приращение, то соответствующая часть цикла просто не выполняется. Отсутствующее логическое выражение считается всегда равным true. Следовательно, для создания бесконечного цикла можно воспользоваться следующей записью:

for (;;)

оператор

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

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

Упражнение 6.3

Напишите метод, который получает два параметра типа char и выводит все символы, лежащие в диапазоне между ними (включая их самих).