Saltar a contenido

5. Operadores

UD1 — Fundamentos de Programación

IES Thiar · Curso 2026 - 2027

Aspecto Valor
Resultado de aprendizaje RA1 — Reconoce la estructura de un programa informático, identificando y relacionando los elementos propios del lenguaje de programación utilizado.
Criterios de evaluación cubiertos CE 1.7 — Se han clasificado, reconocido y utilizado en expresiones los operadores del lenguaje.
Marco normativo RD 405/2023 · RD 450/2010 · RD 659/2023
Tecnología base Java 25 LTS — operadores clásicos + pattern matching para instanceof (Java 16+).

Introducción de la sección

Hasta ahora has creado variables, las has inicializado y las has mostrado por pantalla. Pero un programa que solo "guarda y muestra" no hace nada interesante: para que un programa de verdad sirva para algo, necesita calcular, comparar y decidir. Y para eso están los operadores. Un operador es un símbolo que toma uno o varios valores (llamados operandos) y produce un resultado: + suma, == compara, && combina condiciones, ++ incrementa. Java tiene más de 40 operadores repartidos en categorías: aritméticos, relacionales, lógicos, de asignación, de incremento, ternarios, de tipo...

El objetivo de esta sección es que conozcas los operadores esenciales de Java, que aprendas a combinarlos en expresiones y que entiendas los detalles que más sorprenden al principiante: por qué 5 / 2 da 2 y no 2.5 (división entera), qué significa eso del cortocircuito en && y ||, la diferencia entre ++i y i++ (que ha generado más bugs de los se admiten), y cómo el orden en que se evalúan los operadores (la precedencia) puede dar resultados inesperados si no usas paréntesis. Cuando acabes, sabrás escribir expresiones correctas y leer las de otros sin tropezar.


5.1 El operador de asignación =

Llevas usándolo desde la Sección 4: int edad = 25;. Pero hasta ahora lo has tratado como una instrucción más. En realidad, = es un operador —el de menor precedencia de todos (nivel 14 en la tabla de la Sección 5.9)— y tiene reglas propias que conviene conocer formalmente.

Cómo funciona: el lado derecho se evalúa primero

La asignación siempre sigue este orden:

  1. Se evalúa la expresión a la derecha del =.
  2. Se almacena el resultado en la variable a la izquierda.
1
2
3
int a = 5 + 3;     // 1. se calcula 5 + 3 = 8;  2. se guarda 8 en a
int b = a * 2;     // 1. se lee a (8), se calcula 8 * 2 = 16;  2. se guarda 16 en b
int c = b;         // 1. se lee b (16);  2. se guarda 16 en c

Esto explica por qué esto funciona:

int x = 5;
x = x + 1;   // 1. se evalúa x + 1 = 6;  2. se guarda 6 en x

No hay paradoja: cuando Java evalúa x + 1, x aún vale 5. El 6 resultante se guarda después en x.

El lado izquierdo debe ser una variable

El lado izquierdo del = tiene que ser algo que pueda recibir un valor: una variable declarada. No puede ser un literal ni una expresión compuesta:

1
2
3
4
int x;
x = 10;           // OK
5 = x;             // ERROR: no se puede asignar a un literal
x + 1 = 20;       // ERROR: no se puede asignar a una expresión

Asignación encadenada

= es asociativo por la derecha. Esto permite asignar un mismo valor a varias variables en una sola línea:

1
2
3
4
5
int a, b, c;
a = b = c = 10;   // equivale a: a = (b = (c = 10));
// 1. c = 10 → c vale 10
// 2. b = 10 → b vale 10  (el 10 viene del resultado de c = 10)
// 3. a = 10 → a vale 10  (el 10 viene del resultado de b = 10)

La asignación encadenada es legítima, pero en código profesional se prefiere una línea por variable para claridad.

= no es «igual a» en matemáticas

En matemáticas, x = x + 1 es una ecuación sin solución. En programación, es una instrucción que incrementa x en 1. No pienses en = como «igual a», piensa en él como «almacena en» o «toma el valor de».


5.2 Operadores aritméticos: la aritmética de la CPU

Los operadores aritméticos son los más familiares: suma, resta, multiplicación, división y módulo. Java los hereda de C/C++ y se comportan casi como en matemáticas, pero con dos trampas importantes que conviene desterrar desde el primer día.

Tabla de operadores aritméticos

Operador Operación Ejemplo Resultado Notas
+ Suma 5 + 3 8 También concatena String
- Resta 5 - 3 2 También es operador unario: -x
* Multiplicación 5 * 3 15
/ División 5 / 2 2 (¡no 2.5!) División entera si ambos operandos son enteros
% Módulo (resto) 5 % 2 1 Resto de la división entera

La trampa de la división entera

Si en Java escribes 5 / 2, el resultado es 2, no 2.5. La razón es que cuando los dos operandos son enteros, Java realiza división entera: trunca los decimales hacia cero. Esto es la fuente número 1 de bugs aritméticos en principiantes.

1
2
3
4
5
6
7
8
9
int a = 5;
int b = 2;
System.out.println(a / b);          // imprime 2, NO 2.5
System.out.println(a % b);          // imprime 1 (el resto de 5/2)

// Para obtener 2.5, al menos un operando debe ser decimal:
System.out.println(a / 2.0);        // imprime 2.5
System.out.println(5.0 / b);        // imprime 2.5
System.out.println((double) a / b); // imprime 2.5 (casting explícito)

Cuidado con el orden del casting. (double) a / b convierte primero a a double y luego divide (resultado 2.5). Pero (double) (a / b) primero hace la división entera 5 / 2 = 2 y luego convierte el 2 a 2.0: ¡sigue siendo entero! Los paréntesis importan. Lo verás en detalle en la Sección 7 (Conversión de tipos).

Módulo: más útil de lo que parece

El operador % devuelve el resto de la división entera. Parece exótico, pero es imprescindible en muchos patrones:

// Comprobar paridad
boolean esPar = (numero % 2 == 0);

// Última cifra de un número
int ultimaCifra = numero % 10;

// Repartir en turnos cíclicos (0, 1, 2, 0, 1, 2, ...)
int turno = indice % 3;

// Convertir segundos a minutos y segundos
int totalSegundos = 135;
int minutos = totalSegundos / 60;        // 2
int segundos = totalSegundos % 60;       // 15

Pista

% solo funciona bien con enteros positivos. Con negativos, el signo del resultado sigue al dividendo: -7 % 3 es -1 en Java (no 2 como en Python). Si necesitas un módulo siempre positivo, usa Math.floorMod(a, b).

Operadores unarios

Algunos operadores aritméticos actúan sobre un solo operando (unarios):

Operador Operación Ejemplo
+x Identidad (no hace nada útil, pero existe) +55
-x Negación aritmética -x cambia el signo de x
++x / x++ Pre/post incremento (Sección 5.3)
--x / x-- Pre/post decremento (Sección 5.3)

5.3 Asignación compuesta e incremento/decremento

Asignación compuesta

La asignación compuesta combina una operación aritmética con la asignación en un solo operador. Es azúcar sintáctico: x += 5 equivale a x = x + 5, pero más corto y ligeramente más seguro (evita ciertos errores de casting implícito).

Operador Equivalente a Ejemplo
+= x = x + y precio += 10;
-= x = x - y saldo -= 50;
*= x = x * y precio *= 1.21; (añadir 21% IVA)
/= x = x / y nota /= 2;
%= x = x % y indice %= 7; (mantener en rango 0-6)
1
2
3
4
5
6
7
int contador = 0;
contador += 1;   // contador = 1
contador += 5;   // contador = 6
contador -= 2;   // contador = 4
contador *= 3;   // contador = 12
contador /= 5;   // contador = 2 (división entera)
contador %= 2;   // contador = 0

Pista

La asignación compuesta es muy útil para actualizar contadores, saldos o índices. Es más legible que la forma completa (contador = contador + 1) y menos propensa a errores tipográficos.

Incremento y decremento: ++ y --

Java hereda de C los operadores ++ (suma 1) y -- (resta 1). Tienen dos formas: pre (antes de la variable) y post (después), y la diferencia es sutil pero importante.

Forma Nombre Qué hace Devuelve
++x Pre-incremento Incrementa x en 1 El nuevo valor de x
x++ Post-incremento Incrementa x en 1 El valor antes de incrementar
--x Pre-decremento Decrementa x en 1 El nuevo valor de x
x-- Post-decremento Decrementa x en 1 El valor antes de decrementar
1
2
3
4
5
6
7
8
int x = 5;
int a = x++;   // a = 5, x = 6   (post: asigna el valor viejo, luego incrementa)
int b = ++x;   // b = 7, x = 7   (pre: incrementa primero, luego asigna)

// Equivalencias:
int y = 5;
y++;           // equivale a y = y + 1
++y;           // también equivale a y = y + 1 (cuando va solo en una línea)
flowchart TD
    X1["x = 5"] --> POST["a = x++"]
    POST --> P1["1. Se lee el valor de x (5)"]
    P1 --> P2["2. Se asigna a a: a = 5"]
    P2 --> P3["3. Se incrementa x: x = 6"]
    P3 --> P4["Resultado: a=5, x=6"]

    X2["x = 5"] --> PRE["b = ++x"]
    PRE --> R1["1. Se incrementa x: x = 6"]
    R1 --> R2["2. Se lee el valor de x (6)"]
    R2 --> R3["3. Se asigna a b: b = 6"]
    R3 --> R4["Resultado: b=6, x=6"]

    style X1 fill:#e3f2fd,stroke:#1565c0,color:#000
    style POST fill:#fff3e0,stroke:#e65100,color:#000
    style P1 fill:#fff3e0,stroke:#e65100,color:#000
    style P2 fill:#fff3e0,stroke:#e65100,color:#000
    style P3 fill:#fff3e0,stroke:#e65100,color:#000
    style P4 fill:#ffebee,stroke:#c62828,color:#000
    style X2 fill:#e3f2fd,stroke:#1565c0,color:#000
    style PRE fill:#e8f5e9,stroke:#2e7d32,color:#000
    style R1 fill:#e8f5e9,stroke:#2e7d32,color:#000
    style R2 fill:#e8f5e9,stroke:#2e7d32,color:#000
    style R3 fill:#e8f5e9,stroke:#2e7d32,color:#000
    style R4 fill:#e8f5e9,stroke:#2e7d32,color:#000

Diagrama 5.1 — Diferencia entre x++ (post: asigna y luego incrementa) y ++x (pre: incrementa y luego asigna).

Cuidado

La diferencia entre ++x y x++ solo importa cuando el operador se usa dentro de una expresión más grande. Si va solo en una línea (x++; o ++x;), el efecto es idéntico: ambos incrementan x en 1. La trampa aparece en casos como a = x++ o array[x++] = valor, donde el orden de lectura/escritura cambia el resultado.

La regla mnemotécnica

Regla. La posición del ++ te dice cuándo se incrementa respecto a la lectura del valor: - ++x (prefijo): primero incrementa, luego usa el nuevo valor. - x++ (sufijo): primero usa el valor actual, luego incrementa.

Para evitar bugs, muchos equipos Java modernos recomiendan no usar ++ dentro de expresiones complejas: ponlo siempre en su propia línea. La sentencia i++; sola no tiene ambigüedad.

1
2
3
4
5
6
// Estilo claro (recomendado)
i++;
int a = i;

// Estilo peligroso (a evitar)
int a = i++;

5.4 Operadores relacionales

Los operadores relacionales comparan dos valores y devuelven siempre un boolean (true o false). Son la base de cualquier if, while o condición.

Operador Operación Ejemplo Resultado
== Igualdad 5 == 5 true
!= Desigualdad 5 != 3 true
< Menor que 3 < 5 true
> Mayor que 3 > 5 false
<= Menor o igual que 5 <= 5 true
>= Mayor o igual que 3 >= 5 false
int edad = 23;
double nota = 8.5;

boolean esMayor = edad >= 18;        // true
boolean esSobresaliente = nota >= 9; // false
boolean esApto = nota >= 5 && edad >= 18;   // true (combinando con &&)

if (edad >= 18) {
    System.out.println("Mayor de edad");
}

La trampa == en decimales

Igualar decimales con == es peligroso porque la aritmética de coma flotante no es exacta:

1
2
3
4
double a = 0.1 + 0.2;
double b = 0.3;
System.out.println(a);          // 0.30000000000000004
System.out.println(a == b);     // false  ¡sorpresa!

Esto no es un bug de Java, es inherente al estándar IEEE 754 de coma flotante: 0.1 no tiene representación exacta en binario. Para comparar decimales, usa un margen de tolerancia:

final double EPSILON = 0.0001;
boolean casiIguales = Math.abs(a - b) < EPSILON;   // true

Pista

Para dinero y cantidades financieras, nunca uses double ni float: usa BigDecimal (lo verás en UD2). Para notas, medidas físicas y cálculos aproximados, double es suficiente, pero compara siempre con margen.

La trampa == en String (recordatorio)

Ya la veremos en la Sección 8, pero conviene anticiparla aquí porque encaja en este contexto: para comparar String (o cualquier objeto), usa .equals(), no ==. == compara identidad (si son el mismo objeto), .equals() compara contenido. Esto es válido para todos los operadores relacionales de igualdad: con primitivos == funciona; con referencias, casi nunca.


5.5 Operadores lógicos con cortocircuito

Los operadores lógicos combinan valores booleanos. Tienen una característica crucial llamada cortocircuito (short-circuit evaluation) que es una de las optimizaciones más útiles de Java.

Tabla de operadores lógicos

Operador Operación Devuelve true si... Cortocircuito
&& AND (Y lógico) Ambos operandos son true Sí: si el primero es false, no evalúa el segundo
|| OR (O lógico) Al menos uno es true Sí: si el primero es true, no evalúa el segundo
! NOT (Negación) El operando es false (unario, no aplica)
& AND sin cortocircuito Ambos son true No: siempre evalúa ambos
| OR sin cortocircuito Al menos uno es true No: siempre evalúa ambos
^ XOR (O exclusivo) Exactamente uno es true No

Los operadores &, | y ^ sin cortocircuito son raros en código normal; se usan sobre todo a nivel de bits cuando los operandos son enteros. En lógica booleana, siempre usa && y || con cortocircuito.

Tablas de verdad

Para && (Y lógico):

a b a && b
true true true
true false false
false true false
false false false

Para || (O lógico):

a b a || b
true true true
true false true
false true true
false false false

Para ! (negación):

a !a
true false
false true

Qué es el cortocircuito y por qué importa

El cortocircuito significa que && deja de evaluar en cuanto encuentra un false (porque el resultado ya no puede ser true), y || deja de evaluar en cuanto encuentra un true (porque el resultado ya no puede ser false). Esto tiene dos usos prácticos importantísimos:

1. Evitar NullPointerException

1
2
3
4
5
6
7
String nombre = null;

// Sin cortocircuito: NullPointerException
if (nombre != null & nombre.length() > 3) { ... }   // CRASH

// Con cortocircuito: seguro
if (nombre != null && nombre.length() > 3) { ... }  // false, sin error
flowchart TD
    A["a && b"] --> B{"¿a es true?"}
    B -->|"No"| C["Devuelve false<br/>SIN evaluar b<br/>(cortocircuito)"]
    B -->|"Sí"| D["Evalúa b"]
    D --> E{"¿b es true?"}
    E -->|"No"| F["Devuelve false"]
    E -->|"Sí"| G["Devuelve true"]

    H["a || b"] --> I{"¿a es true?"}
    I -->|"Sí"| J["Devuelve true<br/>SIN evaluar b<br/>(cortocircuito)"]
    I -->|"No"| K["Evalúa b"]
    K --> L{"¿b es true?"}
    L -->|"Sí"| M["Devuelve true"]
    L -->|"No"| N["Devuelve false"]

    style A fill:#1565c0,color:#fff,stroke:#0d47a1
    style H fill:#2e7d32,color:#fff,stroke:#1b5e20
    style C fill:#fff3e0,stroke:#e65100,color:#000
    style J fill:#fff3e0,stroke:#e65100,color:#000

Diagrama 5.2 — Cortocircuito en && y ||: si el primer operando ya decide el resultado, no se evalúa el segundo.

2. Evitar cálculos costosos

// Si la validación rápida falla, no se ejecuta la costosa
if (validacionRapida(dato) && validacionCostosa(dato)) { ... }

Si validacionRapida devuelve false, validacionCostosa ni se llama. Esto puede ahorrar muchísimo tiempo.

Leyes de De Morgan

Dos reglas útiles para simplificar condiciones complejas:

  • !(a && b) es equivalente a !a || !b
  • !(a || b) es equivalente a !a && !b
1
2
3
// Estas dos condiciones son equivalentes:
if (!(edad >= 18 && tienePermiso)) { ... }
if (edad < 18 || !tienePermiso) { ... }

Pista

Las leyes de De Morgan te permiten reescribir condiciones negativas en forma positiva, que suele ser más legible. edad < 18 se entiende mejor que !(edad >= 18).


5.6 Operadores bit a bit (introducción)

Java hereda de C un conjunto de operadores que actúan a nivel de bits sobre valores enteros (byte, short, int, long, char). En programación de alto nivel rara vez los usarás, pero aparecen en dominios como criptografía, compresión de datos, gráficos de bajo nivel, permisos de archivos y comunicación con hardware. Los verás por encima en esta sección; se profundizan en UD4 cuando tratemos operaciones sobre enteros.

Analogía

Los operadores bit a bit son como un interruptor para cada bombilla de una caseta de feria con 32 bombillas. Cada bit del número enciende (1) o apaga (0) una bombilla. Los operadores bit a bit permiten manipular esos interruptores de golpe: encender todos, apagar algunos, invertir el estado, desplazar los interruptores a la izquierda...

Tabla de operadores bit a bit

Operador Operación Ejemplo Resultado Notas
& AND bit a bit 0b1100 & 0b1010 0b1000 (8) 1 solo si ambos bits son 1
\| OR bit a bit 0b1100 \| 0b1010 0b1110 (14) 1 si al menos uno es 1
^ XOR bit a bit 0b1100 ^ 0b1010 0b0110 (6) 1 si exactamente uno es 1
~ NOT bit a bit (unario) ~0b00001100 0b11110011 (-13) Invierte todos los bits
<< Desplazamiento izquierda 0b0001 << 3 0b1000 (8) Multiplica por 2^n
>> Desplazamiento derecha (con signo) 0b1000 >> 2 0b0010 (2) Divide por 2^n, conserva signo
>>> Desplazamiento derecha (sin signo) 0b1000 >>> 2 0b0010 (2) Rellena con ceros por la izquierda

Ejemplos prácticos

// Comprobar si un bit concreto está activado
int mascara = 0b00000100;   // bit 2 (valor 4)
int valor = 0b00010100;     // 20
boolean bit2Activo = (valor & mascara) != 0;   // true

// Activar un bit
valor = valor | mascara;    // activa el bit 2

// Invertir un bit
valor = valor ^ mascara;

// Multiplicar/dividir por potencias de 2 (rápido)
int x = 5;
int xPor8 = x << 3;        // 40 (5 * 8)
int xEntre4 = x >> 2;      // 1 (5 / 4 con truncamiento)

// Permisos estilo Unix (combinar flags con OR)
final int LECTURA  = 0b001;   // 1
final int ESCRITURA = 0b010;   // 2
final int EJECUCION = 0b100;  // 4
int permisos = LECTURA | ESCRITURA;   // 0b011 (3): lectura y escritura
boolean puedeEjecutar = (permisos & EJECUCION) != 0;   // false

Pista

Si no estás trabajando con bits explícitamente, no uses estos operadores. x << 1 para multiplicar por 2 es igual de rápido en Java moderno que x * 2 porque el compilador ya optimiza la multiplicación y el código es menos legible. Úsalos solo cuando manipules bits reales (máscaras, permisos, protocolos).

Asignación compuesta bit a bit

Existen los operadores &=, |=, ^=, <<=, >>=, >>>= equivalentes a x = x op y. Se ven en la tabla de precedencia (Sección 5.8 Precedencia) y funcionan igual que los aritméticos compuestos.

Cuidado

Los operadores bit a bit & y | se parecen a los lógicos && y ||, pero no son lo mismo. & y | siempre evalúan ambos operandos (sin cortocircuito) y operan bit a bit; && y || operan sobre boolean y tienen cortocircuito. Confundirlos es un bug sutil: usa siempre && y || para lógica booleana.


5.7 Otros operadores

Hay otros operadores importantes:

  • El operador ternario ?:
  • El operador instanceof

Pero los veremos según vayamos avanzando en el curso.


5.8 Precedencia de operadores

La precedencia determina qué operador se evalúa primero cuando hay varios en una expresión. Por ejemplo, 2 + 3 * 4 da 14, no 20, porque * tiene mayor precedencia que + y se evalúa primero.

Tabla de precedencia (de mayor a menor)

Nivel Operadores Asociatividad
1 (mayor) () [] . (acceso a miembro) :: Izquierda
2 ! ++ -- + - (unarios) ~ (cast) Derecha
3 * / % Izquierda
4 + - (binarios) Izquierda
5 << >> >>> (desplazamientos de bits) Izquierda
6 < <= > >= instanceof Izquierda
7 == != Izquierda
8 & (AND bit a bit) Izquierda
9 ^ (XOR bit a bit) Izquierda
10 \| (OR bit a bit) Izquierda
11 && (AND lógico) Izquierda
12 \|\| (OR lógico) Izquierda
13 ?: (ternario) Derecha
14 = += -= *= /= %= &= \|= ^= <<= >>= >>>= Derecha

Algunas reglas prácticas:

  • *, /, % se evalúan antes que +, - (como en matemáticas).
  • Los operadores relacionales (<, >, ==, etc.) se evalúan antes que los lógicos (&&, ||).
  • La asignación = es de las últimas, casi al final.
  • Los unarios (!, -, ++, --) son de los primeros.

Ejemplos

// Multiplicación antes que suma
int a = 2 + 3 * 4;          // a = 14, no 20

// Con paréntesis cambia el orden
int b = (2 + 3) * 4;        // b = 20

// Comparación antes que AND lógico
boolean ok = 5 > 3 && 2 < 4;   // ok = (5>3) && (2<4) = true && true = true

// Negación antes que AND
boolean mix = !false && true;  // mix = (!false) && true = true && true = true

// Ternario antes que asignación
int x = condicion ? 1 : 2;    // x = (condicion ? 1 : 2)

La regla de oro: usa paréntesis

Aprenderse la tabla de precedencia entera no es práctico y nadie lo hace. La regla profesional es simple:

Regla. Cuando una expresión mezcla más de dos operadores, usa paréntesis para dejar explícito el orden. Los paréntesis no cuestan nada en rendimiento (el compilador los elimina al generar bytecode) y hacen que el código sea legible para cualquier persona, incluyéndote a ti dentro de seis meses.

1
2
3
4
5
6
7
8
9
// Sin paréntesis: ¿quién sabe qué hace esto?
boolean r = a && b || c && d || !e;

// Con paréntesis: clarísimo
boolean r = (a && b) || (c && d) || !e;

// Otro ejemplo: el orden de evaluación importa
double media = (a + b + c) / 3.0;     // bien: paréntesis fuerzan suma antes que división
double mal = a + b + c / 3.0;         // distinto: c/3.0 primero, luego suma

Pista

IntelliJ puede insertar paréntesis automáticamente cuando seleccionas una expresión y pulsas Alt+Enter → "Surround with parentheses". Úsalo cuando una expresión te parezca ambigua.


5.9 Errores comunes y buenas prácticas

Los ocho errores más frecuentes

Error Síntoma Causa Solución
= en vez de == en un if El if siempre se cumple (o no compila) Confundir asignación con comparación Revisa cada = en condiciones; usa ==
División entera involuntaria 5 / 2 == 2, no 2.5 Ambos operandos son enteros Convierte uno a double: 5.0 / 2
Confundir ++i y i++ Resultado inesperado en expresiones Olvidar cuándo se incrementa Úsalo solo en su propia línea
Comparar decimales con == 0.1 + 0.2 != 0.3 Aritmética de coma flotante inexacta Usa margen de tolerancia (EPSILON)
Comparar String con == Da false aunque el texto sea igual Compara identidad, no contenido Usa .equals() o Objects.equals()
Olvidar paréntesis en condiciones Resultado distinto del esperado Precedencia no intuitiva Pon paréntesis explícitos
NPE en && sin cortocircuito NullPointerException inesperado Usar & en vez de && Usa siempre && para lógica

Buenas prácticas resumidas

  1. Para divisiones con decimales, asegúrate de que al menos un operando sea double: 5.0 / 2, no 5 / 2. Si solo tienes int, haz casting: (double) a / b (ojo a los paréntesis).
  2. Usa % para paridad, ciclos y restos: x % 2 == 0 para pares, indice % n para ciclos.
  3. ++ y -- en su propia línea salvo en casos muy obvios (for clásico). Evita a = i++ y similares.
  4. Compara decimales con margen: Math.abs(a - b) < EPSILON. Para dinero, usa BigDecimal.
  5. Para String y objetos, usa .equals() (o Objects.equals() si puede haber null).
  6. && y || con cortocircuito para proteger llamadas que pueden dar NPE: obj != null && obj.metodo().
  7. Paréntesis explícitos cuando una expresión mezcla más de dos operadores. No confíes en la memoria de la tabla de precedencia.
  8. Revisa tus expresiones con IntelliJ: las inspecciones te avisan de operaciones sospechosas (división entera, comparaciones raras, etc.).

Ejercicios propuestos

Ejercicio 5.1 (= vs ==). ¿Qué hace cada línea? ¿Cuáles compilan? ¿Cuáles son errores lógicos?

1
2
3
4
5
6
int x = 5;
if (x = 5) { System.out.println("A"); }
if (x == 5) { System.out.println("B"); }
boolean activo = false;
if (activo = true) { System.out.println("C"); }
if (activo == true) { System.out.println("D"); }

Ejercicio 5.2 (división entera). Predice el resultado de cada println sin ejecutarlo y comprueba después:

1
2
3
4
5
System.out.println(7 / 2);          // ?
System.out.println(7 / 2.0);        // ?
System.out.println(7.0 / 2);        // ?
System.out.println((double) 7 / 2);  // ?
System.out.println((double) (7 / 2)); // ?

Ejercicio 5.3 (++i vs i++). Predice los valores finales de i, a, b y c sin ejecutarlo y comprueba después:

1
2
3
4
int i = 5;
int a = i++;
int b = ++i;
int c = i--;

Ejercicio 5.4 (cortocircuito). El siguiente código ¿lanza NullPointerException? Explícalo:

1
2
3
4
5
6
String s = null;
if (s != null && s.length() > 3) {
    System.out.println("Válido");
} else {
    System.out.println("Nulo o corto");
}

Ejercicio 5.5 (De Morgan). Reescribe la siguiente condición sin usar !:

if (!(edad >= 18 && tienePermiso)) { ... }

Ejercicio 5.6 (precedencia). Añade paréntesis a la siguiente expresión para que coincida con la evaluación que hace Java por defecto, y predice el resultado:

int r = 2 + 3 * 4 - 6 / 2 % 3;

Ejercicio 5.7 (comparación de decimales). Explica por qué 0.1 + 0.2 == 0.3 da false y escribe una comparación correcta usando EPSILON.


Resumen de la sección 5

Antes de pasar a la siguiente sección, asegúrate de que controlas estos puntos:

  1. El operador de asignación = evalúa primero el lado derecho y almacena el resultado en la variable de la izquierda. Es de menor precedencia y asociativo por la derecha. Nunca lo confundas con == (comparación): if (x = 5) asigna, no compara.
  2. Los operadores aritméticos (+, -, *, /, %) funcionan como en matemáticas, con la trampa de la división entera (5 / 2 == 2). Para decimales, al menos un operando debe ser double.
  3. La asignación compuesta (+=, -=, *=, /=, %=) combina operación y asignación. El incremento/decremento ++ y -- tienen forma pre (++x, primero incrementa) y post (x++, primero lee).
  4. Los operadores relacionales (==, !=, <, >, <=, >=) devuelven boolean. Cuidado al comparar decimales con == (usa margen) y al comparar String (usa .equals()).
  5. Los operadores lógicos && y || tienen cortocircuito: dejan de evaluar en cuanto el resultado está decidido. Útil para evitar NPE y cálculos costosos. &, |, ^ son sin cortocircuito (raros en lógica).
  6. La precedencia determina el orden de evaluación. No te la aprendas: usa paréntesis cuando haya más de dos operadores.
  7. Los ocho errores típicos: = en vez de ==, división entera, ++i vs i++, decimales con ==, String con ==, falta de paréntesis, & sin cortocircuito, ternarios anidados.