Java Language
операторы
Поиск…
Вступление
Операторы на языке программирования Java - это специальные символы, которые выполняют определенные операции над одним, двумя или тремя операндами, а затем возвращают результат.
замечания
Оператор - это символ (или символы), который сообщает программе Java выполнить операцию над одним, двумя или тремя операндами . Оператор и его операнды образуют выражение (см. Раздел «Выражения»). Операнды оператора сами являются выражениями.
В этом разделе описываются 40 или около того различных операторов, определенных Java. В разделе «Отдельные выражения» объясняется:
- как операторы, операнды и другие вещи объединяются в выражения,
- как оцениваются выражения, и
- как работают выражения, преобразования и выражения.
Оператор конкатенации строк (+)
Символ +
может означать три разных оператора в Java:
- Если нет операнда до
+
, то это унарный оператор Plus. - Если есть два операнда, они оба являются числовыми. то он является двоичным оператором сложения.
- Если есть два операнда, и по крайней мере один из них является
String
, то он является двоичным оператором Concatenation.
В простом случае оператор Concatenation соединяет две строки, чтобы дать третью строку. Например:
String s1 = "a String";
String s2 = "This is " + s1; // s2 contains "This is a String"
Если один из двух операндов не является строкой, он преобразуется в String
следующим образом:
Операнд, тип которого является примитивным типом, преобразуется, как если бы он вызывал
toString()
по размеру в штучной упаковке.Операнд, тип которого является ссылочным типом, преобразуется путем вызова метода
toString()
операнда. Если операнд имеет значениеnull
, или если методtoString()
возвращает значениеnull
, вместо него используется строковый литерал"null"
.
Например:
int one = 1;
String s3 = "One is " + one; // s3 contains "One is 1"
String s4 = null + " is null"; // s4 contains "null is null"
String s5 = "{1} is " + new int[]{1}; // s5 contains something like
// "{} is [I@xxxxxxxx"
Объяснение примера s5
заключается в том, что метод toString()
для типов массивов наследуется из java.lang.Object
, и поведение заключается в создании строки, состоящей из имени типа и идентификатора hashcode объекта.
Оператор Concatenation задается для создания нового объекта String
, за исключением случая, когда выражение является константным выражением. В последнем случае выражение оценивается по типу компиляции, а его значение времени выполнения эквивалентно строковому литералу. Это означает, что для разделения длинного строкового литерала нет накладных расходов во время выполнения:
String typing = "The quick brown fox " +
"jumped over the " +
"lazy dog"; // constant expression
Оптимизация и эффективность
Как отмечено выше, за исключением постоянных выражений, каждое выражение конкатенации строк создает новый объект String
. Рассмотрим этот код:
public String stars(int count) {
String res = "";
for (int i = 0; i < count; i++) {
res = res + "*";
}
return res;
}
В вышеприведенном методе каждая итерация цикла создаст новую String
которая будет на один символ длиннее предыдущей итерации. Каждая конкатенация копирует все символы в строках операндов, чтобы сформировать новую String
. Таким образом, stars(N)
будут:
- создать
N
новых объектовString
и выбросить все, кроме последнего, - копировать
N * (N + 1) / 2
символа и - сгенерировать
O(N^2)
байты мусора.
Это очень дорого для больших N
Действительно, любой код, который объединяет строки в цикле, может иметь эту проблему. Лучший способ написать это будет следующим:
public String stars(int count) {
// Create a string builder with capacity 'count'
StringBuilder sb = new StringBuilder(count);
for (int i = 0; i < count; i++) {
sb.append("*");
}
return sb.toString();
}
В идеале вы должны установить емкость StringBuilder
, но если это нецелесообразно, класс автоматически вырастет массив поддержки, который строитель использует для хранения символов. (Примечание: реализация расширяет базовый массив экспоненциально. Эта стратегия сохраняет количество копий символов в O(N)
а не O(N^2)
.)
Некоторые люди применяют этот шаблон для всех конкатенаций строк. Однако это не нужно, поскольку JLS позволяет компилятору Java оптимизировать конкатенации строк в одном выражении. Например:
String s1 = ...;
String s2 = ...;
String test = "Hello " + s1 + ". Welcome to " + s2 + "\n";
как правило , оптимизируется компилятором байт-кода на что-то вроде этого;
StringBuilder tmp = new StringBuilder();
tmp.append("Hello ")
tmp.append(s1 == null ? "null" + s1);
tmp.append("Welcome to ");
tmp.append(s2 == null ? "null" + s2);
tmp.append("\n");
String test = tmp.toString();
(Компилятор JIT может оптимизировать это, если он сможет определить, что s1
или s2
не может быть null
.) Но обратите внимание, что эта оптимизация разрешена только в одном выражении.
Короче говоря, если вас беспокоит эффективность конкатенаций строк:
- Ручная оптимизация, если вы повторяете конкатенацию в цикле (или аналогичном).
- Не ручная оптимизация одного выражения конкатенации.
Арифметические операторы (+, -, *, /,%)
Язык Java предоставляет 7 операторов, выполняющих арифметические операции с целыми и плавающими значениями.
- Есть два
+
операторов:- Оператор двоичного сложения добавляет одно число к другому. (Существует также двоичный
+
оператор, который выполняет конкатенацию строк. Это описано в отдельном примере.) - Оператор унарного плюса ничего не делает, кроме запуска числового продвижения (см. Ниже)
- Оператор двоичного сложения добавляет одно число к другому. (Существует также двоичный
- Есть два
-
операторы:- Оператор двоичного вычитания вычитает одно число из другого.
- Унарный минус-оператор эквивалентен вычитанию его операнда с нуля.
- Оператор двоичного умножения (*) умножает одно число на другое.
- Оператор двоичного деления (/) делит одно число на другое.
- Оператор двоичного остатка 1 (%) вычисляет остаток, когда одно число делится на другое.
1. Это часто неправильно называют оператором «модуль». «Остаток» - это термин, который используется JLS. «Модуль» и «остаток» - это не одно и то же.
Операнд и типы результатов, а также числовое продвижение
Операторы требуют числовых операндов и получают числовые результаты. Типы операндов могут быть любыми примитивными числовыми типами (то есть byte
, short
, char
, int
, long
, float
или double
) или любым числовым типом оболочки, определяемым в java.lang
; т.е. ( Byte
, Character
, Short
, Integer
, Long
, Float
или Double
.
Тип результата определяется базой по типам операнда или операндов следующим образом:
- Если любой из операндов является
double
илиDouble
, тогда тип результата будетdouble
. - В противном случае, если любой из операндов является
float
илиFloat
, тогда тип результата будетfloat
. - В противном случае, если любой из операндов
long
илиLong
, тогда тип результатаlong
. - В противном случае тип результата -
int
. Это охватываетbyte
,short
иchar
операнды, а также `int.
Тип результата операции определяет, как выполняется арифметическая операция, и как обрабатываются операнды
- Если тип результата
double
, операнды повышаются доdouble
, а операция выполняется с использованием 64-битной (двойной точности двоичной) IEE 754 с плавающей запятой. - Если тип результата является
float
, операнды продвигаются наfloat
, и операция выполняется с использованием 32-битной (одиночной точности) IEE 754 с плавающей точкой арифметики. - Если тип результата
long
, операнды продвигаются доlong
, и операция выполняется с использованием битовой целочисленной арифметики двоичного кода с двоичным кодом, состоящей из 64 бит. - Если типом результата является
int
, операнды продвигаются доint
, а операция выполняется с использованием 32-разрядной двоичной двоичной двоичной арифметики двоичного кода.
Продвижение осуществляется в два этапа:
- Если тип операнда является типом-оболочкой, значение операнда будет опущено на значение соответствующего примитивного типа.
- При необходимости примитивный тип продвигается до требуемого типа:
- Продвижение целых чисел в
int
илиlong
потерь. - Продвижение
float
вdouble
потерь. - Продвижение целого числа в значение с плавающей запятой может привести к потере точности. Преобразование выполняется с использованием семантики «круг-к-ближайшему» IEE 768.
- Продвижение целых чисел в
Смысл разделения
Оператор / делит левый операнд n
( дивиденд ) и правый операнд d
( делитель ) и выдает результат q
( фактор ).
Явное целочисленное деление округляется до нуля. В разделе JLS 15.17.2 указано поведение целочисленного деления Java следующим образом:
Фактор, созданный для операндов
n
иd
представляет собой целое значениеq
, величина которого как можно больше, при условии, что|d ⋅ q| ≤ |n|
, Более того,q
положительно, когда|n| ≥ |d|
иn
иd
имеют один и тот же знак, ноq
отрицателен при|n| ≥ |d|
иn
иd
имеют противоположные знаки.
Есть несколько особых случаев:
- Если
n
-MIN_VALUE
, а делитель равен -1, то происходит переполнение целого числа, а результат -MIN_VALUE
. Никакое исключение не возникает в этом случае. - Если
d
равно 0, то генерируется «ArithmeticException».
Разделение с плавающей запятой Java требует рассмотрения более кратных случаев. Однако основная идея состоит в том, что результат q
является значением, наиболее близким к удовлетворяющему d . q = n
.
Разделение с плавающей точкой никогда не приведет к исключению. Вместо этого операции, делящиеся на ноль, приводят к значениям INF и NaN; увидеть ниже.
Значение остатка
В отличие от C и C ++, оператор остатка в Java работает как с целыми, так и с плавающей запятой.
Для целых случаев результат a % b
определяется как число r
такое, что (a / b) * b + r
равно a
, где /
, *
и +
- соответствующие Java-целые операторы. Это применяется во всех случаях, кроме случаев, когда b
равно нулю. В этом случае остаток приводит к ArithmeticException
.
Из приведенного выше определения следует, что a % b
может быть отрицательным, только если a
отрицательно, и оно положительно, только если a
положительно. Более того, величина a % b
всегда меньше величины b
.
Операция останова с плавающей запятой является обобщением целочисленного случая. Результат a % b
- остаток r
определяется математическим соотношением r = a - (b ⋅ q)
где:
-
q
- целое число, - это отрицательно, только если
a / b
отрицательно положительно, только еслиa / b
положительно и - его величина как можно больше, не превышающая величину истинного математического отношения
a
иb
.
Остаток с плавающей точкой может производить значения INF
и NaN
в крайних случаях, например, когда b
равно нулю; увидеть ниже. Это исключение не будет.
Важная заметка:
Результат операции останова с плавающей запятой, вычисляемой по
%
, не совпадает с результатом операции остатка, определенной IEEE 754. Остаток IEEE 754 может быть вычислен с использованием библиотечного методаMath.IEEEremainder
.
Целочисленное переполнение
Значения целых чисел на Java 32 и 64 бит подписаны и используют двоичное представление двоичного кода. Например, диапазон чисел, представляемых как (32 бит) int
-2 31 - +2 31 - 1.
Когда вы добавляете, вычитаете или несколько двух N битовых целых чисел (N == 32 или 64), результат операции может быть слишком большим для представления в виде N битового целого. В этом случае операция приводит к целочисленному переполнению , и результат может быть вычислен следующим образом:
- Математическая операция выполняется, чтобы дать промежуточное представление с двумя дополнениями всего числа. Это представление будет больше, чем N бит.
- В результате используются нижние 32 или 64 бита промежуточного представления.
Следует отметить, что целочисленное переполнение не приводит к исключениям ни при каких обстоятельствах.
Значения INF и NAN с плавающей запятой
Java использует представления с плавающей точкой IEE 754 для float
и double
. Эти представления имеют некоторые специальные значения для представления значений, которые выходят за пределы области действительных чисел:
- Значения «бесконечный» или «INF» означают слишком большие числа. Значение
+INF
обозначает слишком большие и положительные числа. Значение-INF
обозначает слишком большие и отрицательные числа. - «Неопределенный» / «не число» или NaN обозначают значения, возникающие в результате бессмысленных операций.
Значения INF производятся плавающими операциями, которые вызывают переполнение или делением на ноль.
Значения NaN производятся путем деления нуля на ноль или вычисления нуля нуля.
Удивительно, но можно выполнить арифметику с использованием операндов INF и NaN без возникновения исключений. Например:
- Добавление + INF и конечное значение дает + INF.
- Добавление + INF и + INF дает + INF.
- Добавление + INF и -INF дает NaN.
- Разделение по INF дает либо +0.0, либо -0.0.
- Все операции с одним или несколькими операндами NaN дают NaN.
Для получения полной информации см. Соответствующие подразделы JLS 15 . Обратите внимание, что это в значительной степени «академическое». Для типичных вычислений INF
или NaN
означает, что что-то пошло не так; например, у вас есть неполные или неправильные входные данные, или расчет был запрограммирован неправильно.
Операторы равенства (==,! =)
Операторы ==
и !=
- это двоичные операторы, которые оценивают true
или false
зависимости от того, являются ли операнды равными. Оператор ==
задает значение true
если операнды равны и false
противном случае. Оператор !=
Дает false
если операнды равны и true
противном случае.
Этими операторами могут быть использованы операнды с примитивными и ссылочными типами, но поведение существенно отличается. Согласно JLS, на самом деле существует три различных набора этих операторов:
- Операторы Boolean
==
и!=
. - Операторы Numeric
==
и!=
. - Операторы Reference
==
и!=
.
Однако во всех случаях тип результата операторов ==
и !=
Является boolean
.
Операторы Numeric ==
и !=
Когда один (или оба) операндов оператора ==
или !=
Является примитивным числовым типом ( byte
, short
, char
, int,
long
, float
или double
), оператор представляет собой числовое сравнение. Второй операнд должен быть либо примитивным числовым типом, либо коробочным числовым типом.
Поведение других числовых операторов выглядит следующим образом:
- Если один из операндов является коробочным, он распаковывается.
- Если любой из операндов теперь является
byte
,short
илиchar
, он продвигается доint
. - Если типы операндов не совпадают, то операнд с «меньшим» типом продвигается к «более крупному» типу.
- Затем сравнение проводится следующим образом:
- Если продвинутые операнды являются
int
илиlong
тогда значения тестируются, чтобы убедиться, что они идентичны. - Если продвинутые операнды являются
float
илиdouble
тогда:- две версии нуля (
+0.0
и-0.0
) считаются равными - значение
NaN
рассматривается как не равное чему-либо, и - другие значения равны, если их представления IEEE 754 идентичны.
- две версии нуля (
- Если продвинутые операнды являются
Примечание: вам нужно быть осторожным при использовании ==
и !=
Для сравнения значений с плавающей запятой.
Операторы Boolean ==
и !=
Если оба операнда являются boolean
, или один является boolean
а другой Boolean
, эти операторы являются операторами Boolean ==
и !=
. Поведение выглядит следующим образом:
- Если один из операндов является
Boolean
, он распаковывается. - Проверяются незанятые операнды и вычисляется логический результат в соответствии со следующей таблицей истинности
В | A == B | A! = B | |
---|---|---|---|
ложный | ложный | правда | ложный |
ложный | правда | ложный | правда |
правда | ложный | ложный | правда |
правда | правда | правда | ложный |
Есть две «подводные камни», которые позволяют использовать ==
и !=
Экономно с значениями истинности:
Если вы используете
==
или!=
Для сравнения двухBoolean
объектов, то используются операторы Reference. Это может дать неожиданный результат; см. Pitfall: использование == для сравнения объектов примитивных оберток, таких как IntegerОператор
==
может быть легко ошибочен как=
. Для большинства типов операндов эта ошибка приводит к ошибке компиляции. Однако дляboolean
иBoolean
операндов ошибка приводит к неправильному поведению во время выполнения; см. Pitfall - использование '==' для проверки логического
Операторы Reference ==
и !=
Если оба операнда являются объектными ссылками, операторы ==
и !=
Проверяют, относятся ли эти два операнда к одному и тому же объекту . Это часто не то, что вы хотите. Чтобы проверить, являются ли два объекта равными по значению , вместо этого следует использовать метод .equals()
.
String s1 = "We are equal";
String s2 = new String("We are equal");
s1.equals(s2); // true
// WARNING - don't use == or != with String values
s1 == s2; // false
Предупреждение: использование ==
и !=
Для сравнения значений String
в большинстве случаев неверно ; см. http://www.riptutorial.com/java/example/16290/pitfall--using----to-compare-strings . Аналогичная проблема применима к примитивным типам обертки; см. http://www.riptutorial.com/java/example/8996/pitfall--using----to-compare-primitive-wrappers-objects-such-as-integer .
О краях NaN
В JLS 15.21.1 указано следующее:
Если либо операнд
NaN
, то результат==
являетсяfalse
но результат!=
true
. Действительно, тестx != x
true
тогда и только тогда, когда значениеx
равноNaN
.
Такое поведение (для большинства программистов) неожиданно. Если вы проверите, соответствует ли значение NaN
самому себе, ответ будет «Нет, это не так!». Другими словами, ==
не рефлексивно для значений NaN
.
Однако это не «странность» Java, это поведение указано в стандартах с плавающей точкой IEEE 754, и вы обнаружите, что оно реализовано большинством современных языков программирования. (Для получения дополнительной информации см. Http://stackoverflow.com/a/1573715/139985 ... отметив, что это написано кем-то, кто был «в комнате, когда были приняты решения»!)
Операторы Increment / Decrement (++ / -)
Переменные могут быть увеличены или уменьшены на 1 с помощью операторов ++
и --
соответственно.
Когда операторы ++
и --
следуют за переменными, они называются post-increment и post-декремент соответственно.
int a = 10;
a++; // a now equals 11
a--; // a now equals 10 again
Когда операторы ++
и --
предшествуют переменным, операции называются пред-приращениями и пред-декрементами соответственно.
int x = 10;
--x; // x now equals 9
++x; // x now equals 10
Если оператор предшествует переменной, значение выражения будет значением переменной после того, как будет увеличиваться или уменьшаться. Если оператор следует за переменной, значение выражения будет значением переменной до того, как будет увеличиваться или уменьшаться.
int x=10;
System.out.println("x=" + x + " x=" + x++ + " x=" + x); // outputs x=10 x=10 x=11
System.out.println("x=" + x + " x=" + ++x + " x=" + x); // outputs x=11 x=12 x=12
System.out.println("x=" + x + " x=" + x-- + " x=" + x); // outputs x=12 x=12 x=11
System.out.println("x=" + x + " x=" + --x + " x=" + x); // outputs x=11 x=10 x=10
Будьте осторожны, чтобы не перезаписывать пост-приращения или декременты. Это происходит, если вы используете оператор post-in / decment в конце выражения, которое переназначается самой переменной in / decmented. Значение in / decment не будет иметь эффекта. Несмотря на то, что переменная с левой стороны увеличивается правильно, ее значение будет немедленно перезаписано ранее оцененным результатом с правой стороны выражения:
int x = 0;
x = x++ + 1 + x++; // x = 0 + 1 + 1
// do not do this - the last increment has no effect (bug!)
System.out.println(x); // prints 2 (not 3!)
Правильный:
int x = 0;
x = x++ + 1 + x; // evaluates to x = 0 + 1 + 1
x++; // adds 1
System.out.println(x); // prints 3
Условный оператор (? :)
Синтаксис
{условие для оценки} ? {statement-execute-on-true} : {statement-execute-on-false}
Как показано в синтаксисе, Условный оператор (также известный как Тернарный оператор 1 ) использует ?
(знак вопроса) и :
(двоеточие), чтобы разрешить условное выражение двух возможных результатов. Он может использоваться для замены более длинных блоков if-else
для возврата одного из двух значений на основе условия.
result = testCondition ? value1 : value2
Эквивалентно
if (testCondition) {
result = value1;
} else {
result = value2;
}
Его можно прочитать как «Если testCondition истинно, установите результат в value1; в противном случае установите результат в значение2 ".
Например:
// get absolute value using conditional operator
a = -10;
int absValue = a < 0 ? -a : a;
System.out.println("abs = " + absValue); // prints "abs = 10"
Эквивалентно
// get absolute value using if/else loop
a = -10;
int absValue;
if (a < 0) {
absValue = -a;
} else {
absValue = a;
}
System.out.println("abs = " + absValue); // prints "abs = 10"
Общее использование
Вы можете использовать условный оператор для условных присвоений (например, для проверки нуля).
String x = y != null ? y.toString() : ""; //where y is an object
Этот пример эквивалентен:
String x = "";
if (y != null) {
x = y.toString();
}
Поскольку Условный оператор имеет второе наименьшее приоритетное значение, выше Операторов присваивания , редко требуется использовать скобки вокруг условия , но скобки требуются вокруг всей конструкции условного оператора в сочетании с другими операторами:
// no parenthesis needed for expressions in the 3 parts
10 <= a && a < 19 ? b * 5 : b * 7
// parenthesis required
7 * (a > 0 ? 2 : 5)
Условные операторы вложения также могут выполняться в третьей части, где она больше похожа на цепочку или как оператор switch.
a ? "a is true" :
b ? "a is false, b is true" :
c ? "a and b are false, c is true" :
"a, b, and c are false"
//Operator precedence can be illustrated with parenthesis:
a ? x : (b ? y : (c ? z : w))
Сноска:
1 - Как Java Language Specification, так и Java Tutorial вызывают оператор ( ? :
:) Условный оператор . В учебнике говорится, что он также известен как Тернарный оператор, поскольку он (в настоящее время) является единственным тройным оператором, определенным Java. Терминология «Условный оператор» согласуется с C и C ++ и другими языками с эквивалентным оператором.
Побитовые и логические операторы (~, &, |, ^)
Язык Java предоставляет 4 оператора, которые выполняют побитовые или логические операции с целыми или булевыми операндами.
- Оператор дополнения (
~
) является унарным оператором, который выполняет поразрядное или логическое обращение битов одного операнда; см. JLS 15.15.5. , - Оператор AND (
&
) является двоичным оператором, который выполняет побитовое или логическое «и» из двух операндов; см. JLS 15.22.2. , - Оператор OR (
|
) является двоичным оператором, который выполняет побитовое или логическое «включение» или «из двух операндов»; см. JLS 15.22.2. , - Оператор XOR (
^
) является двоичным оператором, который выполняет побитовое или логическое «исключение» или «из двух операндов»; см. JLS 15.22.2. ,
Логические операции, выполняемые этими операторами, когда операнды являются логическими, можно суммировать следующим образом:
В | ~ A | A & B | A | В | A ^ B | |
---|---|---|---|---|---|
0 | 0 | 1 | 0 | 0 | 0 |
0 | 1 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 0 | 1 | 1 |
1 | 1 | 0 | 1 | 1 | 0 |
Обратите внимание, что для целых операндов приведенная выше таблица описывает, что происходит для отдельных бит. Операторы фактически работают со всеми 32 или 64 битами операнда или операндов параллельно.
Типы операндов и типы результатов.
Обычные арифметические преобразования применяются, когда операнды являются целыми числами. Обычные прецеденты для побитовых операторов
Оператор ~
используется для изменения логического значения или изменения всех битов в целочисленном операнде.
Оператор &
используется для «маскировки» некоторых битов целочисленного операнда. Например:
int word = 0b00101010;
int mask = 0b00000011; // Mask for masking out all but the bottom
// two bits of a word
int lowBits = word & mask; // -> 0b00000010
int highBits = word & ~mask; // -> 0b00101000
|
оператор используется для объединения значений истинности двух операндов. Например:
int word2 = 0b01011111;
// Combine the bottom 2 bits of word1 with the top 30 bits of word2
int combined = (word & mask) | (word2 & ~mask); // -> 0b01011110
Оператор ^
используется для переключения или «переворачивания» битов:
int word3 = 0b00101010;
int word4 = word3 ^ mask; // -> 0b00101001
Дополнительные примеры использования побитовых операторов см. В разделе « Манипуляция бит»
Оператор экземпляра
Этот оператор проверяет, имеет ли объект определенный тип класса / интерфейса. Оператор instanceof записывается как:
( Object reference variable ) instanceof (class/interface type)
Пример:
public class Test {
public static void main(String args[]){
String name = "Buyya";
// following will return true since name is type of String
boolean result = name instanceof String;
System.out.println( result );
}
}
Это приведет к следующему результату:
true
Этот оператор по-прежнему будет возвращать true, если сравниваемый объект - это присвоение, совместимое с типом справа.
Пример:
class Vehicle {}
public class Car extends Vehicle {
public static void main(String args[]){
Vehicle a = new Car();
boolean result = a instanceof Car;
System.out.println( result );
}
}
Это приведет к следующему результату:
true
Операторы присваивания (=, + =, - =, * =, / =,% =, << =, >> =, >>> =, & =, | = и ^ =)
Левый операнд для этих операторов должен быть либо не конечной переменной, либо элементом массива. Правый операнд должен быть совместимым с левым операндом. Это означает, что либо типы должны быть одинаковыми, либо правильный тип операнда должен быть конвертирован в тип левых операндов комбинацией бокса, распаковки или расширения. (Подробнее см. JLS 5.2 .)
Точное значение операторов «операция и назначение» указано в JLS 15.26.2 следующим образом:
Составляющее выражение присваивания формы
E1 op= E2
эквивалентноE1 = (T) ((E1) op (E2))
, гдеT
- типE1
, за исключением того, чтоE1
оценивается только один раз.
Обратите внимание, что перед окончательным присваиванием подразумевается неявный тип.
1. =
Простой оператор присваивания: присваивает значение правого операнда левому операнду.
Пример:
c = a + b
добавит значениеa + b
к значениюc
и назначит егоc
2. +=
Оператор «добавить и присваивать»: добавляет значение правого операнда к значению левого операнда и присваивает результат левому операнду. Если левый операнд имеет тип String
, то это оператор «конкатенировать и присваивать».
Пример:
c += a
примерно такой же, какc = c + a
3. -=
Оператор «вычесть и присваивать»: вычитает значение правого операнда из значения левого операнда и присваивает результат левому операнду.
Пример:
c -= a
примерно совпадает сc = c - a
4. *=
Оператор «умножить и присваивать»: умножает значение правого операнда на значение левого операнда и присваивает результат левому операнду. ,
Пример:
c *= a
примерно совпадает сc = c * a
5. /=
Оператор «делить и присваивать»: делит значение правого операнда на значение левого операнда и присваивает результат левому операнду.
Пример:
c /*= a
примерно совпадает сc = c / a
6. %=
Оператор «модуль и назначение» вычисляет модуль значения правого операнда по значению левого операнда и присваивает результат левому операнду.
Пример:
c %*= a
примерно совпадает сc = c % a
7. <<=
Оператор «сдвиг влево и назначение».
Пример:
c <<= 2
примерно совпадает сc = c << 2
8. >>=
Оператор «арифметический сдвиг вправо и назначение».
Пример:
c >>= 2
примерно совпадает сc = c >> 2
9. >>>=
Оператор «Логический сдвиг вправо и назначение».
Пример:
c >>>= 2
примерно совпадает сc = c >>> 2
10. &=
Оператор «побитовой и назначающий».
Пример:
c &= 2
примерно совпадает сc = c & 2
11. |=
Оператор «побитовое или назначить».
Пример:
c |= 2
примерно совпадает сc = c | 2
12. ^=
Оператор «побитовое исключение и присваивание».
Пример:
c ^= 2
примерно такой же, какc = c ^ 2
Условные и условные операторы (&& и ||)
Java предоставляет условный и условный или оператор, которые берут один или два операнда типа boolean
и создают boolean
результат. Это:
&&
- оператор условного-И,||
- операторы условного ИЛИ. Оценка<left-expr> && <right-expr>
эквивалентна следующему псевдокоду:{ boolean L = evaluate(<left-expr>); if (L) { return evaluate(<right-expr>); } else { // short-circuit the evaluation of the 2nd operand expression return false; } }
Оценка <left-expr> || <right-expr>
эквивалентен следующему псевдокоду:
{
boolean L = evaluate(<left-expr>);
if (!L) {
return evaluate(<right-expr>);
} else {
// short-circuit the evaluation of the 2nd operand expression
return true;
}
}
Как видно из приведенного выше псевдокода, поведение операторов короткого замыкания эквивалентно использованию операторов if
/ else
.
Пример - использование && в качестве защиты в выражении
В следующем примере показан наиболее распространенный шаблон использования для оператора &&
. Сравните эти две версии метода, чтобы проверить, является ли поставленное Integer
равным нулю.
public boolean isZero(Integer value) {
return value == 0;
}
public boolean isZero(Integer value) {
return value != null && value == 0;
}
Первая версия работает в большинстве случаев, но если аргумент value
имеет value
null
, тогда будет NullPointerException
.
Во второй версии мы добавили тест «guard». Выражение value != null && value == 0
оценивается, сначала выполняя value != null
test. Если null
тест завершается успешно (т.е. он оценивается как true
), тогда вычисляется выражение value == 0
. Если null
тест терпит неудачу, то оценка value == 0
пропущена (закорочена), и мы не получаем NullPointerException
.
Пример. Используя &&, чтобы избежать дорогостоящего расчета
В следующем примере показано, как &&
можно использовать, чтобы избежать относительно дорогостоящего расчета:
public boolean verify(int value, boolean needPrime) {
return !needPrime | isPrime(value);
}
public boolean verify(int value, boolean needPrime) {
return !needPrime || isPrime(value);
}
В первой версии оба операнда |
всегда будет оцениваться, поэтому (дорогостоящий) метод isPrime
будет вызван без необходимости. Вторая версия позволяет избежать ненужного вызова, используя ||
вместо |
,
Операторы сдвига (<<, >> и >>>)
Язык Java предоставляет три оператора для выполнения поразрядного смещения по 32 и 64-битным целым значениям. Это все двоичные операторы, первый операнд которых является смещаемым значением, а второй операнд говорит, как далеко сдвинуться.
Оператор
<<
или левого сдвига сдвигает значение, заданное первым операндом влево , на число битных позиций, заданных вторым операндом. Пустые позиции на правом конце заполняются нулями.Оператор «>>» или арифметического сдвига сдвигает значение, заданное первым операндом, вправо , на количество битных позиций, заданных вторым операндом. Пустые позиции на левом конце заполняются копированием самого левого разряда. Этот процесс известен как расширение знака .
Оператор «>>>» или логического сдвига сдвигает значение, заданное первым операндом, вправо на число битных позиций, заданных вторым операндом. Пустые позиции в левом конце заполняются нулями.
Заметки:
Этим операторам требуется значение
int
илиlong
в качестве первого операнда и выдает значение с тем же типом, что и первый операнд. (Вам нужно будет использовать явный тип приведения при назначении результата сдвигаbyte
,short
или переменнойchar
.)Если вы используете оператор сдвига с первым операндом, который является
byte
,char
илиshort
, он продвигается доint
а операция производитint
.)Второй операнд уменьшается по модулю количества бит операции, чтобы дать величину сдвига. Подробнее о математической концепции мод см. Примеры модулей .
Биты, сдвинутые с левого или правого конца с помощью операции, отбрасываются. (Java не предоставляет примитивный оператор «rotate».)
Оператор арифметического сдвига эквивалентен делению числа (двух) дополнений на мощность 2.
Оператор сдвига влево эквивалентен, умножая число (2) дополнител на 2.
Следующая таблица поможет вам увидеть эффекты трех операторов сдвига. (Числа были выражены в двоичной нотации, чтобы помочь визуализации.)
Operand1 | operand2 | << | >> | >>> |
---|---|---|---|---|
0b0000000000001011 | 0 | 0b0000000000001011 | 0b0000000000001011 | 0b0000000000001011 |
0b0000000000001011 | 1 | 0b0000000000010110 | 0b0000000000000101 | 0b0000000000000101 |
0b0000000000001011 | 2 | 0b0000000000101100 | 0b0000000000000010 | 0b0000000000000010 |
0b0000000000001011 | 28 | 0b1011000000000000 | 0b0000000000000000 | 0b0000000000000000 |
0b0000000000001011 | 31 | 0b1000000000000000 | 0b0000000000000000 | 0b0000000000000000 |
0b0000000000001011 | 32 | 0b0000000000001011 | 0b0000000000001011 | 0b0000000000001011 |
... | ... | ... | ... | ... |
0b1000000000001011 | 0 | 0b1000000000001011 | 0b1000000000001011 | 0b1000000000001011 |
0b1000000000001011 | 1 | 0b0000000000010110 | 0b1100000000000101 | 0b0100000000000101 |
0b1000000000001011 | 2 | 0b0000000000101100 | 0b1110000000000010 | 0b00100000000000100 |
0b1000000000001011 | 31 | 0b1000000000000000 | 0b1111111111111111 | 0b0000000000000001 |
Там приведены примеры пользователя операторов сдвига в манипуляции бит
Оператор Лямбды (->)
Начиная с Java 8, оператор лямбды ( ->
) является оператором, используемым для введения выражения Лямбды. Существуют два распространенных синтаксиса, которые иллюстрируются следующими примерами:
a -> a + 1 // a lambda that adds one to its argument
a -> { return a + 1; } // an equivalent lambda using a block.
Выражение лямбда определяет анонимную функцию или, вернее, экземпляр анонимного класса, который реализует функциональный интерфейс .
(Этот пример включен здесь для полноты. См. Раздел « Лямбда-выражения» для полного лечения.)
Реляционные операторы (<, <=,>,> =)
Операторы <
, <=
, >
и >=
являются двоичными операторами для сравнения числовых типов. Смысл операторов, как и следовало ожидать. Например, если a
и b
объявлены как byte
, short
, char
, int
, long
, float
, double
или соответствующие типы в коробке:
- `a < b` tests if the value of `a` is less than the value of `b`.
- `a <= b` tests if the value of `a` is less than or equal to the value of `b`.
- `a > b` tests if the value of `a` is greater than the value of `b`.
- `a >= b` tests if the value of `a` is greater than or equal to the value of `b`.
Тип результата для этих операторов boolean
во всех случаях.
Операторы отношения могут использоваться для сравнения чисел с разными типами. Например:
int i = 1;
long l = 2;
if (i < l) {
System.out.println("i is smaller");
}
Операторы отношения могут использоваться, когда оба или оба числа являются экземплярами числовых типов в штучной упаковке. Например:
Integer i = 1; // 1 is autoboxed to an Integer
Integer j = 2; // 2 is autoboxed to an Integer
if (i < j) {
System.out.println("i is smaller");
}
Точное поведение суммируется следующим образом:
- Если один из операндов является коробочным, он распаковывается.
- Если любой из операндов теперь является
byte
,short
илиchar
, он продвигается доint
. - Если типы операндов не совпадают, то операнд с «меньшим» типом продвигается к «более крупному» типу.
- Сравнение выполняется по итоговым значениям
int
,long
,float
илиdouble
.
Вы должны быть осторожны с реляционными сравнениями, которые включают числа с плавающей запятой:
- Выражения, которые вычисляют числа с плавающей запятой, часто приводят к ошибкам округления из-за того, что представления с плавающей запятой компьютера имеют ограниченную точность.
- При сравнении целочисленного типа и типа с плавающей точкой преобразование целочисленного числа в плавающую точку также может приводить к ошибкам округления.
Наконец, Java немного поддерживает использование реляционных операторов с любыми типами, отличными от перечисленных выше. Например, вы не можете использовать эти операторы для сравнения строк, массивов чисел и т. Д.