Operadores aritméticos, relacionales y lógicos
Introducción
Los operadores son símbolos especiales que realizan operaciones sobre uno, dos o más operandos (valores o variables). Son fundamentales en cualquier lenguaje de programación, ya que nos permiten manipular datos, realizar cálculos y tomar decisiones en nuestros programas. Java dispone de un conjunto completo de operadores que podemos clasificar en diferentes categorías según su función: aritméticos, relacionales, lógicos, de asignación, entre otros. En este artículo, exploraremos en detalle los operadores aritméticos, relacionales y lógicos, aprendiendo cómo utilizarlos correctamente en nuestros programas Java para realizar cálculos y tomar decisiones basadas en condiciones.
Operadores aritméticos
Los operadores aritméticos nos permiten realizar operaciones matemáticas básicas como suma, resta, multiplicación y división. Java proporciona los siguientes operadores aritméticos:
Operadores aritméticos básicos
Operador | Descripción | Ejemplo |
---|---|---|
+ |
Suma | a + b |
- |
Resta | a - b |
* |
Multiplicación | a * b |
/ |
División | a / b |
% |
Módulo (resto de la división) | a % b |
Veamos algunos ejemplos de cómo utilizar estos operadores:
public class OperadoresAritmeticos {
public static void main(String[] args) {
int a = 10;
int b = 3;
// Operaciones básicas
int suma = a + b;
int resta = a - b;
int multiplicacion = a * b;
int division = a / b;
int modulo = a % b;
System.out.println("Suma: " + suma); // Resultado: 13
System.out.println("Resta: " + resta); // Resultado: 7
System.out.println("Multiplicación: " + multiplicacion); // Resultado: 30
System.out.println("División: " + division); // Resultado: 3
System.out.println("Módulo: " + modulo); // Resultado: 1
}
}
Es importante tener en cuenta algunas consideraciones especiales:
- División entre enteros: Cuando dividimos dos números enteros en Java, el resultado es otro número entero (se trunca la parte decimal). Si queremos obtener un resultado con decimales, al menos uno de los operandos debe ser de tipo
float
odouble
.
int a = 10;
int b = 3;
int divisionEntera = a / b; // Resultado: 3
double divisionDecimal = a / (double)b; // Resultado: 3.3333...
System.out.println("División entera: " + divisionEntera);
System.out.println("División decimal: " + divisionDecimal);
- El operador módulo
%
: Este operador devuelve el resto de la división entre dos números. Es muy útil para determinar si un número es divisible por otro (el resultado será 0) o para operaciones cíclicas.
// Comprobar si un número es par
int numero = 15;
boolean esPar = (numero % 2 == 0);
System.out.println(numero + " es par: " + esPar); // Resultado: 15 es par: false
Operadores de incremento y decremento
Java proporciona operadores especiales para incrementar o decrementar una variable en una unidad:
Operador | Descripción | Ejemplo |
---|---|---|
++ |
Incremento | a++ o ++a |
-- |
Decremento | a-- o --a |
Estos operadores pueden utilizarse en dos formas:
- Prefijo (
++a
,--a
): Primero se incrementa/decrementa la variable y luego se utiliza su valor. - Sufijo (
a++
,a--
): Primero se utiliza el valor actual de la variable y luego se incrementa/decrementa.
Veamos la diferencia con un ejemplo:
public class OperadoresIncrementoDecremento {
public static void main(String[] args) {
int a = 5;
int b;
// Incremento en sufijo
b = a++; // b = 5, después a se incrementa a 6
System.out.println("Después de b = a++: a = " + a + ", b = " + b);
// Reiniciamos a
a = 5;
// Incremento en prefijo
b = ++a; // a se incrementa a 6, después b = 6
System.out.println("Después de b = ++a: a = " + a + ", b = " + b);
// Reiniciamos a
a = 5;
// Decremento en sufijo
b = a--; // b = 5, después a se decrementa a 4
System.out.println("Después de b = a--: a = " + a + ", b = " + b);
// Reiniciamos a
a = 5;
// Decremento en prefijo
b = --a; // a se decrementa a 4, después b = 4
System.out.println("Después de b = --a: a = " + a + ", b = " + b);
}
}
Operadores aritméticos combinados con asignación
Java también proporciona operadores combinados que realizan una operación aritmética y una asignación en un solo paso:
Operador | Equivalente | Ejemplo |
---|---|---|
+= |
a = a + b |
a += b |
-= |
a = a - b |
a -= b |
*= |
a = a * b |
a *= b |
/= |
a = a / b |
a /= b |
%= |
a = a % b |
a %= b |
Estos operadores son útiles para escribir código más conciso:
public class OperadoresCombinados {
public static void main(String[] args) {
int a = 10;
// Operaciones combinadas
a += 5; // a = a + 5, ahora a = 15
System.out.println("Después de a += 5: a = " + a);
a -= 3; // a = a - 3, ahora a = 12
System.out.println("Después de a -= 3: a = " + a);
a *= 2; // a = a * 2, ahora a = 24
System.out.println("Después de a *= 2: a = " + a);
a /= 4; // a = a / 4, ahora a = 6
System.out.println("Después de a /= 4: a = " + a);
a %= 4; // a = a % 4, ahora a = 2
System.out.println("Después de a %= 4: a = " + a);
}
}
Operadores relacionales
Los operadores relacionales se utilizan para comparar dos valores y determinar la relación entre ellos. El resultado de una expresión relacional es siempre un valor booleano (true
o false
).
Operador | Descripción | Ejemplo |
---|---|---|
== |
Igual a | a == b |
!= |
No igual a | a != b |
> |
Mayor que | a > b |
< |
Menor que | a < b |
>= |
Mayor o igual que | a >= b |
<= |
Menor o igual que | a <= b |
Veamos cómo utilizar estos operadores:
public class OperadoresRelacionales {
public static void main(String[] args) {
int a = 10;
int b = 20;
// Comparaciones
boolean iguales = (a == b);
boolean diferentes = (a != b);
boolean mayor = (a > b);
boolean menor = (a < b);
boolean mayorIgual = (a >= b);
boolean menorIgual = (a <= b);
System.out.println("a == b: " + iguales); // false
System.out.println("a != b: " + diferentes); // true
System.out.println("a > b: " + mayor); // false
System.out.println("a < b: " + menor); // true
System.out.println("a >= b: " + mayorIgual); // false
System.out.println("a <= b: " + menorIgual); // true
// Uso común en estructuras condicionales
if (a < b) {
System.out.println("a es menor que b");
} else {
System.out.println("a no es menor que b");
}
}
}
¡Importante! Para comparar objetos, especialmente cadenas (String
), no debemos usar el operador ==
ya que compara referencias de memoria, no el contenido. En su lugar, debemos usar el método equals()
:
String cadena1 = "Hola";
String cadena2 = "Hola";
String cadena3 = new String("Hola");
// Comparación incorrecta para contenido de cadenas
boolean comparacion1 = (cadena1 == cadena2); // Puede dar true por optimización del compilador
boolean comparacion2 = (cadena1 == cadena3); // Normalmente dará false
// Comparación correcta para contenido
boolean comparacion3 = cadena1.equals(cadena2); // true
boolean comparacion4 = cadena1.equals(cadena3); // true
System.out.println("cadena1 == cadena2: " + comparacion1);
System.out.println("cadena1 == cadena3: " + comparacion2);
System.out.println("cadena1.equals(cadena2): " + comparacion3);
System.out.println("cadena1.equals(cadena3): " + comparacion4);
Operadores lógicos
Los operadores lógicos se utilizan para combinar expresiones booleanas y realizar operaciones de lógica booleana. Java proporciona los siguientes operadores lógicos:
Operador | Descripción | Ejemplo |
---|---|---|
&& |
AND lógico | a && b |
|| |
OR lógico | a || b |
! |
NOT lógico | !a |
Veamos cómo funcionan estos operadores:
Operador AND (&&
)
El operador AND devuelve true
solo si ambas expresiones son true
:
a | b | a && b |
---|---|---|
true | true | true |
true | false | false |
false | true | false |
false | false | false |
boolean condicion1 = true;
boolean condicion2 = false;
boolean resultadoAnd = condicion1 && condicion2;
System.out.println("condicion1 && condicion2: " + resultadoAnd); // false
// Ejemplo práctico: verificar si un número está en un rango
int numero = 15;
boolean estaEnRango = (numero >= 10) && (numero <= 20);
System.out.println("¿El número " + numero + " está entre 10 y 20? " + estaEnRango); // true
Operador OR (||
)
El operador OR devuelve true
si al menos una de las expresiones es true
:
a | b | a || b |
---|---|---|
true | true | true |
true | false | true |
false | true | true |
false | false | false |
boolean condicion1 = true;
boolean condicion2 = false;
boolean resultadoOr = condicion1 || condicion2;
System.out.println("condicion1 || condicion2: " + resultadoOr); // true
// Ejemplo práctico: verificar si un número está fuera de un rango
int numero = 5;
boolean estaFueraDeRango = (numero < 10) || (numero > 20);
System.out.println("¿El número " + numero + " está fuera del rango 10-20? " + estaFueraDeRango); // true
Operador NOT (!
)
El operador NOT invierte el valor de una expresión booleana:
a | !a |
---|---|
true | false |
false | true |
boolean condicion = true;
boolean resultadoNot = !condicion;
System.out.println("!condicion: " + resultadoNot); // false
// Ejemplo práctico: verificar si un número no es par
int numero = 15;
boolean noPar = !(numero % 2 == 0);
System.out.println("¿El número " + numero + " no es par? " + noPar); // true
Evaluación de cortocircuito
Java utiliza la evaluación de cortocircuito para los operadores &&
y ||
. Esto significa:
- Para
&&
: Si la primera expresión esfalse
, la segunda expresión no se evalúa, ya que el resultado final seráfalse
independientemente. - Para
||
: Si la primera expresión estrue
, la segunda expresión no se evalúa, ya que el resultado final serátrue
independientemente.
Esto puede ser útil para evitar errores, como en el siguiente ejemplo:
public class EvaluacionCortocircuito {
public static void main(String[] args) {
int divisor = 0;
int numerador = 10;
// Sin cortocircuito, esto causaría una excepción de división por cero
// if (divisor != 0 & numerador / divisor > 2) { ... }
// Con cortocircuito, la segunda parte no se evalúa si divisor es 0
if (divisor != 0 && numerador / divisor > 2) {
System.out.println("La condición se cumple");
} else {
System.out.println("La condición no se cumple o el divisor es 0");
}
}
}
Operadores lógicos de bits
Java también proporciona operadores lógicos a nivel de bits, que operan sobre los bits individuales de valores enteros:
Operador | Descripción | Ejemplo |
---|---|---|
& |
AND a nivel de bits | a & b |
| |
OR a nivel de bits | a | b |
^ |
XOR a nivel de bits | a ^ b |
~ |
NOT a nivel de bits | ~a |
<< |
Desplazamiento a la izquierda | a << b |
>> |
Desplazamiento a la derecha con signo | a >> b |
>>> |
Desplazamiento a la derecha sin signo | a >>> b |
Estos operadores son utilizados principalmente en programación de bajo nivel, manipulación de bits y situaciones donde se requiere optimización de memoria.
public class OperadoresBits {
public static void main(String[] args) {
int a = 5; // En binario: 0101
int b = 3; // En binario: 0011
// Operaciones a nivel de bits
int resultadoAnd = a & b; // 0101 & 0011 = 0001 (1 en decimal)
int resultadoOr = a | b; // 0101 | 0011 = 0111 (7 en decimal)
int resultadoXor = a ^ b; // 0101 ^ 0011 = 0110 (6 en decimal)
int resultadoNot = ~a; // ~0101 = 1010 con extensión de signo (-6 en decimal con complemento a 2)
System.out.println("a & b: " + resultadoAnd);
System.out.println("a | b: " + resultadoOr);
System.out.println("a ^ b: " + resultadoXor);
System.out.println("~a: " + resultadoNot);
// Desplazamientos
int desplazamientoIzq = a << 1; // 0101 << 1 = 1010 (10 en decimal)
int desplazamientoDer = a >> 1; // 0101 >> 1 = 0010 (2 en decimal)
System.out.println("a << 1: " + desplazamientoIzq);
System.out.println("a >> 1: " + desplazamientoDer);
}
}
Operador ternario
Java proporciona un operador ternario (también conocido como operador condicional), que es una forma abreviada de una instrucción if-else
:
expresión_condicional ? expresión_si_verdadero : expresión_si_falso
Este operador evalúa la expresión_condicional
; si es true
, el resultado es expresión_si_verdadero
, si es false
, el resultado es expresión_si_falso
.
public class OperadorTernario {
public static void main(String[] args) {
int edad = 17;
// Usando if-else
String mensaje;
if (edad >= 18) {
mensaje = "Eres mayor de edad";
} else {
mensaje = "Eres menor de edad";
}
System.out.println(mensaje);
// Equivalente usando operador ternario
mensaje = (edad >= 18) ? "Eres mayor de edad" : "Eres menor de edad";
System.out.println(mensaje);
// También se puede usar directamente en una expresión
System.out.println((edad >= 18) ? "Eres mayor de edad" : "Eres menor de edad");
// Ejemplo con asignación de valores
int descuento = (edad < 12) ? 50 : (edad >= 65) ? 40 : 10;
System.out.println("Tu descuento es del " + descuento + "%");
}
}
Precedencia de operadores
Cuando utilizamos múltiples operadores en una expresión, es importante entender el orden en que Java los evalúa. A continuación, se muestra la precedencia de los operadores en Java, de mayor a menor:
- Operadores postfijos:
expr++
,expr--
- Operadores unarios:
++expr
,--expr
,+expr
,-expr
,~
,!
- Multiplicación, división, módulo:
*
,/
,%
- Suma, resta:
+
,-
- Desplazamiento:
<<
,>>
,>>>
- Relacionales:
<
,>
,<=
,>=
,instanceof
- Igualdad:
==
,!=
- AND a nivel de bits:
&
- XOR a nivel de bits:
^
- OR a nivel de bits:
|
- AND lógico:
&&
- OR lógico:
||
- Operador ternario:
? :
- Asignación:
=
,+=
,-=
,*=
,/=
,%=
, etc.
Es recomendable usar paréntesis para hacer que el código sea más legible y para evitar confusiones:
public class PrecedenciaOperadores {
public static void main(String[] args) {
int a = 5, b = 3, c = 8;
// Sin paréntesis, la multiplicación tiene precedencia sobre la suma
int resultado1 = a + b * c; // 5 + (3 * 8) = 5 + 24 = 29
// Con paréntesis, cambiamos la precedencia
int resultado2 = (a + b) * c; // (5 + 3) * 8 = 8 * 8 = 64
System.out.println("a + b * c = " + resultado1);
System.out.println("(a + b) * c = " + resultado2);
// Ejemplo con operadores lógicos
boolean res1 = a > b && b < c; // (a > b) && (b < c) = true && true = true
boolean res2 = a > b || b > c; // (a > b) || (b > c) = true || false = true
System.out.println("a > b && b < c: " + res1);
System.out.println("a > b || b > c: " + res2);
}
}
Ejemplos prácticos
Ejemplo 1: Calculadora simple
import java.util.Scanner;
public class Calculadora {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Calculadora Simple");
System.out.println("------------------");
System.out.print("Introduce el primer número: ");
double num1 = scanner.nextDouble();
System.out.print("Introduce el segundo número: ");
double num2 = scanner.nextDouble();
System.out.println("Suma: " + (num1 + num2));
System.out.println("Resta: " + (num1 - num2));
System.out.println("Multiplicación: " + (num1 * num2));
// Evitamos la división por cero
if (num2 != 0) {
System.out.println("División: " + (num1 / num2));
System.out.println("Módulo: " + (num1 % num2));
} else {
System.out.println("No se puede dividir entre cero");
}
scanner.close();
}
}
Ejemplo 2: Verificación de requisitos para un préstamo
import java.util.Scanner;
public class VerificacionPrestamo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Sistema de verificación de préstamos");
System.out.println("------------------------------------");
System.out.print("¿Cuál es tu edad? ");
int edad = scanner.nextInt();
System.out.print("¿Cuál es tu salario mensual? ");
double salario = scanner.nextDouble();
System.out.print("¿Cuántos años llevas en tu empleo actual? ");
int antiguedad = scanner.nextInt();
// Verificamos requisitos
boolean edadSuficiente = edad >= 18;
boolean salarioSuficiente = salario >= 1000;
boolean antiguedadSuficiente = antiguedad >= 1;
// Utilizamos operadores lógicos para combinar condiciones
boolean cumpleRequisitos = edadSuficiente && (salarioSuficiente || antiguedadSuficiente);
// Operador ternario para mensaje
String mensaje = cumpleRequisitos
? "¡Felicidades! Cumples los requisitos para solicitar un préstamo."
: "Lo sentimos, no cumples los requisitos para un préstamo.";
System.out.println("\nResultado de la verificación:");
System.out.println("- Edad adecuada: " + edadSuficiente);
System.out.println("- Salario suficiente: " + salarioSuficiente);
System.out.println("- Antigüedad suficiente: " + antiguedadSuficiente);
System.out.println("\n" + mensaje);
scanner.close();
}
}
Ejemplo 3: Operaciones con bits para permisos
public class SistemaPermisos {
// Definimos constantes para permisos usando potencias de 2 (bits individuales)
static final int PERMISO_LECTURA = 1; // 001 en binario
static final int PERMISO_ESCRITURA = 2; // 010 en binario
static final int PERMISO_EJECUCION = 4; // 100 en binario
public static void main(String[] args) {
// Asignamos permisos: lectura y ejecución
int permisosUsuario = PERMISO_LECTURA | PERMISO_EJECUCION; // 001 | 100 = 101
System.out.println("Permisos del usuario: " + permisosUsuario);
// Verificamos si el usuario tiene permiso de lectura
boolean tienePermisoLectura = (permisosUsuario & PERMISO_LECTURA) != 0;
System.out.println("¿Tiene permiso de lectura? " + tienePermisoLectura);
// Verificamos si el usuario tiene permiso de escritura
boolean tienePermisoEscritura = (permisosUsuario & PERMISO_ESCRITURA) != 0;
System.out.println("¿Tiene permiso de escritura? " + tienePermisoEscritura);
// Añadimos permiso de escritura
permisosUsuario |= PERMISO_ESCRITURA; // 101 | 010 = 111
System.out.println("Permisos después de añadir escritura: " + permisosUsuario);
// Verificamos de nuevo el permiso de escritura
tienePermisoEscritura = (permisosUsuario & PERMISO_ESCRITURA) != 0;
System.out.println("¿Ahora tiene permiso de escritura? " + tienePermisoEscritura);
// Revocamos el permiso de ejecución
permisosUsuario &= ~PERMISO_EJECUCION; // 111 & ~100 = 111 & 011 = 011
System.out.println("Permisos después de revocar ejecución: " + permisosUsuario);
// Verificamos si aún tiene permiso de ejecución
boolean tienePermisoEjecucion = (permisosUsuario & PERMISO_EJECUCION) != 0;
System.out.println("¿Todavía tiene permiso de ejecución? " + tienePermisoEjecucion);
}
}
Resumen
En este artículo hemos explorado los operadores aritméticos, relacionales y lógicos en Java, herramientas fundamentales para manipular datos y tomar decisiones en nuestros programas. Hemos visto cómo realizar cálculos matemáticos con operadores aritméticos, comparar valores con operadores relacionales y combinar condiciones con operadores lógicos.
La comprensión adecuada de estos operadores y su precedencia es crucial para escribir código eficiente y libre de errores. Los operadores nos permiten construir expresiones complejas que son la base para las estructuras de control como condicionales y bucles, que veremos en próximos artículos. Dominar el uso de estos operadores te dará la capacidad de expresar lógica compleja de manera clara y concisa en tus programas Java.