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

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

Содержание


5.10. Приоритет и ассоциативность операторов
5.11. Порядок вычислений
Подобный материал:
1   ...   25   26   27   28   29   30   31   32   ...   81

5.10. Приоритет и ассоциативность операторов


Приоритетом (precedence) оператора называется порядок, в котором он выполняется по отношению к другим операторам. Различные операторы имеют различные приоритеты. Например, приоритет условных операторов выше, чем у логических, поэтому вы можете написать

if (i >>= min && i <<= max)

process(i);

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

5 * 3 — 3

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

5 * (3 — 3)

Когда два оператора с одинаковыми приоритетами оказываются рядом, порядок их выполнения определяется ассоциативностью операторов. Поскольку + (сложение) относится к лево-ассоциативным операторам, выражение

a + b + c

эквивалентно следующему:

(a + b) + c

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

постфиксные операторы

[] . (параметры) expr++ expr—

унарные операторы

++expr —expr +expr -expr ~ !

создание и преобразование типа

new (тип)expr

операторы умножения/деления

* / %

операторы сложения/вычитания

+ -

операторы сдвига

<< >> >>>

операторы отношения

< > >= <= instanceof

операторы равенства

== !=

поразрядное И

&

поразрядное исключающее ИЛИ



поразрядное включающее ИЛИ

|

логическое И

&&

логическое ИЛИ

||

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

?:

операторы присваивания

= += -= *= /= %= >>= <<= >>>= &= = |=

Все бинарные операторы, за исключением операторов присваивания, являются лево-ассоциативными. Операторы присваивания являются право-ассоциативными — другими словами, выражение a=b=c эквивалентно a=(b=c).

Приоритет может изменяться с помощью скобок. В выражении x+y*z сначала y умножается на z, после чего к результату прибавляется x, тогда как в выражении (x+y)*z сначала вычисляется сумма x и y, а затем результат умножается на z.

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

while ((v = stream.next()) != null)

processValue(v);

Приоритет операторов присваивания ниже, чем у операторов равенства; без скобок наш пример был бы равносилен следующему:

while (v = (stream.next() != null)) // НЕВЕРНО

processValue(v);

что, вероятно, отличается от ожидаемого порядка вычислений. Кроме того, конструкция без скобок, скорее всего, окажется неверной — она будет работать лишь в маловероятном случае, если v имеет тип boolean.

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

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

5.11. Порядок вычислений


Язык Java гарантирует, что операнды в операторах вычисляются слева направо. Например, в выражении x+y+z компилятор вычисляет значение x, потом значение y, складывает эти два значения, вычисляет значение z и прибавляет его к предыдущему результату. Компилятор не станет вычислять значение y перед x или z — перед y или x.

Такой порядок имеет значение, если вычисление x, y и z имеет некоторый побочный эффект. Скажем, если при этом будут вызываться методы, которые изменяют состояние объекта или выводят что-нибудь на печать, то изменение порядка вычислений отразится на работе программы. Язык гарантирует, что этого не произойдет.

Все операнды всех операторов, за исключением &&, || и ?: (см. ниже), вычисляются перед выполнением оператора. Это утверждение оказывается истинным даже для тех операций, в ходе которых могут возникнуть исключения. Например, целочисленное деление на ноль приводит к запуску исключения ArithmeticException, но происходит это лишь после вычисления обоих операндов.