JavaRush /Java Blog /Random EN /Logical Operators in Java

Logical Operators in Java

Published in the Random EN group
Logical operations in Java.  Bitwise operations in Java - 1

Logical Operations in Java

Logical operations are performed using Boolean operators. Pardon the tautology, but this is exactly how things are. Basic logical operations (in programming and mathematics) can be applied to logical arguments (operands), and can also be used to form more complex expressions, similar to arithmetic operations on numbers. For example the expression:

(a | b) | (c < 100) & !(true) ^ (q == 5)
is a complex logical expression with four operands: (a | b), where аand bare type variables boolean (c < 100) (true) (q == 5) . In turn, a simple logical expression (a | b)also consists of two operand arguments. A logical operand is an expression that can be said to be true or false, true or false . In Java parlance, a Boolean operand is an expression of type booleanor Boolean, for example:
  • (2 < 1)— logical operand, its value is false
  • true- a logical operand whose value is obviously true
  • boolean a- can also be a logical operand, like Boolean a
  • int a = 2- is not a logical operand , it is just a variable of typeint
  • String a = "true"is also not a logical operand . This is a string whose text value is "true".
The following logical operations are available in Java:
  • Logical negation , also known NOTas inversion. In Java, it is indicated by the “ !” symbol before the operand. Applies to one operand.
  • Logical and , it is also ANDa conjunction. Indicated by a “ &” symbol between the two operands to which it is applied.
  • Logical or in Java , it is also - OR, it is also disjunction. In Java, it is indicated by the symbol “ |” between two operands.
  • Exclusive or , XOR, strict disjunction. In Java, it is indicated by the symbol “ ^” between two operands.
  • In Java, logical operators include the conditional or , denoted as ||, as well as the conditional and - &&.
Note: also in mathematical logic they consider the equivalence relation, in other words, equality. However, in Java, the equality operator==is not considered a logical operator. Attention! In Java, the logical operators&,|and^also apply to integers. In this case, they work slightly differently and are called bitwise (or bitwise) logical operators. About them - towards the end of the article. Let's look at a table with a brief description of each of the Java logical operators, and below we will describe them in more detail and provide code examples.
Java operator Name Type Short description Example
! Logical “not” (negation) Unary !xmeans “not x”. Returns true if the operand is false . Returns false if the operand is true . boolean x = true;
Then
// !x == false
& Logical AND ( AND, multiplication) Binary Returns true if both operands are true . a = true;
b = false;
Then
a & b == false
| Logical OR ( OR, addition) Binary Returns true if at least one of the operands is true . a = true;
b = false;
Then
a | b == true
^ Logical exclusive OR ( XOR) Binary Returns true if one and only one of the operands is true . Returns false if both operands are true or false . Essentially, it returns true if the operands are different. a = true;
b = false;
Then
a ^ b == true
&& Conditional AND (short logical AND) Binary Same as , &but if the operand to the left of &is false , this operator returns false without checking the second operand.
|| Conditional OR (short logical OR) Binary Same as , |but if the operator on the left is true , the operator returns true without checking the second operand.

Logical operations in the JavaRush course

There is no escape from logical operations, and in the JavaRush course they appear from the first levels, along with conditions and the boolean data type. Programmers gradually learn to use the methods of mathematical logic. For more confident manipulations with logical constructions, certain dexterity and understanding of certain processes are required. So these operations are approached in more detail and at a completely different level at the end of the Multithreading quest, when most students are no longer too distracted directly by the syntax and constructions, but try to delve into the essence of the task.

Logical operations in Java.  Bitwise operations in Java - 2

Logical negation operator !

This operator is unary, meaning it applies to a single Boolean expression or operand. It is very simple to understand, like any negation: the operator simply changes the meaning of the expression to its opposite. Truth table or results of performing a negation operation:
The value of a !a
false true
true false
Example. Logical negation operation
public class Solution {
   public static void main(String[] args) {
       boolean a = true;
       System.out.println(!a); // here our boolean expression reverses its value
       System.out.println(!false); // non-false expression, as you might guess, will be equal to... what?
       System.out.println(!(2 < 5)); // expression (2 < 5) is true, so its negation is false

   }
}
The output of the program will be as follows:

false
true
false

Logical AND - &, as well as conditional AND - &&

Logical AND or conjunction is applied to two expressions, and its result will be true only if both operands are true. That is, if one of the aor operands bis false , then the expression a & bwill be false regardless of the value of the second operator. If you imagine that true is the number 1 and false is 0, then the operator &works exactly the same as normal multiplication. Therefore, logical AND is often called “logical multiplication.” And, by the way, this fact helps to quickly remember the operation of the operator &and not confuse it with the logical or operator |. Truth table AND, it is also the result of the operator’s work&
a b a&b
true true true
true false false
false true false
false false false
Logical AND, it is also a conjunction, examples:
public class Solution {
   public static void main(String[] args) {
       boolean a = true;
       boolean b = false;
       boolean c = true;
       System.out.println(a & b); // if we multiply true by false, we will definitely get false
       System.out.println(a & c); // true to true will be true
       System.out.println(false & (2 > 5));
 System.out.println((2 < 5) & false);
 // regardless of the truthfulness of the expression in brackets, in which case we have to be content with false
   }
}
Result of the program:

false
true
false
false
The operator &&is sometimes called “short AND”. It produces the same result when working with logical operands as the operator &. However, there is a difference in his work itself. So, you have already noticed that if a & bthe operand in the expression ( ) ais false , then it makes no sense to check the value of the operand b: the result of the operation will definitely be false . So if we don’t fundamentally need the value of the second operand, using it &&we reduce the number of calculations in the program. If we replace all the operators in the example &with &&, the result will be exactly the same, but the program itself will run a little faster (though we won’t notice this, since we are talking about mili-micro... in short, very small units of time).

Logical OR is the operator |, as well as conditional OR is the operator ||

The OR operator in Java is represented by the symbol |. A logical OR or disjunction is applied to two expressions, and its result will be false if and only if both operands are false. Here we to some extent observe the same picture as in the case of the operator &, but exactly the opposite. That is, if at least one operand is true , then the expression a | bis guaranteed to be true regardless of the value of the second operator. If &it behaves like logical multiplication, then OR is logical addition, if you imagine that true is 1 and false is 0. Just remember that logical addition works differently than normal addition. 1 + 1 in this case is equal not to 2, but to 1 (the number 2 simply does not exist in this system). Sometimes disjunction is understood as the maximum of 0 and 1, and in this case, if at least one operand is equal to 1 ( true ), we get exactly true . OR truth table, also known as the result of the operator |:
a b a | b
true true true
true false true
false true true
false false false
Logical OR, also known as disjunction, example:
public class Solution {
   public static void main(String[] args) {
       boolean a = true;
       boolean b = false;
       boolean c = true;
       System.out.println(!a | b); // Compose the use of two logical operators: a == true, so !a, as we already know, is false.
       System.out.println(a | c);
       System.out.println((2 < 5) | false); // expression (2 < 5) is true, which means that for any second operand we get a true result
       System.out.println((2 > 5) | true);

   }
}
Result:

false
true
true
true
If we use the conditional OR operator - ||instead of |, we will get exactly the same result, but, as in the case of conditional AND &&, it will act economically: if we “run into” the first operand equal to true , the value of the second operand is not checked, but immediately the result is true .

XOR Java - logical exclusive OR - operator ^

XOR, modulo 2 addition, logical XOR, logical subtraction, strict disjunction, bitwise complement... the operator ^has many names in Boolean algebra. The result of applying this operator to two operands will be true if the operands are different and false if the operands are the same. Therefore, it is convenient to compare it with subtracting zeros ( false ) and ones ( true ). Truth table XOR, also known as the result of the operator ^:
Boolean a Boolean b a^b
true true false
true false true
false true true
false false false
Example:
public class Solution {
   public static void main(String[] args) {
       boolean a = true;
       boolean b = false;
       boolean c = true;
       System.out.println(!a ^ b); // Compose the use of two logical operators: a == true, so !a, as we already know, is false.
       System.out.println(a ^ c);
       System.out.println((2 < 5) ^ false);
       System.out.println((2 > 5) ^ true);
   }
}
Result:

false
false
true
true

Priority of logical operations

Just like in mathematics, in programming operators have a specific execution order when they appear in the same expression. Unary operators have advantages over binary ones, and multiplication (even logical) over addition. We have ranked logical operators higher in the list, the higher their priority:
  1. !
  2. &
  3. ^
  4. |
  5. &&
  6. ||
Let's look at examples. Conjunction and disjunction ( &and |) have different precedence:
public class Solution {
   public static void main(String[] args) {
       boolean a = true, b = true, c = false;
       System.out.println(a | b & c);
}
If we were to proceed from left to right, that is, to first apply the operator |and then - &, we would get the value false . But in fact, if you run this program, you will be sure that the output will be true , since the logical AND operator &will have higher priority than the logical OR operator |. To avoid confusion, you need to remember that what &behaves like multiplication and |what behaves like addition. You can change the priority order. Just use brackets, just like in school math. Let's change our example code a little:
public class Solution {
   public static void main(String[] args) {
       boolean a = true, b = true, c = false;
       System.out.println((a|b)&c);
}
Whats up? First we use logical addition in brackets, and then multiplication. The result will be false .

Complex logical expressions

Of course, we can combine Boolean expressions and operators. Let's remember the expression from the beginning of the article:
(a | b) | (c < 100) & !(true) ^ (q == 5)
Now it doesn't look so scary. Let's write a program that displays its value, having previously determined the values ​​of a, b, сand q. Example of calculating the value of a complex Boolean expression
public class Solution {
   public static void main(String[] args) {
       boolean a = true;
       boolean b = false;
       int c = 25;
       int q = 2;
       System.out.println((a|b) | (c < 100) & !(true)^(q == 5));
   }
}
Note:qour variable is of type int, but q == 5this is a Boolean expression, and it is equal to false , since above we initialized with qthe number 2. The same is with the variable c. This number is equal to 25, but (c < 100) is a Boolean expression equal to true . The result of this program:

true
Complex Boolean expressions can be used to test very complex and branchy conditions, but they should not be overused: they make the code difficult to read.

Bitwise (bitwise) operators

At the beginning of the article, we mentioned that the operators &, |and ^can be used in relation to Java integer types. In this case they are bitwise operators. They are also called bitwise, since one digit is one bit, and these operations work specifically with bits. Of course, they work somewhat differently than logical operators, and to understand exactly how, you need to know what a binary number system is. If you don’t know anything about it or have completely forgotten, we suggest you first read the article Java: bits and bytes , and remind everyone else that in the binary number system there are only two digits - 0 and 1, and all data in the computer is represented precisely with using conditional zeros and ones. Any of the numbers we are used to (decimal; for them there are 10 different digits from 0 to 9, with which we write any numbers) can be represented in the binary number system. You can convert a decimal number to binary using sequential division into a column using the number system base (2). The remainders of the division at each step, written in reverse order, will give us the desired binary number. Here, for example, is the conversion of the decimal number 103 into binary representation: Logical operations in Java.  Bitwise operations in Java - 3

Binary number system in the JavaRush course

In the JavaRush course, they talk about the binary number system while studying the MultiThreading quest (level 10, lecture 1); after the lecture there are several tasks for consolidation. However, this topic is not at all difficult, and even if you haven't gotten that far in the course yet, you'll likely figure it out.

In addition to &, |and ^Java also uses bitwise operators:
  • ~ bitwise negation operator
  • >>bitwise shift right
  • >>>unsigned bitwise right shift
  • <<bitwise shift left
To beginners, bitwise operators seem very confusing and artificial. They most often do not understand what they are needed for, except for solving educational problems. In fact, they can be used at a minimum to organize efficient division and multiplication, and professionals use them for encoding/decoding, encryption, and generating random numbers.

Bitwise operators &, | and ^

Let's look at an example of how these operators work. Let's say we have two integers:
int a = 25;
int b = 112; 
We need to apply three operations to them &, |and ^display the result on the screen. Here is the program code:
public class Solution {
   public static void main(String[] args) {

       int a = 25;
       int b = 112;

       int res1 = a & b;
       int res2 = a | b;
       int res3 = a ^ b;

       System.out.println("a & b = " + res1);
       System.out.println("a | b = " + res2);
       System.out.println("a ^ b = " + res3);

   }
}
The result of the program is as follows:

a & b = 16
a | b = 121
a ^ b = 105
If you don’t understand what’s happening, the result looks very, very mysterious. In fact, everything is simpler than it seems. Bitwise operators “see” the operand numbers in their binary form. And then they apply logical operators &, |or ^to the corresponding digits (bits) of both numbers. So, for &the last bit of the binary representation of the number 25 logically adds up to the last bit of the binary representation of the number 112, the penultimate bit with the penultimate one, and so on: Logical operations in Java.  Bitwise operations in Java - 4The same logic can be traced in the case of |and ^. Logical operations in Java.  Bitwise operations in Java - 5

Bit shift left or right

There are several bit shift operators in Java. The most commonly used operators <<are and >>. They shift the binary representation of a number to the left or right, respectively, and in the case of a shift to the right, while preserving the sign (we’ll explain what preserving the sign means below). There is another right shift operator >>>. It does the same thing but >>does not save the sign. So, let's look at their work using an example. int a = 13 a << 1shifts all bits of the binary representation of the number a to the left by 1 bit. To simplify, let's imagine the number 13 in binary as 0000 1101. In fact, this number looks like this: 00000000 00000000 00000000 00001101, since Java intallocates 4 bytes or 32 bits for numbers. However, this does not play a role in the example, so in this example we will consider our number to be one-byte. Logical operations in Java.  Bitwise operations in Java - 6The bit vacated on the right is filled with zeros. As a result of this operation, we get the number 26. a << 2It shifts all the bits of the binary representation of the number ato the left by 2 bits, and the two bits vacated on the right are filled with zeros. As a result, we will get the number 52. a << 3The result will be 104... Notice the pattern? Bitwise shifting aleft by n positions works like multiplying a number aby 2 to the power of n. The same applies to negative numbers. This -13 << 3will give the result -104. a >> nshifts the binary representation of a number n positions to the right. For example, 13 >> 1 Transforms the number 1101 into the number 0110, that is, 6. And 13 >> 2the result will be 3. That is, in essence, here we divide the number by 2 to the power of n, where n is the number of shifts to the right, but with one caveat: if the number is odd , during this operation we seem to reset the last bit of the number. But with negative ones the situation is somewhat different. Let's say, try to check what the program will produce if you ask it to perform an operation -13 >> 1. You will see the number -7, not -6, as you might think. This happens due to the way negative numbers are stored in Java and other programming languages. They are stored in what is called complementary code. In this case, the most significant digit (the one on the left) is given under the sign. In the case of a negative number, the most significant digit is 1.

Additional code

Let's consider the number int a = 13. If in the program you print its binary representation to the console using the command System.out.println(Integer.toBinaryString(a));, then we will get 1101. In fact, this is a shorthand notation, since the type number inttakes up 4 bytes in memory, so the computer “sees” it more like this:

00000000 00000000 00000000 00001101
The most significant digit is zero, which means we have a positive number. To translate into additional code:
  1. We write the number -13 in the so-called “direct code”. To do this, change the most significant digit of the number to 1.
    Result of the action:

    
    10000000 0000000 0000000 00001101
  2. Next, we invert all the bits (we change 0 to 1, and 1 to 0) except the sign bit. In fact, we have already changed it.
    Result of the action:

    
    11111111 11111111 11111111 11110010

    (yes, steps 1 and 2 could be combined, but it’s better to think of it that way)

  3. Add 1 to the resulting number.
    Result of the action:

    
    11111111 11111111 11111111 11110011
The resulting binary number is -13, written in two's complement code, and the bit shift (and other operations) will be applied specifically to it. It’s just that the difference in the logic of operation is not noticeable in all operations. Let's say, for the same shift to the left, the difference is unnoticeable; we can work with negative numbers in the same way as with positive numbers. Now let's shift right -13 >> 1. Since our operator >>preserves the sign, in this operation all the bits freed on the left are filled not with zeros, but with ones. Thus, shifting the number

11111111 11111111 11111111 11110011
one bit to the right, resulting in the following sequence of bits:

11111111 11111111 11111111 11111001
If we convert this number into direct code (that is, first subtract 1, then invert all bits except the first) we get the number:

10000000 00000000 00000000 00000111
or -7. Now that we have understood the sign-preserving right shift operator, it will become clear how it differs from the operator >>>. a >>> n— this operation is an unsigned shift, that is, it shifts the binary representation of a number ato the right by n bits, but fills the n bits vacated on the left not with ones, like the operator >>, but with zeros. Let's do the operation -13 >>> 1. We already have the number -13in two's complement:

11111111 11111111 11111111 11110011
By shifting to the right by 1 bit and filling the free bit with zero, we get the following number:

01111111 11111111 11111111 11111001
What gives the number in decimal notation 2147483641.

Bitwise negation operator ~

This unary operator works very simply: it reverses each bit of the binary representation of an integer. Let's take the number -13:

11111111 11111111 11111111 11110011
The bitwise negation operation ~13will simply reverse the value of each bit. As a result we get:

00000000 00000000 00000000 00001100
Or 12in decimal form.

Brief conclusions

  • All logical operators apply to Boolean expressions, that is, those that can be said to be true or false .
  • If the operators &, |or ^are applied to numbers, we are no longer talking about logical operations, but about bitwise ones. That is, both numbers are converted into the binary system and the operations of logical addition, multiplication or subtraction are applied to these numbers bit by bit.
  • In mathematical logic, the operators &and |correspond to conjunction and disjunction.
  • Logical AND is similar to multiplying 1 ( true ) and 0 ( false ).
  • Logical OR is similar to finding the maximum among 1 ( true ) and 0 ( false ).
  • For the bitwise negation of an integer a, the operator is used ~a.
  • To logically negate a Boolean expression a, use the operator !a.
  • Negative numbers are stored and processed in two's complement code.
  • A bitwise shift to the right may >>or may not preserve the sign ( >>>).
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION