🔍 ¿Qué son los operadores relacionales?
Los operadores relacionales (también llamados operadores de comparación) son símbolos que permiten comparar dos valores o expresiones entre sí. El resultado de toda operación relacional es siempre un valor de tipo boolean: true si la comparación se cumple, o false si no se cumple.
En la programación diaria con Java, los operadores relacionales son fundamentales porque constituyen la base de toda toma de decisiones. Cada vez que escribimos una sentencia if, un bucle while o una expresión ternaria, estamos usando —directa o indirectamente— uno o más operadores relacionales para determinar qué camino debe seguir el programa.
La estructura general de una expresión relacional es la siguiente:
expresión_1 operador_relacional expresión_2 → boolean (true / false)
Por ejemplo, la expresión (3 + 4) > 12 se evalúa como false, ya que 7 no es mayor que 12. En cambio, (3 + 4) < 12 devuelve true.
boolean. No se puede usar un entero como condición en un if: la expresión if (1) genera un error de compilación en Java.📊 Tabla resumen de operadores relacionales en Java
Java proporciona seis operadores relacionales. Todos ellos son operadores binarios (requieren dos operandos) y devuelven un resultado boolean:
| Operador | Nombre | Ejemplo | Resultado | Descripción |
|---|---|---|---|---|
== |
Igual a | 5 == 5 |
true |
Verdadero si ambos operandos tienen el mismo valor |
!= |
Distinto de | 5 != 3 |
true |
Verdadero si los operandos tienen valores diferentes |
> |
Mayor que | 7 > 3 |
true |
Verdadero si el operando izquierdo es mayor |
< |
Menor que | 3 < 7 |
true |
Verdadero si el operando izquierdo es menor |
>= |
Mayor o igual que | 5 >= 5 |
true |
Verdadero si el operando izquierdo es mayor o igual |
<= |
Menor o igual que | 3 <= 7 |
true |
Verdadero si el operando izquierdo es menor o igual |
>=, <=, !=) siempre llevan el signo = a la derecha, nunca a la izquierda. Escribir => o =< provoca un error de compilación.⚖️ Operador de igualdad (==)
El operador == devuelve true cuando ambos operandos tienen el mismo valor. Es, junto con !=, el operador relacional más utilizado en Java, ya que interviene en prácticamente toda estructura condicional.
▶️ Igualdad con tipos primitivos
Cuando se comparan tipos primitivos (int, double, char, boolean, etc.), el operador == compara directamente los valores almacenados:
int a = 10; int b = 10; int c = 20; System.out.println(a == b); // true → mismo valor System.out.println(a == c); // false → valores diferentes System.out.println(a == 10); // true → comparación con literal double precio = 9.99; System.out.println(precio == 9.99); // true char letra = 'A'; System.out.println(letra == 'A'); // true System.out.println(letra == 65); // true → 'A' tiene código Unicode 65
⚠️ Cuidado con la igualdad en punto flotante
Los números en punto flotante (float y double) tienen una precisión limitada, lo que puede producir resultados inesperados al compararlos con ==:
double resultado = 0.1 + 0.2; System.out.println(resultado); // 0.30000000000000004 System.out.println(resultado == 0.3); // false ← ¡sorpresa! // Solución: comparar con un margen de tolerancia (epsilon) final double EPSILON = 1e-9; System.out.println(Math.abs(resultado - 0.3) < EPSILON); // true
double o float directamente con == si proceden de operaciones aritméticas. La representación en coma flotante según el estándar IEEE 754 introduce pequeños errores de redondeo que hacen que comparaciones aparentemente obvias fallen. Usa siempre un valor épsilon.🔀 Operador de desigualdad (!=)
El operador != es el opuesto lógico de ==: devuelve true cuando los dos operandos no tienen el mismo valor, y false cuando sí lo tienen.
int intentos = 3;
int maxIntentos = 5;
System.out.println(intentos != maxIntentos); // true → 3 ≠ 5
System.out.println(intentos != 3); // false → 3 = 3
boolean activo = true;
System.out.println(activo != false); // true
// Uso típico en bucles: repetir mientras no se alcance el límite
while (intentos != maxIntentos) {
System.out.println("Intento " + intentos);
intentos++;
}
// Salida: Intento 3, Intento 4
En la práctica, != se utiliza con frecuencia para validar que una variable no contenga un valor prohibido, para comprobar que una referencia no sea null, o como condición de continuación en bucles.
a != b es lógicamente equivalente a !(a == b). Sin embargo, la forma directa con != es más legible y se considera mejor práctica.📐 Operadores mayor que (>) y menor que (<)
Estos operadores comparan la magnitud de dos valores numéricos. Devuelven true cuando la relación de orden se cumple, y false en caso contrario.
int edad = 25; // Mayor que System.out.println(edad > 18); // true → 25 es mayor que 18 System.out.println(edad > 25); // false → 25 NO es mayor que 25 (es igual) System.out.println(edad > 30); // false → 25 no es mayor que 30 // Menor que System.out.println(edad < 30); // true → 25 es menor que 30 System.out.println(edad < 25); // false → 25 NO es menor que 25 (es igual) System.out.println(edad < 18); // false → 25 no es menor que 18
🔹 Comparación de caracteres
En Java, los caracteres (char) se representan internamente como valores numéricos Unicode (UTF-16). Al compararlos con operadores relacionales, se comparan sus códigos numéricos:
// Códigos Unicode relevantes:
// '0'-'9' → 48-57 | 'A'-'Z' → 65-90 | 'a'-'z' → 97-122
char c1 = 'a'; // código 97
char c2 = 'A'; // código 65
char c3 = 'z'; // código 122
System.out.println(c1 > c2); // true → 97 > 65
System.out.println(c1 < c3); // true → 97 < 122
System.out.println('5' > '2'); // true → 53 > 50
// Verificar si un carácter es una letra minúscula
char letra = 'm';
boolean esMinuscula = (letra >= 'a' && letra <= 'z');
System.out.println(esMinuscula); // true
| Rango de caracteres | Códigos Unicode | Ejemplo |
|---|---|---|
Dígitos '0' a '9' |
48 – 57 | '5' tiene código 53 |
Mayúsculas 'A' a 'Z' |
65 – 90 | 'M' tiene código 77 |
Minúsculas 'a' a 'z' |
97 – 122 | 'm' tiene código 109 |
📏 Operadores mayor o igual (>=) y menor o igual (<=)
Estos operadores son versiones «inclusivas» de > y <. Devuelven true también cuando los operandos son iguales, lo cual los hace especialmente útiles para validar rangos y límites.
int nota = 5;
// Mayor o igual
System.out.println(nota >= 5); // true → 5 es igual a 5, se cumple
System.out.println(nota >= 4); // true → 5 es mayor que 4
System.out.println(nota >= 6); // false → 5 no es mayor ni igual que 6
// Menor o igual
System.out.println(nota <= 5); // true → 5 es igual a 5, se cumple
System.out.println(nota <= 10); // true → 5 es menor que 10
System.out.println(nota <= 4); // false → 5 no es menor ni igual que 4
// Caso práctico: validar que una nota esté en rango [0, 10]
boolean notaValida = (nota >= 0 && nota <= 10);
System.out.println("¿Nota válida? " + notaValida); // true
🔹 Diferencia clave entre > y >=
La diferencia parece sutil, pero tiene un impacto directo en la lógica de los programas. Observa este ejemplo donde una pequeña confusión cambia el resultado:
int edad = 18;
// ¿Es mayor de edad? Depende del operador elegido:
if (edad > 18) {
System.out.println("Mayor de edad"); // NO se imprime (18 no es > 18)
}
if (edad >= 18) {
System.out.println("Mayor de edad"); // SÍ se imprime (18 es >= 18)
}
>= o <=). Una confusión entre > y >= es una de las fuentes de bugs más comunes en programación, conocida como error off-by-one.🧩 Comparar objetos y Strings: == vs equals()
Esta sección aborda una de las fuentes de errores más frecuentes para quienes comienzan a programar en Java. Cuando se trabaja con objetos (incluidos los String), el operador == se comporta de manera diferente a como lo hace con tipos primitivos.
🔹 El operador == con objetos compara referencias
Con tipos primitivos, == compara valores. Pero con objetos, == compara si las dos variables apuntan al mismo objeto en memoria (la misma referencia), no si sus contenidos son iguales:
// Con String: == puede engañar
String s1 = new String("Hola");
String s2 = new String("Hola");
String s3 = s1;
System.out.println(s1 == s2); // false → objetos distintos en memoria
System.out.println(s1 == s3); // true → misma referencia
System.out.println(s1.equals(s2)); // true → mismo contenido "Hola"
// Pool de Strings (caso especial)
String s4 = "Hola";
String s5 = "Hola";
System.out.println(s4 == s5); // true → apuntan al mismo literal del pool
System.out.println(s4 == s1); // false → s1 se creó con new (fuera del pool)
🔹 La regla de oro para comparar Strings
equals() o equalsIgnoreCase(). Nunca uses == para comparar Strings, aunque parezca funcionar en algunos casos (por el pool de literales), porque fallará con Strings creados dinámicamente (con new, leídos de archivo, recibidos por teclado, etc.).String usuario = obtenerUsuarioDeBD(); // viene de una fuente externa
// ❌ INCORRECTO — puede fallar impredeciblemente
if (usuario == "admin") { ... }
// ✅ CORRECTO — compara el contenido real
if (usuario.equals("admin")) { ... }
// ✅ MEJOR — evita NullPointerException si usuario es null
if ("admin".equals(usuario)) { ... }
// ✅ Comparación sin distinguir mayúsculas/minúsculas
if ("admin".equalsIgnoreCase(usuario)) { ... }
🔹 Comparar otros objetos: equals() y compareTo()
La misma regla se aplica a cualquier objeto. Los operadores >, <, >=, <= no se pueden usar con objetos (error de compilación). Para establecer un orden entre objetos, Java ofrece dos mecanismos:
| Mecanismo | Interfaz | Método | Uso |
|---|---|---|---|
| Orden natural | Comparable<T> |
compareTo(T otro) |
La clase define su propio criterio de ordenación |
| Orden externo | Comparator<T> |
compare(T o1, T o2) |
Se define un criterio de ordenación sin modificar la clase |
// String implementa Comparable → se puede usar compareTo() String nombre1 = "Ana"; String nombre2 = "Carlos"; int comparacion = nombre1.compareTo(nombre2); // comparacion < 0 → nombre1 va antes que nombre2 (orden alfabético) // comparacion == 0 → son iguales // comparacion > 0 → nombre1 va después que nombre2 System.out.println(comparacion); // negativo → "Ana" < "Carlos"
🔄 Tipos compatibles en comparaciones
No todas las combinaciones de tipos pueden compararse con operadores relacionales. Java establece reglas claras de compatibilidad:
| Comparación | ¿Permitida? | Comportamiento |
|---|---|---|
int con int |
✅ Sí | Comparación directa de valores |
int con double |
✅ Sí | El int se promueve a double |
char con int |
✅ Sí | El char se promueve a int (valor Unicode) |
byte con long |
✅ Sí | El byte se promueve a long |
boolean con int |
❌ No | Error de compilación |
boolean con boolean |
Solo == y != |
No se puede usar >, <, >=, <= |
String con String |
Solo == y != |
Compara referencias (usar equals() para contenido) |
| Objeto con primitivo | ❌ No | Error de compilación (excepto autoboxing) |
🔹 Promoción automática de tipos (widening)
Cuando se comparan dos tipos numéricos diferentes, Java convierte automáticamente el tipo más pequeño al más grande antes de realizar la comparación. Esta conversión sigue la jerarquía:
byte → short → int → long → float → double
↑
char
int entero = 5; double decimal = 5.0; char letra = 'A'; // valor Unicode: 65 System.out.println(entero == decimal); // true → 5 se promueve a 5.0 System.out.println(letra > 60); // true → 65 > 60 System.out.println(letra == 65); // true → 'A' se promueve a int 65 // Caso especial con long y float long valorGrande = 123456789L; float valorFloat = 123456789.0f; System.out.println(valorGrande == valorFloat); // true (¡puede perder precisión!)
🏗️ Precedencia y asociatividad
Los operadores relacionales tienen una posición específica en la jerarquía de precedencia de Java. Conocerla es esencial para evitar errores de lógica en expresiones complejas:
| Prioridad | Categoría | Operadores | Asociatividad |
|---|---|---|---|
| 1 (más alta) | Unarios | ++ -- ! + - |
Derecha → Izquierda |
| 2 | Aritméticos multiplicativos | * / % |
Izquierda → Derecha |
| 3 | Aritméticos aditivos | + - |
Izquierda → Derecha |
| 4 | Relacionales de orden | > < >= <= instanceof |
Izquierda → Derecha |
| 5 | Relacionales de igualdad | == != |
Izquierda → Derecha |
| 6 | AND lógico | && |
Izquierda → Derecha |
| 7 | OR lógico | || |
Izquierda → Derecha |
| 8 (más baja) | Asignación | = += -= *= /= |
Derecha → Izquierda |
>, <, >=, <=) tienen mayor precedencia que los de igualdad (==, !=). Esto permite escribir expresiones combinadas sin paréntesis: a > b == c < d se evalúa como (a > b) == (c < d), comparando dos resultados booleanos.int a = 10, b = 5, c = 3; // Sin paréntesis: los aritméticos se evalúan primero boolean resultado = a - b > c; // Equivale a: (a - b) > c → (10 - 5) > 3 → 5 > 3 → true // Combinación con lógicos: los relacionales se evalúan antes boolean complejo = a > b && b > c; // Equivale a: (a > b) && (b > c) → true && true → true // Buena práctica: usar paréntesis para mayor claridad boolean claro = (a > b) && (b > c); // Misma lógica, más legible
🎓 Ejemplo completo: sistema de calificaciones
Este ejemplo integra todos los operadores relacionales en un programa completo que simula un sistema de calificaciones universitario. Clasifica alumnos según su nota, aplica reglas de negocio con validaciones y genera un informe:
public class SistemaCalificaciones {
// Constantes del sistema
static final double NOTA_MINIMA = 0.0;
static final double NOTA_MAXIMA = 10.0;
static final double NOTA_APROBADO = 5.0;
static final double NOTA_NOTABLE = 7.0;
static final double NOTA_SOBRESALIENTE = 9.0;
static final double NOTA_MATRICULA = 9.5;
public static String clasificar(double nota) {
// Validación con operadores relacionales
if (nota < NOTA_MINIMA || nota > NOTA_MAXIMA) {
return "ERROR: Nota fuera de rango [0-10]";
}
// Clasificación usando operadores >= y <
if (nota >= NOTA_MATRICULA) {
return "Matrícula de Honor";
} else if (nota >= NOTA_SOBRESALIENTE) {
return "Sobresaliente";
} else if (nota >= NOTA_NOTABLE) {
return "Notable";
} else if (nota >= NOTA_APROBADO) {
return "Aprobado";
} else {
return "Suspenso";
}
}
public static void imprimirInforme(String[] nombres, double[] notas) {
int aprobados = 0;
int suspensos = 0;
double mejorNota = NOTA_MINIMA;
String mejorAlumno = "";
System.out.println("╔════════════════════════════════════════════╗");
System.out.println("║ INFORME DE CALIFICACIONES ║");
System.out.println("╠════════════════════════════════════════════╣");
for (int i = 0; i < nombres.length; i++) {
String calificacion = clasificar(notas[i]);
System.out.printf("║ %-15s │ %4.1f │ %-20s ║%n",
nombres[i], notas[i], calificacion);
// Contar aprobados y suspensos
if (notas[i] >= NOTA_APROBADO) {
aprobados++;
} else {
suspensos++;
}
// Encontrar la mejor nota
if (notas[i] > mejorNota) {
mejorNota = notas[i];
mejorAlumno = nombres[i];
}
}
// Estadísticas finales
double porcentajeAprobados = (aprobados * 100.0) / nombres.length;
System.out.println("╠════════════════════════════════════════════╣");
System.out.printf("║ Aprobados: %d | Suspensos: %d ║%n",
aprobados, suspensos);
System.out.printf("║ Tasa aprobados: %.1f%% ║%n",
porcentajeAprobados);
System.out.printf("║ Mejor: %s (%.1f) ║%n",
mejorAlumno, mejorNota);
// Alerta si la tasa de aprobados es baja
if (porcentajeAprobados < 50.0) {
System.out.println("║ ⚠️ ALERTA: tasa de aprobados < 50% ║");
}
System.out.println("╚════════════════════════════════════════════╝");
}
public static void main(String[] args) {
String[] nombres = {"Ana", "Carlos", "Elena", "Pedro", "Lucía"};
double[] notas = { 9.7, 4.5, 7.8, 5.0, 9.2 };
imprimirInforme(nombres, notas);
}
}
Salida esperada:
╔════════════════════════════════════════════╗ ║ INFORME DE CALIFICACIONES ║ ╠════════════════════════════════════════════╣ ║ Ana │ 9.7 │ Matrícula de Honor ║ ║ Carlos │ 4.5 │ Suspenso ║ ║ Elena │ 7.8 │ Notable ║ ║ Pedro │ 5.0 │ Aprobado ║ ║ Lucía │ 9.2 │ Sobresaliente ║ ╠════════════════════════════════════════════╣ ║ Aprobados: 4 | Suspensos: 1 ║ ║ Tasa aprobados: 80.0% ║ ║ Mejor: Ana (9.7) ║ ╚════════════════════════════════════════════╝
🚫 Errores frecuentes
Estos son los errores más comunes al trabajar con operadores relacionales en Java. Conocerlos te ahorrará horas de depuración:
❌ Error 1: Confundir = (asignación) con == (comparación)
int x = 5;
// ❌ ERROR: esto es una asignación, no una comparación
// if (x = 10) { ... } // Error de compilación en Java
// ✅ CORRECTO: doble igual para comparar
if (x == 10) {
System.out.println("x vale 10");
}
En Java, este error se detecta en tiempo de compilación (a diferencia de C/C++), porque una asignación devuelve un int, no un boolean, y el if exige un boolean. Sin embargo, con variables boolean, el error pasa desapercibido:
boolean activo = false;
// ❌ BUG SILENCIOSO: asigna true a activo y entra siempre
if (activo = true) {
System.out.println("Siempre se ejecuta"); // ¡Siempre imprime!
}
// ✅ CORRECTO
if (activo == true) { ... }
// ✅ AÚN MEJOR (idiomático)
if (activo) { ... }
❌ Error 2: Comparar Strings con ==
import java.util.Scanner;
Scanner sc = new Scanner(System.in);
System.out.print("¿Continuar? (si/no): ");
String respuesta = sc.nextLine();
// ❌ Puede fallar: compara referencias, no contenido
if (respuesta == "si") { ... }
// ✅ CORRECTO
if (respuesta.equals("si")) { ... }
// ✅ MEJOR: tolera null y mayúsculas/minúsculas
if ("si".equalsIgnoreCase(respuesta)) { ... }
❌ Error 3: Escribir los operadores compuestos al revés
int nota = 7;
// ❌ ERROR DE COMPILACIÓN: el = va siempre a la derecha
// if (nota => 5) { ... } // Sintaxis inválida
// if (nota =< 10) { ... } // Sintaxis inválida
// ✅ CORRECTO
if (nota >= 5) { ... }
if (nota <= 10) { ... }
❌ Error 4: Encadenar operadores como en matemáticas
int nota = 7;
// ❌ ERROR: en Java NO se pueden encadenar comparaciones
// if (0 <= nota <= 10) { ... } // Error de compilación
// Motivo: Java evalúa de izquierda a derecha:
// (0 <= nota) → true → (true <= 10) → Error: boolean vs int
// ✅ CORRECTO: usar operador lógico AND
if (nota >= 0 && nota <= 10) {
System.out.println("Nota válida");
}
❌ Error 5: Comparar con NaN
double resultado = 0.0 / 0.0; // NaN (Not a Number) // ❌ TODAS estas comparaciones devuelven false System.out.println(resultado == Double.NaN); // false System.out.println(resultado > 0); // false System.out.println(resultado < 0); // false System.out.println(resultado == resultado); // false ← ¡NaN ≠ NaN! // ✅ CORRECTO: usar el método isNaN() System.out.println(Double.isNaN(resultado)); // true
✏️ Ejercicios prácticos
Practica los operadores relacionales con estos ejercicios de dificultad progresiva. Intenta resolverlos antes de consultar la solución.
Ejercicio 1: Clasificador de edades
Escribe un programa que reciba una edad (int) y devuelva la clasificación correspondiente: «Menor de edad» (edad < 18), «Adulto» (18 ≤ edad < 65), «Jubilado» (edad ≥ 65). Si la edad es negativa o superior a 130, debe mostrar «Edad no válida».
Ejercicio 2: Comparador de tres números
Escribe un método que reciba tres números enteros y devuelva el mayor de los tres. Si hay empate entre dos o más valores, devuelve ese valor. Usa solo operadores relacionales y el operador ternario (sin Math.max()).
Ejercicio 3: Validador de contraseña
Escribe un método que valide una contraseña según estas reglas: longitud ≥ 8 caracteres, longitud ≤ 64 caracteres, debe contener al menos una mayúscula, al menos una minúscula y al menos un dígito. El método debe recorrer la cadena carácter a carácter usando operadores relacionales para identificar mayúsculas (c >= 'A' && c <= 'Z'), minúsculas y dígitos.
❓ Preguntas frecuentes sobre Operadores relacionales en Java
Las dudas más comunes respondidas de forma clara y directa.
💬 Foro de discusión
¿Tienes dudas sobre Operadores relacionales en Java? Comparte tu pregunta con la comunidad.
Todavía no hay mensajes. ¡Sé el primero en participar!