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

Logical operators in Java

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

Boolean operations in Java

Logical operations are performed using logical operators. Forgive the tautology, but that's how things are. Basic logical operations (in programming and mathematics) can be applied to logical arguments (operands), as well as more complex expressions, like 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 boolean operand is an expression that can be said to be true or false, true or false . In Java language, a boolean operand is an expression of type booleanor Boolean, for example:
  • (2 < 1)- logical operand, its value is false
  • trueis a boolean 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 boolean operand . This is a string whose text value is "true".
The following logical operations are available in Java:
  • Logical negation , it is the same NOTor inversion. In Java, it is denoted by the character “ !” in front of the operand. Applies to one operand.
  • Logical and , it is ANDor conjunction. Indicated by the symbol “ &” between the two operands to which it applies.
  • Boolean or in Java , it is - OR, it is also a disjunction. In Java, denoted by the symbol “ |” between two operands.
  • Exclusive or , XOR, strict disjunction. In Java, denoted 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, the equivalence relation is considered, in other words, equality. However, in Java, the equality operator==is not commonly referred to as boolean. Attention! In Java, the logical operators&, ,|and^apply to integers as well. In this case, they work a little 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 give 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 XOR ( XOR) Binary Returns true if one and only one of the operands is true . Returns false if both operands are true or false . Essentially returns true if the operands are different. a = true;
b = false;
Then
a ^ b == true
&& Conditional AND (abbreviated 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 (abbreviated logical OR) Binary Same as but |if the operator on the left is true , the operator returns true without checking the second operand.

Boolean operations in CodeGym course

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

Boolean operations in Java.  Bitwise Operations in Java - 2

The logical negation operator !

This operator is unary, meaning it applies to a single Boolean expression or operand. It is very simple to understand it, like any negation: the operator simply changes the value of the expression to the opposite. The truth table or the results of the negation operation:
Value 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 the following:

false
true
false

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

A logical AND or conjunction is applied to two expressions, and the result of its operation will be true ( 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 a 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 to confuse it with the logical or operator |. Truth table AND, it is also the result of the work of the operator&
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
   }
}
The result of the program:

false
true
false
false
The operator &&is sometimes referred to as the "abbreviated 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 in the expression ( a & b) the operand ais equal to 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 do not fundamentally need the value of the second operand, with the help &&we reduce the number of calculations in the program. If we replace all operators in the example &with&&, the result of the work will be exactly the same, but the program itself will run a little faster (although we will not notice this, since we are talking about mi-micro ... in short, about very small units of time).

Logical OR - operator |, as well as conditional OR - operator ||

The OR operator in Java is denoted by the symbol |. A logical OR or disjunction is applied to two expressions, and the result of its operation will be false ( false ) if and only if both operands are false. Here, to some extent, we 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 a logical multiplication, then OR is a logical addition, if you imagine that true is 1 and false- 0. Just remember that logical addition does not work like normal addition. 1 + 1 in this case is not equal to 2, but 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 . The truth table OR, it is also the result of the operation of the operator |:
a b a | b
true true true
true false true
false true true
false false false
Logical OR, it is also 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 apply the conditional OR operator - ||instead of |, we will get exactly the same result, but, as in the case of conditional AND &&, it will act sparingly: 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 - Boolean XOR - 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 the subtraction of zeros ( false ) and ones ( true ). Truth table XOR, it is also the result of the operation 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

Precedence of logical operations

As in mathematics, in programming, operators have a certain order of execution if they occur in the same expression. Unary operators have advantages over binary ones, and multiplication (even logical) over addition. We have arranged logical operators in the list of topics higher, the higher their precedence:
  1. !
  2. &
  3. ^
  4. |
  5. &&
  6. ||
Consider 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 act from left to right, that is, first apply the operator |and then - &, we would get the value false . But in fact, if you run this program, then make sure that the output is true , because the logical AND operator &will have higher precedence than the logical OR operator |. In order not to get confused, you need to remember that &it behaves like a multiplication, but |like an addition. You can change the order of priority. Just use parentheses, just like in high school math. Let's change our example code a bit:
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 apply logical addition in brackets, and then multiplication. The result will be false .

Complex Boolean Expressions

Of course, we can combine logical expressions and operators. Recall 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 prints its value, having previously determined the values a​​, b, сand q. An example of calculating the value of a complex logical 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:qwe have a variable of type int, but this q == 5is a Boolean expression, and it is equal to false , since we initialized it with qthe number 2 above. The same is with the variable c. This number is 25, but (c < 100) is a boolean expression that evaluates to true . The output of this program:

true
Complex logical expressions can be used to test very confusing and branching conditions, but they should not be abused: they make the code difficult to read.

Bitwise (bitwise) operators

At the beginning of the article, we mentioned that the &, |and operators ^can be used with Java integer types. In this case, they are bitwise operators. They are also called bitwise, because one bit is one bit, and these operations operate on bits. Of course, they work a little differently than logical operators, and in order to understand exactly how, you need to know what a binary (binary) number system is. If you do not know anything about it or have completely forgotten, we suggest that you first read the article Java: bits and bytes, and we 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 the help of conditional zeros and ones. Any of the numbers familiar to us (decimal; for them there are 10 different digits from 0 to 9, with which we write any numbers) is representable in the binary number system. You can convert a decimal number to binary using sequential division into a column on the basis of the number system (2). The remainder of the division at each step, written in reverse order, will give us the binary number we are looking for. Here, for example, is the translation of the decimal number 103 into binary representation: Boolean operations in Java.  Bitwise Operations in Java - 3

Binary number system in CodeGym course

In the CodeGym course, they talk about the binary number system while studying the MultiThreading quest (level 10, 1 lecture), after the lecture there are several tasks for fixing. However, this topic is not difficult at all, and even if you have not yet gone through the course that far, most likely you will understand it.

In addition to &, |and ^Java also uses bitwise operators:
  • ~ bitwise negation operator
  • >>bit shift right
  • >>>unsigned bitwise right shift
  • <<bitwise left shift
For 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 least to organize efficient division and multiplication, and professionals use them for encoding / decoding, encryption, random number generation.

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 ^and display the result. 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 output of the program is the following:

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

Bit shift left or right

There are several bitwise 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, the sign is preserved (what sign preservation means, we will describe below). There is another right shift operator >>>. It does the same as but >>does not save the sign. So, let's look at their work with an example. int a = 13 a << 1shifts all bits of the binary representation of a to the left by 1 bit. To simplify, let's represent the number 13 in binary form as 0000 1101. In fact, this number looks like this:intJava allocates 4 bytes or 32 bits. However, this does not play a role in the example, so in this example we will think our number is one-byte. Boolean operations in Java.  Bitwise Operations in Java - 6The freed bit on the right is filled with zeros. As a result of such an operation, we get the number 26. a << 2shifts all the bits of the binary representation of the number ato the left by 2 bits, and the two bits freed on the right are filled with zeros. As a result, we will get the number 52. a << 3It will give the result 104 ... Have you noticed a pattern? A bitwise left shift aby n positions works like multiplying a number aby 2 to the power of n. The same goes for negative numbers. This -13 << 3will give the result -104. a >> nshifts the binary representation of a number n places to the right. For example, 13 >> 1 Turns the number 1101 into the number 0110, that is, 6. A13 >> 2will give 3 as a result. That is, in fact, 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 nuance: if the number is odd, we kind of reset the last bit of the number during this operation. But with the negative, the situation is somewhat different. Let's say try to check what the program will produce if you ask it to perform the operation -13 >> 1. You will see the number -7, not -6 as you might think. This is due to the nature of storing negative numbers in Java and other programming languages. They are stored in the so-called additional 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 a number int a = 13. If in the program you output its binary representation to the console using the command System.out.println(Integer.toBinaryString(a));, then we will get 1101. In fact, this is an abbreviation, since the number of the type inttakes 4 bytes in memory, so the computer “sees” it, rather like this:

00000000 00000000 00000000 00001101
The most significant digit is zero, which means that we have a positive number. To convert to two's complement:
  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.
    The result of the action:

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

    
    11111111 11111111 11111111 11110010

    (yes, steps 1 and 2 could be combined, but it's better to represent it that way)

  3. We add 1 to the resulting number.
    The result of the action:

    
    11111111 11111111 11111111 11110011
The resulting binary number is -13, written in the two's complement code, and the bitwise shift (and other operations) will be applied to it. It's just that the difference in the logic of work is not noticeable in all operations. Let's say for the same shift to the left the difference is imperceptible, we can work with negative numbers in the same way as with positive numbers. Now let's shift to the right -13 >> 1. Since our operator >>is sign-preserving, 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 translate this number into a direct code (that is, first subtract 1, then invert all bits except the first), we get a number:

10000000 00000000 00000000 00000111
or -7. Now that we have dealt with 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 that are freed on the left not with ones, like the operator >>, but with zeros. Let's do the operation -13 >>> 1. We already have a number -13in two's complement:

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

01111111 11111111 11111111 11111001
What is the number in decimal representation 2147483641.

Bitwise negation operator ~

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

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

00000000 00000000 00000000 00001100
Or 12in decimal.

Brief conclusions

  • All logical operators apply to boolean expressions, that is, expressions 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 to 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 like multiplying 1 ( true ) and 0 ( false ).
  • Logical OR is like finding the maximum between 1 ( true ) and 0 ( false ).
  • To bitwise negate an integer a, the operation is used ~a.
  • The operation is used to logically negate the Boolean expression a !a.
  • Negative numbers are stored and processed in two's complement.
  • A bitwise right shift may >>or may not preserve the sign ( >>>).
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION