1. Обзор
Java предоставляет набор побитовых операторов . Эти операторы позволяют нам удобно манипулировать отдельными битами числа.
Однако, когда мы сравниваем результат побитовой операции, мы можем попасть в распространенную ловушку.
В этом кратком руководстве мы обсудим, почему мы можем столкнуться с ошибкой времени компиляции Java «неверные типы операндов для бинарного оператора» и как решить эту проблему.
2. Введение в проблему
Как обычно, разберемся в проблеме на примере. Но сначала рассмотрим простой метод:
public void checkNumber() {
List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
intList.forEach(i -> {
if (i & 1 == 1) {
System.out.println(i + " is odd.");
} else {
System.out.println(i + " is even.");
}
});
}
Как мы видим, метод checkNumber
проходит через intList
, проверяет и выводит, является ли каждое число четным или нечетным.
Отметим, что логика проверки на нечетность в методе реализована нестандартно: i % 2 == 1
. Вместо этого мы выполняем побитовую операцию И (&) над целым числом
( i
) и 1. Если результат равен 1, мы знаем, что целое число i
является нечетным числом: i & 1 ==1
.
Однако, когда мы пытаемся протестировать описанный выше метод, код неожиданно не компилируется:
java: bad operand types for binary operator '&'
first type: java.lang.Integer
second type: boolean
Далее давайте разберемся, в чем причина проблемы и как ее решить.
3. Понимание приоритета операторов Java
Во-первых, сообщение об ошибке довольно простое. В нем говорится, что мы пытаемся выполнить побитовое И для логического
типа и целочисленного
типа.
Однако это странно, поскольку мы буквально написали « i & 1
» в коде. Почему компилятор считает, что логический
тип участвует в побитовой операции И?
Это связано с тем, что оператор « ==
» имеет более высокий приоритет, чем оператор « &
». То есть выражение « i & 1 == 1
» такое же, как « i & (1 == 1)
». Таким образом, у нас есть « i & true (boolean)
».
Теперь мы можем спросить: «Хорошо, == имеет более высокий приоритет, чем &
. Но почему ' i % 2 == 1
' работает так, как ожидалось?»
Чтобы ответить на этот вопрос, нам нужно более подробно рассмотреть правило приоритета операторов Java.
Java предоставляет довольно много операторов . На практике мы часто используем разные операторы вместе. Поэтому важно понимать приоритет операторов Java. В противном случае мы можем получить неожиданный результат.
Далее, давайте посмотрим на правило приоритета операторов Java (чем выше в таблице стоит оператор, тем выше его приоритет):
| Операторы | Приоритет |
| постфикс | `выражение ++ выражение —` |
| унарный | `++ выражение — выражение + выражение — выражение ~ !` |
| мультипликативный | `* / %` |
| добавка | `+ –` |
| сдвиг | `<< >> >>>` |
| относительный | `< > <= >= instanceof` |
| равенство | `== !=` |
| побитовое И | `&` |
| побитовое исключающее ИЛИ | `^` |
| побитовое включительно ИЛИ | `|` |
| логическое И | `&&` |
| логическое ИЛИ | `||` |
| троичный | `? :` |
| назначение | `= += -= *= /= %= &= ^= |= <<= >>= >>>=` |
Как видно из приведенного выше списка, оператор по модулю (%) имеет более высокий приоритет, чем оператор равенства ( ==
) . С другой стороны, побитовый оператор И (&) находится ниже оператора равенства (==) в таблице.
Вот почему « i % 2 == 1
» работает, как и ожидалось, а « i & 1 == 1
» — нет.
В нашем примере мы столкнулись с ошибкой времени компиляции. Таким образом, мы можем обнаружить проблему относительно рано. Однако представьте, что некоторая реализация с ошибкой приоритета оператора компилируется, но выдает неверный результат. Поиск реальной причины проблемы может занять у нас много времени.
Итак, стоит помнить о правиле приоритета операторов Java.
4. Решение проблемы
Теперь, когда мы понимаем причину проблемы, ее устранение не является сложной задачей. Нам просто нужно добавить круглые скобки к операции побитового И:
if (i & 1 == 1) --> if ((i & 1) == 1)
После исправления, если мы запустим метод еще раз, мы увидим, что компилятор больше не жалуется, и мы получим ожидаемый результат:
1 is odd.
2 is even.
3 is odd.
4 is even.
5 is odd.
6 is even.
7 is odd.
5. Вывод
В этой быстрой статье мы проанализировали ошибку компиляции «неправильные типы операндов для бинарного оператора» на примере операции побитового И.
Кроме того, мы обсудили правило приоритета операторов Java.
Наконец, мы исправили проблему.