Главная страница

Java. Полное руководство. 8-е издание. С. Н. Тригуб Перевод с английского и редакция


Скачать 25.04 Mb.
НазваниеС. Н. Тригуб Перевод с английского и редакция
АнкорJava. Полное руководство. 8-е издание.pdf
Дата28.02.2017
Размер25.04 Mb.
Формат файлаpdf
Имя файлаJava. Полное руководство. 8-е издание.pdf
ТипДокументы
#3236
страница10 из 90
1   ...   6   7   8   9   10   11   12   13   ...   90
System.out.println("Эта строка отображаться не будет");
Тело цикла while или любого другого цикла Java) может быть пустым. Это обусловлено тем, что синтаксис Java допускает применение пустого оператора (содержащего только символ точка с запятой. Например, рассмотрим следующую программу Целевая часть цикла может быть пустой
class NoBody {
public static void main(String a r g s []) {
int i ,
j ;
i = 100;

1 2 Часть I. Язык Java
j = 200;
// вычисление среднего значения i ив этом цикле тело цикла отсутствует
System.out.println("Среднее значение равно " + Эта программа вычисляет среднее значение переменных i и j . Она создает следующий вывод.
Среднее значение равно 15 Этот цикл w h i l e работает следующим образом. Значение переменной i увеличивается, а значение переменной j уменьшается на единицу. Затем программа сравнивает эти два значения. Если новое значение переменной i по-прежнему меньше нового значения переменной j , цикл повторяется. Если значение переменной i равно значению переменной j или больше его, выполнение цикла прекращается. По выходу из цикла переменная i будет содержать среднее значение исходных значений переменных i и j . (Конечно, эта процедура работает только в том случае, если в самом начале значение переменной i меньше значения переменной j.) Как видите, никакой потребности в наличии тела цикла не существует. Все действия выполняются внутри самого условного выражения. В профессионально написанном коде Java короткие циклы часто не содержат тела, если само по себе управляющее выражение может выполнять все необходимые действия.
Ц и кл Как вы видели, если в начальный момент условное выражение, управляющее циклом w h ile , ложно, тело цикла вообще не будет выполняться. Однако иногда желательно выполнить тело цикла хотя бы один раз, даже если в начальный момент условное выражение ложно. Иначе говоря, существуют ситуации, когда проверку условия прерывания цикла желательно выполнять в конце цикла, а не в его начале. К счастью, Java поддерживает именно такой цикл d o - w h ile . Этот цикл всегда выполняет тело цикла хотя бы один раз, поскольку его условное выражение проверяется в конце цикла. Общая форма цикла d o - w h i le следующая {
// тело цикла while (условие При каждом повторении цикла d o - w h i le программа вначале выполняет тело цикла, а затем вычисляет условное выражение. Если это выражение истинно, цикл повторяется. В противном случае выполнение цикла прерывается. Как и во всех циклах Java, условие должно быть булевым.
Ниже приведена измененная программа вывода тактов, которая демонстрирует использование цикла d o - w h ile . Она создает такой же вывод, что и предыдущая версия Демонстрация использования цикла do-while.

class DoWhile {
public static void main(String a r g s []) {
int n = 10;
do такт " + n) ;
n - - ;
Глава 5. Управляющие операторы
1 2 7
} w h i l e (n > Хотя с технической точки зрения в приведенной программе цикл записан правильно, его можно переписать в более эффективном виде {
S y s t e m .out.p r i n t l n (такт " + n ) ;
} w h i l e (--n > В этом примере декремент переменной пи сравнение результирующего значения с нулем объединены водном выражении ( - - п > 0 ). Программа работает следующим образом. Вначале она выполняет оператор - - п , уменьшая значение переменной п на единицу и возвращая новое значение переменной п. Затем программа сравнивает это значение с нулем. Если оно больше нуля, выполнение цикла продолжается. В противном случае цикл прерывается.
Цикл d o - w h i le особенно удобен при выборе пункта меню, поскольку обычно в этом случае требуется, чтобы тело цикла меню выполнялось, по меньшей мере, один раз. Рассмотрим следующую программу, которая реализует очень простую систему справки по операторам выбора и цикла Java.
// Использование цикла do-while для выбора пункта меню
class Menu {
public static voi d m a i n( S tr i ng a r g s [])
throws j a v a .i o .IOExcept ion {
char choice;
do Справка n o :");
S y s t e m .out.pr i n t l
n("
1 .
i f " ) ;
S y s t e m .out.pr i n t l
n("
2 .
s w i t c h " ) ;
S y s t e m .out.pr i n t l
n("
3. w h i l e " ) ;
S y s t e m .out.p r in tl
n("
4. d o - w h i l e " ) ;
S y s t e m .out.pr i n t l
n("
5. f o r \ n " ) ;
S y s t e m .out.p r i n t Выберите интересующий пункт = (char) S y s t e m . i n .r e a d ();
} w h i l e ( choice < '1' || choice > '5') ;
System.out.println("\n");
switch(choice) {
case '1':
System
.out.p
rintln("i f :\n");
System
.out.
println("i f (условие) оператор оператор
break;
case 'выражение {");
System
.out.
println(" case константа" последовательность операторов" break;");
System
.out.
println(" // ...");
System
.out.p
rintln ( " }");
break;
case '3 ':
System
.out.p
rintln("w h i l e :\n");
System
.out.p
rintln("w h i l e (условие) оператор

1 2 Часть I. Язык Java
case '4':
System.out.println("do-while:\n");
System.out.println("do {");
System.out.println(" оператор u t .p r i ntIn("} while (условие
break;
case '5':
System.out.println("for:\n");
System.out.print("f o r (инициализация условие повторение r i ntln(" оператор;");
break;
}
}
}
Пример вывода этой программы выглядит следующим образом.
Справка по Выберите интересующий пункт оператор while (условие);

В этой программе в цикле d o - w h i le осуществляется проверка допустимости введенного пользователем значения. Если это значение недопустимо, программа предлагает пользователю повторить ввод. Поскольку меню должно отобразиться, по меньшей мере, один раз, цикл d o - w h i le является прекрасным средством решения этой задачи.
Отметим еще несколько особенностей приведенного примера. Обратите внимание на то, что для считывания символов с клавиатуры используется метод S y s te m . i n . r e a d (). Это — одна из функций консольного ввода Java. Подробно методы консольного ввода-вывода рассмотрим в главе 13, а пока отметим, что в данном случае метод S y s te m . i n . r e a d () используется для выяснения сделанного пользователем выбора. Этот метод считывает символы из стандартного устройства ввода (возвращаемые в виде целочисленных значений — именно потому тип возвращаемого значения был приведен к типу c h a r). По умолчанию данные из стандартного ввода помещаются в буфер построчно, поэтому, чтобы любые введенные символы были пересланы программе, необходимо нажать клавишу Консольный ввод Java может вызывать некоторые затруднения при работе. Более того, большинство реальных программ Java будут графическими и ориентированными на работу в оконном режиме. Поэтому в данной книге консольному вводу уделяется не очень много внимания. Однако в данном случае он удобен. Еще один важный момент. Поскольку мы используем метод
S y s t e m . i n . r e a d () , программа должна содержать выражение n . Эта строка необходима для обработки ошибок ввода. Она является составной частью системы обработки исключений, которая будет рассмотрена в главе 10.
Глава 5. Управляющие операторы
1 2 Цикл Простая форма цикла f o r была представлена в главе 2. Вскоре читатели убедятся в больших возможностях и гибкости этой конструкции.
Начиная с версии JDK 5 в Java существует две формы цикла f o r . Первая — традиционная форма, используемая начиная с исходной версии Java. Вторая — новая форма “for-each”. Мы рассмотрим оба типа цикла f o r , начиная с традиционной формы.
Общая форма традиционного оператора цикла f o r выглядит следующим образом о г (инициализация условие повторение тело

}
Если в цикле будет повторяться только один оператор, фигурные скобки можно опустить.
Цикл f o r действует следующим образом. При первом запуске цикла программа выполняет инициализационную часть цикла. В общем случае это выражение, устанавливающее значение управляющей переменной цикла, которая действует в качестве счетчика, управляющего циклом. Важно понимать, что выражение инициализации выполняется только один раз. Затем программа вычисляет условие, которое должно быть булевым выражением. Как правило, выражение сравнивает значение управляющей переменной с целевым значением. Если это значение истинно, программа выполняет тело цикла. Если оно ложно, выполнение цикла прерывается. Затем программа выполняет часть повторение цикла. Обычно это выражение, которое увеличивает или уменьшает значение управляющей переменной. Затем программа повторяет цикл, при каждом прохождении вначале вычисляя условное выражение, затем выполняя тело цикла и выражение повторения. Процесс повторяется до тех пор, пока значение выражения повторения не станет ложным.
Ниже приведена версия программы подсчета тактов, в которой использован цикл f o r .
// Демонстрация использования цикла for.
class ForTick {
public static void main(String a r g s []) {
int n;
for(n=10; n>0; такт " + n ) Объявление управляющих переменных цикла внутри цикла f o Часто переменная, которая управляет циклом f o r , требуется только для него и не используется нигде больше. В этом случае переменную можно объявить внутри инициализационной части оператора f o r . Например, предыдущую программу можно переписать, объявляя управляющую переменную п типа i n t внутри цикла f o r .
// Объявление управляющей переменной цикла внутри цикла for.
class ForTick {
public static void main(String a r g s []) {
// в данном случае переменная п объявляется внутри цикла for
for(int n=10; n>0; такт " + n ) ;
}
}
5

1 3 Часть I. Язык При объявлении переменной внутри цикла f o r необходимо помнить о следующем область и продолжительность существования этой переменной полностью совпадают с областью и продолжительностью существования оператора f o r . (То есть область существования переменной ограничена циклом f o r .) Вне цикла f o r переменная прекратит свое существование. Если управляющую переменную цикла нужно использовать в других частях программы, ее нельзя объявлять внутри цикла f o r В тех случаях, когда управляющая переменная цикла не требуется нигде больше, большинство программистов Java предпочитают объявлять ее внутри оператора f o r . В качестве примера приведем простую программу, которая проверяет, является ли введенное число простым. Обратите внимание на то, что управляющая переменная цикла i объявлена внутри цикла f o r , поскольку она нигде больше не требуется Проверка принадлежности к простым числам
class FindPrime {
public static void main(String a r g s []) {
int num;
boolean isPrime;
num = 14;
if(num < 2) isPrime = false;
else isPrime = true;
for(int i=2; i <= num/i; i++) {
i f ((num % i )
== 0) {
isPrime = false;
break;
}
}
i f (isPrime) Простое
else System.out.println("He простое");
}
}
Использование запятой
В ряде случаев требуется указание нескольких операторов в инициализацион- ной и итерационной частях цикла f o r . Например, рассмотрим цикл в следующей программе Sample {

public static void main(String a r g s []) {
int a, b;
b = 4;
for(a=l; a
+ )
{
System.out.println("a = " + a) ;
System.out.println("b = " + b ) Как видите, управление этим циклом осуществляется одновременно двумя переменными. Поскольку цикл управляется двумя переменными, желательно, чтобы их обе можно было бы включить в сам оператора не выполнять обработку
Глава 5. Управляющие операторы
1 3 переменной b вручную. К счастью, язык Java предоставляет средства для выполнения этой задачи. Чтобы две или более переменных могли управлять циклом f o r ,
Java позволяет указывать по нескольку операторов как в инициализационной, таки итерационной частях оператора f o r . Один от другого операторы отделяются запятыми.
Используя запятые, предыдущий цикл f o r можно записать в более эффективном виде Использование запятой
class Comma {
public static void main(String a r g s []) {
int a, b;
for(a=l, b = 4 ; a
System.out.println("a = " + a) ;
System.out.println("b = " + b ) В этом примере в инициализационной части цикла мы устанавливаем начальные значения обеих управляющих переменных аи Ь. Оба разделенных запятой оператора в итерационной части выполняются при каждом повторении цикла. Программа создает следующий вывода = 1 b = 4 а = 2 b = На заметку Читатели, знакомые с языками C/C++, знают, что в этих языках запятая — оператор, который можно использовать в любом допустимом выражении. Однако в Java это не так. Здесь запятая служит разделителем.
Разновидности цикла Цикл f o r имеет несколько разновидностей, которые увеличивают его возможности и повышают применимость. Гибкость этого цикла обусловлена тем, что его три части — инициализационную, проверку условий и итерационную — необязательно использовать только по прямому назначению. Фактически каждый раздел оператора f o r можно применять в любых целях. Рассмотрим несколько примеров.
Одна из наиболее часто встречающихся вариаций предполагает использование условного выражения. В частности, это выражение необязательно должно выполнять сравнение управляющей переменной цикла с каким-либо целевым значением. Фактически условием, управляющим циклом f o r , может быть любое булево выражение. Например, рассмотрим следующий фрагмент done = false;

for(int i=l; Idone; i++) {
/ / . .
i f (interrupted()) done = В этом примере выполнение цикла f o r продолжается до тех пор, пока значение переменной d o ne не будет установлено равным t r u e . В этом цикле проверка значения управляющей переменной цикла i не выполняется

1 3 2 Часть I. Язык Ниже приведена еще одна интересная разновидность цикла f o r .
Инициализационное или итерационное выражения либо оба могут отсутствовать, как показано в следующей программе Части цикла for могут быть пустыми
class ForVar {
public static void main(String a r g s []) {
int i ;
boolean done = false;
i - 0 ;
for( ;
Idone; )
{
S ystem .out.p r i n t l n ("i равно "

+ i ) ; i f ( i ==
1 0
) done = tru e ; i + +В этом примере инициализационное и итерационное выражения вынесены за пределы цикла f o r . В результате соответствующие части оператора f o r пусты. Хотя в этом простом примере — действительно, его можно считать достаточно примитивным — это и не имеет никакого значения, в отдельных случаях такой подход имеет смысл. Например, если начальное условие определяется сложным выражением где-то в другом месте программы или значение управляющей переменной цикла изменяется случайным образом в зависимости от действий, выполняемых внутри тела цикла, вполне целесообразно оставить эти части цикла f o r пустыми.
Приведем еще одну разновидность цикла f o r . Оставляя все три части оператора пустыми, можно умышленно создать бесконечный цикл (цикл, который никогда не завершается o r ( ; ; ) {
/ / . . Этот цикл может выполняться бесконечно, поскольку условие, по которому он был бы прерван, отсутствует. Хотя некоторые программы, такие как командные процессоры операционной системы, требуют наличия бесконечного цикла, большинство бесконечных циклов в действительности представляет собой всего лишь циклы с особыми условиями прерывания. Как вы вскоре убедитесь, существует способ прерывания цикла (даже бесконечного, подобного приведенному примеру, который не требует использования обычного условного выражения цикла.
Версия “for-each” цикла fo Начиная с версии JDK 5 в Java можно использовать вторую форму циклам o r , реализующую цикл в стиле “for-each” (для каждого. Как вам, возможно, известно, в современной теории языков программирования все большее применение находит концепция циклов “for-each”, которые быстро становятся стандартными функциональными возможностями во многих языках. Цикл в стиле “for-each” предназначен для строго последовательного выполнения повторяющихся действий по отношению к коллекции объектов, такой как массив. В отличие от некоторых языков, подобных Св котором для реализации циклов “for-each” используют ключевое слово f o r e a c h , в Java возможность применения цикла “for-each” реализована за счет усовершенствования цикла f o r . Преимущество этого подхода состоит в том, что для его реализации не требуется дополнительное ключевое слово и никакой ранее существовавший код не разрушается. Цикл f o r в стиле “for-each”
Глава 5. Управляющие операторы 3 называют также усовершенствованным циклом f o r . Общая форма версии “for-each” цикла f o r имеет следующий вид
( тип и тер_пер
коллекция) л ок_операторов
Здесь тип указывает типа ит ер_пер — имя итерационной переменной, которая последовательно будет принимать значения из коллекции, от первого до последнего. Элемент коллекция указывает коллекцию, по которой должен выполняться цикл. С циклом f o r можно применять различные типы коллекций, нов этой главе мы будем использовать только массивы. (Другие типы коллекций, которые можно применять с циклом f o r , вроде определенных в инфраструктуре коллекций
Collection Framework, рассматриваются в последующих главах книги) На каждой итерации цикла программа извлекает следующий элемент коллекции и сохраняет его в переменной ит ер_пер. Цикл выполняется до тех пор, пока не будут получены все элементы коллекции.
Поскольку итерационная переменная получает значения из коллекции, тип должен совпадать (или быть совместимым) с типом элементов, хранящихся в коллекции. Таким образом, при переборе массива тип должен быть совместим с типом элемента массива.
Чтобы понять побудительные причины применения циклов в стиле “for-each”, рассмотрим тип цикла f o r , для замены которого предназначен этот стиль. В следующем фрагменте для вычисления суммы значений элементов массива применяется традиционный цикл f o r .
int n u m s [] = { 1, 2 ,
3, 4, 5, 6 ,
7 ,
8, 9 ,
10 } ;
int sum = 0;
for(int i=0; i < 10; i++) sum +
= Чтобы вычислить сумму, мы последовательно считываем значения каждого элемента массива nums. Таким образом, чтение всего массива выполняется строго последовательно. Это осуществляется за счет индексации массива nums вручную по управляющей переменной цикла i Цикл f o r в стиле “for-each” позволяет автоматизировать этот процесс. В частности, применение такого цикла позволяет не устанавливать значение счетчика цикла за счет указания его начального и конечного значений и исключает необходимость индексации массива вручную. Вместо этого программа автоматически выполняет цикл по всему массиву, последовательно получая значения каждого из его элементов, от первого до последнего. Например, с учетом версии “for-each” цикла f o r предыдущий фрагмент можно переписать следующим образом n u m s [] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int sum = 0;
for(int x: nums) sum += При каждом прохождении цикла, переменной х автоматически присваивается значение, равное значению следующего элемента массива nums. Таким образом, на первой итерации переменная х содержит 1, на второй — 2 и т.д. При этом не только упрощается синтаксис программы, но и исключается возможность ошибок выхода за пределы массива.
Ниже показан пример полной программы, иллюстрирующей применение описанной версии “for-each” цикла f o r .
// Использование цикла for в стиле for-each.
class ForEach {
public static void main(String a r g s []) {
int n u m s [] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 1 0 } ;

1 3 Часть I. Язык Java
int sum = 0;
11
использование стиля for-each для отображения и
// суммирования значений
for(int х :
nums) Значение равно " + x ) ;
sum += Сумма равна " + Эта программа создает следующий вывод.
Значение равно 1 Значение равно 2
Значение равно Значение равно 4
Значение равно 5
Значение равно Значение равно 7 Значение равно 8 Значение равно Значение равно 10 Сумма равна Как видно из этого вывода, оператор f o r в стиле “for-each” автоматически перебирает элементы массива, от наименьшего индекса к наибольшему.
Хотя повторение цикла f o r в стиле “for-each” выполняется до тех пор, пока не будут обработаны все элементы массива, цикл можно прервать и раньше, используя оператор b r e a k . Например, следующая программа суммирует значения пяти первых элементов массива nums.
// Использование оператора break в цикле for в стиле for-each.
class ForEach2 {
public static void main(String a r g s []) {
int sum = 0;
int n u m s [] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 1 0 } ;
// использование цикла for для отображения и
// суммирования значений
for(int х :
nums) Значение равно " + x ) ;
sum +
= x;
if(x == 5) break; // прекращение цикла после
// получения 5 значений
}
System.out.println("Сумма пяти первых элементов равна " + Программа создает следующий вывод.
Значение равно 1 Значение равно 2
Значение равно Значение равно Значение равно Сумма пяти первых элементов равна 15

Глава 5. Управляющие операторы
1 3 Как видите, выполнение цикла прекращается после получения значения пятого элемента. Оператор можно использовать также и с другими циклами
Java. Подробнее этот оператор будет рассмотрен в последующих разделах.
П ри использовании цикла в стиле “for-each” необходимо помнить о следующем его итерационная переменная является переменной только для чтения, поскольку она связана только с исходным массивом. Оператор присваивания значения итерационной переменной не оказывает никакого влияния на исходный массив. Иначе говоря, содержимое массива нельзя изменять, присваивая новое значение итерационной переменной. Например, рассмотрим следующую программу Переменная цикла for-each доступна только для чтения
class NoChange {
public static void main(String a r g s []) {
int n u m s [] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 1 0 } ;
for(int x :
nums) {
System.out.print(x + " ");
x = x * 10; // этот оператор не оказывает никакого
// влияния на массив nums
}
System.out.println();
for(int x :
nums)
System.out.print(x + " "Первый цикл f o r увеличивает значение итерационной переменной на 10. Однако этот оператор присваивания не оказывает никакого влияния на исходный массив nums, как видно из результата выполнения второго оператора f o r . Создаваемый программой вывод подтверждает сказанное 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 Итерация в многомерных массивах
У совершенствованная версия цикла f o r применима также и к многомерным массивам. Однако следует помнить, что вязы кем ногомерны е массивы состоят из массивов массивов (Например, двухмерный массив — это массив одномерных массивов) Это важно при переборем ногомерного массива, поскольку результат каждой итерации — следующий массива не отдельный элемент. Более того, тип итерационной переменной цикла f o r должен быть совместим с типом получаемого массива. Например, в случае двухмерного массива итерационная переменная должна быть ссылкой на одномерный массив. В общем случае при использовании цикла “for-each” для перебора массива размерностью
N получаемые объекты будут массивами размерностью N - 1. Чтобы понять, что из этого следует, рассмотрим следующую программу. В ней вложенные циклы f o r служат для получения упорядоченных по строкам элементов двухмерного массива Использование цикла for в стиле for-each применительно
// к двухмерному массиву
class ForEach3 {
public static void main(String a r g s []) {
int sum = 0;

1 3 Часть I. Язык Java
int n u m s [][] = new int[3][5];
11
присвоение значений элементам массива nums
for(int i = 0; i < 3; i++)
for(int j = 0; j < 5; j++)
n u m s [i ][j ]
= (i+l)*(j+l);
// использование цикла for в стиле for-each для отображения
// и суммирования значений
for(int х :
nums) {
for(int у :
x) Значение равно " + у
sum += у;
}
}
System.out.println("Сумма:
" + Эта программа создает следующий вывод.
Значение равно Значение равно Значение равно Значение равно Значение равно Значение равно Значение равно Значение равно Значение равно Значение равно Значение равно Значение равно Значение равно Значение равно Значение равно Сумма Следующая строка этой программы заслуживает особого внимания х :
nums) Обратите внимание на способ объявления переменной х. Эта переменная — ссылка на одномерный массив целочисленных значений. Это необходимо, потому что результат выполнения каждой итерации цикла f o r — следующий массив в массиве nums, начиная с массива, указанного элементом nums [0 ]. Затем внутренний цикл f o r перебирает каждый из этих массивов, отображая значения каждого элемента.
И спользование усовершенствованного цикла Поскольку каждый оператор f o r в стиле “for-each” может перебирать элементы массива только последовательно, начиная с первого и заканчивая последним, может показаться, что его применение ограничено. Но это не так. Множество алгоритмов требуют использования именно этого механизма. Одним из наиболее часто используемых алгоритмов является поиск. Например, следующая программа использует цикл f o r для поиска значения в неупорядоченном массиве. Поиск прекращается после обнаружения искомого значения Поиск в массиве с применением цикла for в стиле for-each.
class Search {
public static void main(String a r g s []) {
int n u m s [] = { 6, 8, 3, 7 ,
5, 6, 1, 4 };
Глава 5. Управляющие операторы 3 7
int val = 5;
boolean found = false;
11
использование цикла for в стиле for-each для
// поискав значения val
for(int x :
nums) {
if(x == v a l )
{
found = true;
break;
}
}
i f (Значение найдено!");
}
}
В данном случае выбор стиля “for-each” для цикла f o r полностью оправдан, поскольку поиск в неупорядоченном массиве предполагает последовательный просмотр каждого элемента. (Конечно, если бы массив был упорядоченным, можно было бы использовать бинарный поиск, реализация которого требовала бы применения цикла другого стиля) К другим типам приложений, которым применение циклов в стиле “for-each” предоставляет преимущества, относятся вычисление среднего значения, отыскание минимального или максимального значения в наборе, поиск дубликатов и т.п.
Хотя в примерах этой главы мы использовали массивы, цикл f o r в стиле “for- each” особенно удобен при работе с коллекциями, определенными в инфраструктуре Collections Framework (Инфраструктура коллекций, которая описана в части. В более общем случае оператор f o r может перебирать элементы любой коллекции объектов, если эта коллекция удовлетворяет определенному набору ограничений, который описан в главе Вложенные циклы

Подобно другим языкам программирования, Java допускает использование вложенных циклов. Другими словами, один цикл может выполняться внутри другого. Например, в следующей программе использованы вложенные циклы f o r .
// Циклы могут быть вложенными
class Nested {
public static void main(String a r g s []) {
int i ,
j ;
for(i=0; i<10; i++) {
f o r (j = i ; j <10; j++)
System.o u t .p r i n t (Эта программа создает следующий вывод

1 3 Часть I. Язык Операторы перехода
В языке Java определены три оператора перехода b r e a k , c o n t i n u e и r e t u r n . Они передают управление другой части программы. Рассмотрим каждый из них.
На заметку Кроме операторов перехода, рассмотренных в этом разделе, язык Java поддерживает еще один способ изменения порядка выполнения инструкций программы обработку исключений. Обработка исключений предоставляет структурированный метод, используя который программа может обнаруживать и обрабатывать ошибки времени выполнения. Для поддержки этого метода служат ключевые слова
t r y , c a tc h , th ro w s и

f i n a l l y . По сути механизм обработки ошибок позволяет программе выполнять нелокальные ветви. Поскольку тема обработки исключений очень обширна, она рассмотрена в посвященной ей главе Использование оператора b r e a В языке Java оператор b r e a k находит три применения. Во-первых, как уже было показано, он завершает последовательность операторов в операторе s w itc h . Во- вторых, его можно использовать для выхода из цикла. И в-третьих, этот оператор можно применять в качестве цивилизованной формы оператора безусловного перехода (“goto”). Рассмотрим последние два применения.
Использование оператора b r e a k для выхода из цикла Используя оператор b re a k , можно вызвать немедленное завершение цикла, пропуская условное выражение и любой остальной код в теле цикла. Когда программа встречает оператор b r e a k внутри цикла, она прекращает выполнение цикла и управление передается оператору, следующему за циклом. Ниже показан простой пример Использование оператора break для выхода из цикла
class BreakLoop {
public static void main(String a r g s []) {
for(int i=0; i<100; i++) {
if(i == 10) break; // выход из цикла если i равно 10
System.out.println("i :
" + Цикл завершен.");
}
}
Эта программа создает следующий вывод : 0
i: 1
i :
2
i: 3
i: 4
i: 5
i :
6
i: 7
i: 8
i: Цикл завершен
Глава 5. Управляющие операторы 3 Как видите, хотя цикл f o r должен был бы выполняться для значений управляющей переменной от 0 до 99, оператор b r e a k приводит к более раннему выходу из него, когда значение переменной i становится равным Оператор можно использовать в любых циклах Java, в том числе в преднамеренно бесконечных циклах. Например, в предыдущей программе можно было применить цикл w h ile . Эта программа создает вывод, совпадающий с предыдущим Использование оператора break для выхода из цикла while,
class BreakLoop2 {
public static void main(String a r g s []) {
int i = 0;
w h i l e d < 1 0 0 ) {
if(i == 10) break; // выход из цикла, если i равно 10
System.out.println("i :
" + i);
i
+ Цикл завершен.");
}
}
В случае его использования внутри набора вложенных циклов оператор b r e a k осуществляет выход только из самого внутреннего цикла Использование оператора break во вложенных циклах
class ВгеакЬоорЗ {
public static void main(String a r g s []) {
for(int i=0; i<3; i++) Проход " + i +
");
for(int j =
0; j<100; j++) {
if(j == 10) break; // выход из цикла, если j равно 10
System.out.print(j + " ");
}
System.out.p r Циклы завершены.");
}
}
Эта программа создает следующий вывод.
Проход 0: 0 1 2 3 4 5 6 7 8 9 Проход 1: 0 1 2 3 4 5 6 7 8 9
Проход 2 : 0 1 2 3 4 5 6 7 8 9
Циклы завершены.
Как видите, оператор b r e a k во внутреннем цикле может приводить к выходу только из этого цикла. На внешний циклон не оказывает никакого влияния.
При использовании оператора b r e a k необходимо помнить следующее. Во- первых, в цикле можно использовать более одного оператора b r e a k . Однако при этом следует соблюдать осторожность. Как правило, применение слишком большого количества операторов b r e a k приводит к нарушению структуры кода. Во- вторых, оператор b r e a k , который завершает последовательность операторов в операторе s w i tc h , оказывает влияние только на данный оператора не на какие-либо содержащие его циклы.
Помните! Оператор
b r e a k не был задуман в качестве обычного средства выхода из цикла Для этого служит условное выражение цикла. Этот оператор следует использовать для выхода из цикла только в особых ситуациях
но Часть I. Язык Использование оператора b r e a k в качестве формы оператора безусловного Перехода
Кроме применения с операторами switch и циклами, оператор break можно использовать и сам по себе в качестве цивилизованной формы оператора безусловного перехода (“goto”). Язык Java не содержит оператора “goto”, поскольку он позволяет выполнять ветвление программ произвольными неструктурированным образом. Как правило, код, который управляется оператором “goto”, труден для понимания и поддержки. Кроме того, этот оператор исключает возможность оптимизации кода для определенного компилятора. Однако в некоторых случаях оператор “goto” — ценная и вполне допустимая конструкция управления потоком команд. Например, оператор “goto” может быть полезен при выходе из набора вложенных циклов с большим количеством уровней. Для таких ситуаций Java определяет расширенную форму оператора break. Используя эту форму, можно, например, осуществлять выход из одного или нескольких блоков кода. Эти блоки необязательно должны быть частью цикла или оператора switch. Они могут быть любым блоком. Более того, можно точно указать оператор, с которого будет продолжено выполнение программы, поскольку эта форма оператора break работает с метками. Как будет показано, оператор break предоставляет все преимущества оператора “goto”, не порождая его проблемы. Общая форма оператора break сметкой имеет следующий вид
метка;
Чащ е всего метка — это имя метки, идентифицирующей блок кода. Им может быть как самостоятельный блок кода, таки целевой блок другого оператора. При выполнении этой формы оператора управление передается названному блоку кода. Помеченный блок кода должен содержать оператор break, но он необязательно должен быть непосредственно содержащим его блоком. В частности это означает, что оператор break сметкой можно применять для выхода из набора вложенных блоков. Однако его нельзя использовать для передачи управления внешнему блоку кода, который не содержит данный оператор Чтобы пометить блок, необходимо поместить метку в его начале. Метка — это любой допустимый идентификатор Java, за которым следует двоеточие. Как только блок помечен, его метку можно использовать в качестве цели оператора break. В результате выполнение программы будет продолжено с конца помеченного блока. Например, следующая программа содержит три вложенных блока, каждый из которых помечен своей меткой. Оператор приводит к переходу к концу блока сметкой с пропуском двух вызовов метода print
In ().
// Использование оператора break в качестве цивилизованной формы оператора
g o t o .
class Break {
public static void main(String a r g s []) {
boolean t = true;
first: {
second: {
third: Предшествует оператору break.");
if(t) break second; // выход из блока Этот оператор не будет выполняться");
}
System.out.println("Этот оператор не будет выполняться
Глава 5. Управляющие операторы 6 Этот оператор следует за блоком Эта программа создает следующий вывод.
Предшествует оператору Этот оператор следует за блоком Одно из наиболее распространенных применений оператора b r e a k сметкой его использование для выхода из вложенных циклов. Например, в следующей программе внешний цикл выполняется только один раз Использование оператора break для выхода из вложенных циклов
class BreakLoop4 {
public static void main(String a r g s []) {
outer: for(int i=0; i<3;
i++) Проход " + i + ": ");
for(int j =0; j<100; j++) {
if(j == 10) break outer; // выход из обоих циклов
System.out.print(j + " "Эта строка не будет выводиться");
}
System.out.println("Циклы завершены.");
}
}
Эта программа создает следующий вывод.
Проход 0: 0 1 2 3 4 5 6 7 8 9 Циклы завершены.
Как видите, когда внутренний цикл выполняет выход во внешний цикл, это приводит к завершению обоих циклов.
Следует иметь ввиду, что нельзя выполнить переход к какой-либо метке, которая определена не для содержащего данный оператор b r e a k блока. Например, следующая программа содержит ошибку, и поэтому ее компиляция будет невозможна Эта программа содержит ошибку
class BreakErr {
public static void main(String a r g s []) {
one: for(int i=0; i<3; i++) {
System.out.p r i n t ("Pass " + i + ": ");
}
for(int j =
0; j<100; j++) {
i f (j == 10) break one; // ОШИБКА + " "Поскольку блок, помеченный меткой one, не содержит оператор b r e a k , передача управления этому внешнему блоку невозможна.
Использование оператора
c o n t i n u Иногда требуется, чтобы повторение цикла осуществлялось с более раннего оператора его тела. То есть на данной конкретной итерации может требоваться

1 4 Часть I. Язык продолжить выполнение цикла без обработки остального кода в его теле. По сути, это означает переход в теле цикла к его окончанию. Для выполнения этого действия служит оператор continue. В циклах while и do-while оператор con­
tinue вызывает передачу управления непосредственно управляющему условному выражению цикла. В цикле for управление передается вначале итерационной части цикла for, а потом условному выражению. Во всех этих трех циклах любой промежуточный код пропускается.
Ниже приведен пример программы, в которой оператор cont inue используется для вывода двух чисел в каждой строке Демонстрация применения оператора continue,

class Continue {
public static void main(String a r g s []) {
for(int i=0; i<10; i++) {
System.out.print(i + " ");
if (i%2 == 0) В этом коде оператор % служит для проверки четности значения переменной i . Если оно четное, выполнение цикла продолжается без перехода к новой строке. Программа создает следующий вывод 1 2 3
4 5
6 7
8 Как и оператор break, оператор continue может содержать метку содержащего его цикла, который нужно продолжить. Ниже показан пример программы, в которой оператор cont inue применяется для вывода треугольной таблицы умножения чисел от 0 до 9.
// Использование оператора continue сметкой j++) {
i f (j > i) {
System.out.println();
continue outer;
}
System.out.print(" " + (i * В этом примере оператор continue прерывает цикл подсчета значений переменной j и продолжает его со следующей итерации цикла подсчета переменной i. Вывод этой программы имеет следующий вид.
о
0 1
0 2 4
0 3 6 9
0 4 8 12 16
0 5 10 15 20 25
Глава 5. Управляющие операторы О 6 12 18 24 30 36
0 7 14 21 28 35 42 49
0 8 16 24 32 40 48 56 О 9 18 27 36 45 54 63 72 Удачные применения оператора c o n t i n u e встречаются редко. Одна из причин состоит в том, что язык Java предлагает широкий выбор операторов цикла, удовлетворяющих требованиям большинства приложений. Однако в тех случаях, когда требуется более раннее начало новой итерации, оператор c o n t i n u e предоставляет структурированный метод выполнения этой задачи.
Оператор
r e t u r Последний из управляющих операторов — r e t u r n . Его используют для выполнения явного выхода из метода. То есть он снова передает управление объекту, который вызвал данный метод. Как таковой, этот оператор относится к операторам перехода. Хотя полное описание оператора r e t u r n придется отложить до рассмотрения методов в главе 6, все же кратко ознакомимся сего особенностями.
Оператор r e t u r n можно использовать в любом месте метода для возврата управления тому объекту, который вызвал данный метод. Таким образом, оператор r e t u r n немедленно прекращает выполнение метода, в котором он находится. Следующий пример иллюстрирует это. В данном случае оператор r e t u r n приводит к возврату управления системе времени выполнения Java, поскольку именно она вызывает метод m ain ().
// Демонстрация использования оператора return,
class Return {
public static void ma i n ( S t r i n g a r g s []) {
boolean t = true;
S y s t e m . o u t . p r i n t l n (До выполнения возврата
if(t) return; // возврат к вызывающему объекту
S y s t e m . o u t . p r i n t l n (Этот оператор выполняться не будет.");
}
}
Вывод этой программы имеет такой вид.
До выполнения возврата.
Как видите, заключительный вызов метода p r i n t l n () не выполняется. Сразу после выполнения оператора r e t u r n программа возвращает управление вызывающему объекту.
И последний нюанс в приведенной программе использование оператора i f ( t ) обязательно. Без него компилятор Java сигнализировал бы об ошибке
“unreachable code” (недостижимый код, поскольку выяснил бы, что последний вызов метода p r i n t I n () никогда не будет выполняться. Во избежание этой ошибки в демонстрационном примере пришлось ввести компилятор в заблуждение с помощью оператора i f .

1   ...   6   7   8   9   10   11   12   13   ...   90


написать администратору сайта