Introducción a Conceptos Intermedios
Los conceptos intermedios de Java son herramientas esenciales que permiten escribir código más organizado, robusto y eficiente. Dominar estos conceptos es crucial para desarrollar aplicaciones profesionales.
Paquetes
Organizan clases en namespaces lógicos, evitando conflictos de nombres y facilitando el mantenimiento.
Excepciones
Manejan errores de manera elegante, permitiendo que los programas se recuperen de situaciones inesperadas.
Colecciones
Estructuras de datos flexibles para almacenar y manipular grupos de objetos de manera eficiente.
Enumeraciones
Definen conjuntos fijos de constantes con nombres, mejorando la legibilidad y seguridad del código.
Clases Wrapper
Envuelven tipos primitivos en objetos, permitiendo su uso en contextos que requieren objetos.
Paquetes (Packages)
Explorador de Estructura de Paquetes
// ESTRUCTURA DE DIRECTORIOS (Sistema de archivos)
src/
├── com/
│ └── miapp/
│ ├── model/
│ │ ├── Usuario.java
│ │ └── Producto.java
│ ├── service/
│ │ ├── UsuarioService.java
│ │ └── ProductoService.java
│ ├── util/
│ │ ├── Validador.java
│ │ └── Calculadora.java
│ └── main/
│ └── MainApp.java
// DECLARACIÓN DE PAQUETE (en cada archivo .java)
package com.miapp.model; // En Usuario.java
// IMPORTACIÓN DE CLASES
import java.util.ArrayList; // Import específico
import java.util.*; // Import de todo el paquete
import com.miapp.model.Usuario; // Import de nuestro propio paquete
// IMPORT ESTÁTICO (para métodos/constantes estáticas)
import static java.lang.Math.PI;
import static java.lang.Math.pow;
// CLASE PRINCIPAL QUE USA LOS PAQUETES
package com.miapp.main;
import com.miapp.model.Usuario;
import com.miapp.model.Producto;
import com.miapp.service.UsuarioService;
import static java.lang.System.out;
public class MainApp {
public static void main(String[] args) {
// Usar clases importadas
Usuario usuario = new Usuario("Juan", "juan@email.com");
UsuarioService service = new UsuarioService();
// Usar import estático
out.println("PI = " + PI);
out.println("2^3 = " + pow(2, 3));
}
}
📌 Convenciones de Nombres para Paquetes:
- Usar dominio inverso:
com.empresa.proyecto.modulo - Todas las letras en minúscula
- Evitar palabras reservadas de Java
- Los nombres deben ser descriptivos y jerárquicos
- Ejemplo:
org.apache.commons.math3.analysis
Manejo de Excepciones
Simulador de Flujo de Excepciones
Las excepciones son eventos que interrumpen el flujo normal de ejecución. Java proporciona un mecanismo robusto para manejarlas.
Código que puede lanzar excepciones
try {
// Código que puede fallar
int resultado = dividir(10, 0);
System.out.println("Resultado: " + resultado);
}
Captura y maneja excepciones específicas
} catch (ArithmeticException e) {
// Maneja división por cero
System.out.println("Error: " + e.getMessage());
System.out.println("No se puede dividir por cero");
}
Se ejecuta siempre, haya o no excepción
} finally {
// Código de limpieza
System.out.println("Operación finalizada");
cerrarRecursos();
}
// JERARQUÍA DE EXCEPCIONES
Throwable (clase base)
├── Error (errores graves, no se deben capturar)
│ ├── OutOfMemoryError
│ ├── StackOverflowError
│ └── ...
└── Exception (excepciones recuperables)
├── RuntimeException (unchecked - no requiere declaración)
│ ├── NullPointerException
│ ├── ArrayIndexOutOfBoundsException
│ ├── ArithmeticException
│ ├── IllegalArgumentException
│ └── ...
└── IOException (checked - requiere manejo)
├── FileNotFoundException
├── EOFException
└── ...
// EJEMPLOS COMPLETOS
// 1. EXCEPCIÓN CHECKED (obligatorio manejar)
public void leerArchivo(String ruta) {
try {
FileReader reader = new FileReader(ruta);
// Leer archivo...
} catch (FileNotFoundException e) {
System.err.println("Archivo no encontrado: " + e.getMessage());
} catch (IOException e) {
System.err.println("Error de E/S: " + e.getMessage());
}
}
// 2. EXCEPCIÓN UNCHECKED (opcional manejar)
public int dividir(int a, int b) {
if (b == 0) {
throw new ArithmeticException("Divisor no puede ser cero");
}
return a / b;
}
// 3. MULTI-CATCH (Java 7+)
try {
// Código que puede lanzar múltiples excepciones
} catch (NullPointerException | IllegalArgumentException e) {
System.err.println("Error de argumento: " + e.getMessage());
}
// 4. TRY-WITH-RESOURCES (Java 7+)
try (FileReader reader = new FileReader("archivo.txt");
BufferedReader br = new BufferedReader(reader)) {
String linea;
while ((linea = br.readLine()) != null) {
System.out.println(linea);
}
} catch (IOException e) {
System.err.println("Error al leer archivo: " + e.getMessage());
}
// 5. EXCEPCIONES PERSONALIZADAS
class SaldoInsuficienteException extends Exception {
private double saldo;
private double montoRequerido;
public SaldoInsuficienteException(double saldo, double montoRequerido) {
super("Saldo insuficiente: $" + saldo + ", se requiere: $" + montoRequerido);
this.saldo = saldo;
this.montoRequerido = montoRequerido;
}
public double getSaldo() { return saldo; }
public double getMontoRequerido() { return montoRequerido; }
}
// USO DE EXCEPCIÓN PERSONALIZADA
public void retirar(double cantidad) throws SaldoInsuficienteException {
if (cantidad > saldo) {
throw new SaldoInsuficienteException(saldo, cantidad);
}
saldo -= cantidad;
}
Colecciones Framework
Explorador de Colecciones Java
El Framework de Colecciones proporciona una arquitectura unificada para representar y manipular colecciones.
List - Listas
Colecciones ordenadas que permiten duplicados
// ArrayList - Array redimensionable
List frutas = new ArrayList<>();
frutas.add("Manzana");
frutas.add("Banana");
frutas.add("Naranja");
// LinkedList - Lista doblemente enlazada
List numeros = new LinkedList<>();
numeros.add(1);
numeros.add(2);
numeros.add(3);
// Características:
// • Mantienen orden de inserción
// • Permiten acceso por índice
// • Permiten elementos duplicados
// • Tiempo de acceso: ArrayList O(1), LinkedList O(n)
Set - Conjuntos
Colecciones que no permiten duplicados
// HashSet - Basado en tabla hash
Set colores = new HashSet<>();
colores.add("Rojo");
colores.add("Verde");
colores.add("Azul");
colores.add("Rojo"); // No se agrega (duplicado)
// TreeSet - Ordenado automáticamente
Set numeros = new TreeSet<>();
numeros.add(5);
numeros.add(1);
numeros.add(3);
// Resultado: [1, 3, 5] (ordenado)
// Características:
// • No permiten duplicados
// • HashSet no mantiene orden
// • TreeSet mantiene orden natural
// • Operaciones O(1) promedio (HashSet)
Map - Mapas
Almacenan pares clave-valor
// HashMap - Basado en tabla hash
Map capitales = new HashMap<>();
capitales.put("España", "Madrid");
capitales.put("Francia", "París");
capitales.put("Italia", "Roma");
// TreeMap - Ordenado por clave
Map edades = new TreeMap<>();
edades.put("Ana", 25);
edades.put("Carlos", 30);
edades.put("Beatriz", 28);
// Ordenado: Ana, Beatriz, Carlos
// Características:
// • Claves únicas, valores pueden repetirse
// • Acceso rápido por clave O(1)
// • HashMap no mantiene orden
// • TreeMap mantiene orden por clave
| Interfaz | Implementación | Orden | Duplicados | Acceso | Uso Típico |
|---|---|---|---|---|---|
List |
ArrayList |
Por índice | Sí | O(1) por índice | Listas dinámicas |
List |
LinkedList |
Por índice | Sí | O(n) por índice | Inserciones/eliminaciones frecuentes |
Set |
HashSet |
No | No | O(1) promedio | Conjuntos sin orden |
Set |
TreeSet |
Orden natural | No | O(log n) | Conjuntos ordenados |
Map |
HashMap |
No | Claves únicas | O(1) promedio | Tablas hash |
Map |
TreeMap |
Por clave | Claves únicas | O(log n) | Mapas ordenados |
Enumeraciones (Enum)
Simulador de Enumeraciones
Los enums definen un conjunto fijo de constantes con nombres, mejorando la legibilidad y seguridad del código.
Días de la Semana
Estados de Pedido
// ENUM BÁSICO
public enum DiaSemana {
LUNES, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO
}
// ENUM CON ATRIBUTOS Y MÉTODOS
public enum EstadoPedido {
PENDIENTE("En espera de procesamiento", 1),
PROCESANDO("En preparación", 2),
ENVIADO("En camino al cliente", 3),
ENTREGADO("Entregado satisfactoriamente", 4),
CANCELADO("Pedido cancelado", 0);
private final String descripcion;
private final int prioridad;
EstadoPedido(String descripcion, int prioridad) {
this.descripcion = descripcion;
this.prioridad = prioridad;
}
public String getDescripcion() { return descripcion; }
public int getPrioridad() { return prioridad; }
public boolean esFinal() {
return this == ENTREGADO || this == CANCELADO;
}
}
// ENUM CON MÉTODOS ABSTRACTOS
public enum OperacionMatematica {
SUMA("+") {
public double aplicar(double x, double y) { return x + y; }
},
RESTA("-") {
public double aplicar(double x, double y) { return x - y; }
},
MULTIPLICACION("*") {
public double aplicar(double x, double y) { return x * y; }
},
DIVISION("/") {
public double aplicar(double x, double y) {
if (y == 0) throw new ArithmeticException("División por cero");
return x / y;
}
};
private final String simbolo;
OperacionMatematica(String simbolo) {
this.simbolo = simbolo;
}
public String getSimbolo() { return simbolo; }
// Método abstracto que cada constante debe implementar
public abstract double aplicar(double x, double y);
}
// USO DE ENUMS
public class EjemploEnums {
public static void main(String[] args) {
// Valores básicos
DiaSemana hoy = DiaSemana.LUNES;
System.out.println("Hoy es: " + hoy);
// Iterar sobre todos los valores
for (DiaSemana dia : DiaSemana.values()) {
System.out.println(dia);
}
// Enums avanzados
EstadoPedido estado = EstadoPedido.PROCESANDO;
System.out.println("Estado: " + estado);
System.out.println("Descripción: " + estado.getDescripcion());
System.out.println("Es estado final: " + estado.esFinal());
// Switch con enum
switch (estado) {
case PENDIENTE:
System.out.println("El pedido está pendiente");
break;
case PROCESANDO:
System.out.println("El pedido se está procesando");
break;
case ENTREGADO:
System.out.println("¡Pedido entregado!");
break;
}
// Enum con métodos
OperacionMatematica op = OperacionMatematica.SUMA;
double resultado = op.aplicar(10, 5);
System.out.println("10 " + op.getSimbolo() + " 5 = " + resultado);
// Comparación de enums
if (estado == EstadoPedido.PROCESANDO) {
System.out.println("El pedido está en proceso");
}
// Convertir String a enum
String texto = "ENTREGADO";
EstadoPedido estadoDesdeTexto = EstadoPedido.valueOf(texto);
System.out.println("Estado desde texto: " + estadoDesdeTexto);
}
}
Clases Wrapper
Conversiones entre Tipos Primitivos y Objetos
Las clases wrapper envuelven tipos primitivos en objetos, permitiendo su uso en colecciones y otros contextos que requieren objetos.
| Tipo Primitivo | Clase Wrapper | Tamaño | Valor por Defecto | Ejemplo |
|---|---|---|---|---|
byte |
Byte |
8 bits | 0 | Byte.valueOf((byte)10) |
short |
Short |
16 bits | 0 | Short.valueOf((short)100) |
int |
Integer |
32 bits | 0 | Integer.valueOf(1000) |
long |
Long |
64 bits | 0L | Long.valueOf(100000L) |
float |
Float |
32 bits | 0.0f | Float.valueOf(3.14f) |
double |
Double |
64 bits | 0.0d | Double.valueOf(3.14159) |
char |
Character |
16 bits | '\u0000' | Character.valueOf('A') |
boolean |
Boolean |
1 bit | false | Boolean.valueOf(true) |
Autoboxing/Unboxing
Métodos Utiles
Constantes
// AUTOBOXING Y UNBOXING (Java 5+)
// Autoboxing: conversión automática primitivo → wrapper
Integer numeroObj = 42; // Equivale a: Integer.valueOf(42)
Double precioObj = 19.99; // Equivale a: Double.valueOf(19.99)
Boolean esVerdadero = true; // Equivale a: Boolean.valueOf(true)
// Unboxing: conversión automática wrapper → primitivo
int numero = numeroObj; // Equivale a: numeroObj.intValue()
double precio = precioObj; // Equivale a: precioObj.doubleValue()
boolean valor = esVerdadero; // Equivale a: esVerdadero.booleanValue()
// MÉTODOS ÚTILES DE CLASES WRAPPER
// 1. Conversión de String a tipos numéricos
String textoNumero = "123";
int valorInt = Integer.parseInt(textoNumero); // 123
double valorDouble = Double.parseDouble("3.14"); // 3.14
boolean valorBool = Boolean.parseBoolean("true"); // true
// 2. Conversión a String
String str1 = Integer.toString(456); // "456"
String str2 = Double.toString(2.718); // "2.718"
String str3 = Boolean.toString(false); // "false"
// 3. Comparación de objetos
Integer a = 100;
Integer b = 100;
Integer c = 200;
Integer d = 200;
System.out.println(a == b); // true (cache de -128 a 127)
System.out.println(c == d); // false (fuera del cache)
System.out.println(c.equals(d)); // true (comparación por valor)
// 4. Constantes útiles
System.out.println("Máximo int: " + Integer.MAX_VALUE); // 2147483647
System.out.println("Mínimo int: " + Integer.MIN_VALUE); // -2147483648
System.out.println("Bytes en int: " + Integer.BYTES); // 4
System.out.println("Bits en int: " + Integer.SIZE); // 32
// 5. Métodos de Character
char letra = 'A';
System.out.println(Character.isLetter(letra)); // true
System.out.println(Character.isDigit(letra)); // false
System.out.println(Character.isUpperCase(letra)); // true
System.out.println(Character.toLowerCase(letra)); // 'a'
// USO EN COLECCIONES (necesitan objetos)
List numeros = new ArrayList<>();
numeros.add(1); // Autoboxing: int → Integer
numeros.add(2);
numeros.add(3);
int suma = 0;
for (Integer num : numeros) {
suma += num; // Unboxing: Integer → int
}
System.out.println("Suma: " + suma);
// COMPARACIÓN SEGURA (evitar NullPointerException)
Integer posibleNull = obtenerNumero();
int valorSeguro = (posibleNull != null) ? posibleNull : 0;
// MÉTODOS DE CONVERSIÓN ADICIONALES
int hex = Integer.parseInt("FF", 16); // 255 en hexadecimal
int bin = Integer.parseInt("1010", 2); // 10 en binario
String binStr = Integer.toBinaryString(10); // "1010"
String hexStr = Integer.toHexString(255); // "ff"
// WRAPPER PARA TIPOS GENÉRICOS
public class Caja {
private T valor;
public Caja(T valor) {
this.valor = valor;
}
public double obtenerValorDouble() {
return valor.doubleValue(); // Método de Number
}
}
Caja cajaEntero = new Caja<>(100);
Caja cajaDouble = new Caja<>(3.14);
Juego de Memoria: Conceptos
Encuentra las Parejas de Conceptos
Voltea las cartas para encontrar las definiciones que corresponden a cada concepto.
Ejercicios Prácticos
Sistema de Gestión de Biblioteca
Crea un sistema completo para una biblioteca usando todos los conceptos aprendidos:
- Paquetes: Organiza el código en paquetes:
com.biblioteca.modelo,com.biblioteca.servicio,com.biblioteca.util - Excepciones: Crea excepciones personalizadas:
LibroNoDisponibleException,UsuarioBloqueadoException - Colecciones: Usa
HashMappara buscar libros por ISBN yTreeSetpara usuarios ordenados - Enums: Define
EstadoLibro(DISPONIBLE, PRESTADO, RESERVADO, REPARACION) - Wrappers: Usa clases wrapper para cálculos estadísticos
Sistema de Pedidos con Validación
Implementa un sistema de pedidos con validación robusta:
- Excepciones: Crea jerarquía de excepciones para diferentes tipos de errores
- Colecciones: Usa
ArrayListpara items del pedido,HashSetpara códigos únicos - Enums: Define
EstadoPedido,CategoriaProducto,Prioridad - Wrappers: Implementa cálculos con
BigDecimalpara precisión monetaria - Validación: Usa métodos de validación de clases wrapper
Analizador de Texto con Colecciones
Crea un analizador de texto que use colecciones de manera avanzada:
- HashMap: Contar frecuencia de palabras (palabra → cantidad)
- TreeMap: Ordenar palabras por frecuencia descendente
- HashSet: Identificar palabras únicas
- ArrayList: Almacenar palabras en orden de aparición
- Enums: Definir tipos de análisis (FRECUENCIA, UNICAS, LONGITUD)
- Wrappers: Usar
Characterpara análisis de caracteres
Sistema de Juego con Todos los Conceptos
Implementa un sistema de juego que integre todos los conceptos intermedios:
- Paquetes: Estructura organizada:
com.juego.entidades,com.juego.mecanicas,com.juego.util - Excepciones: Excepciones para el juego:
JugadorSinVidaException,ItemNoDisponibleException - Colecciones: Usar diferentes colecciones: inventario (
ArrayList), logros (HashSet), ranking (TreeMap) - Enums: Definir
Dificultad,TipoItem,EstadoJuego - Wrappers: Sistema de puntuación con cálculos precisos
Desafío Integrador
Banco de Preguntas: ¿Cuánto Sabes?
Pregunta 1: ¿Cuál es la ventaja principal de usar paquetes en Java?
Resumen y Buenas Prácticas
Conceptos Clave
- Paquetes: Organizan código en namespaces jerárquicos
- Excepciones: Manejan errores de forma controlada (checked/unchecked)
- Colecciones: Framework unificado para estructuras de datos
- List: Colecciones ordenadas que permiten duplicados
- Set: Colecciones que no permiten duplicados
- Map: Almacenan pares clave-valor
- Enums: Conjuntos fijos de constantes con nombres
- Wrappers: Envuelven tipos primitivos en objetos
- Autoboxing/Unboxing: Conversiones automáticas primitivo↔wrapper
Buenas Prácticas
- Usar nombres de paquete basados en dominio inverso
- Capturar excepciones específicas en lugar de Exception general
- Usar try-with-resources para recursos auto-cerrables
- Elegir la colección adecuada según las necesidades
- Usar enums en lugar de constantes numéricas mágicas
- Preferir valueOf() sobre constructores para wrappers
- Usar equals() para comparar wrappers, no ==
- Documentar excepciones lanzadas por métodos
- Usar imports específicos en lugar de import *
Errores Comunes
- No manejar excepciones checked (error de compilación)
- Capturar Exception en lugar de excepciones específicas
- Usar == para comparar objetos wrapper fuera del cache
- Olvidar cerrar recursos en bloques finally
- Usar ArrayList cuando se necesitan inserciones/eliminaciones frecuentes
- Confundir HashSet con TreeSet (orden vs velocidad)
- No sobrescribir equals() y hashCode() en clases usadas en HashSet/HashMap
- Usar números mágicos en lugar de enums
- No validar datos al convertir Strings a wrappers
Hoja de Referencia Rápida
Paquetes:
package com.empresa.proyecto;
import java.util.List;
import static java.lang.Math.PI;
Excepciones:
try {
// código
} catch (IOException e) {
// manejo
} finally {
// limpieza
}
Colecciones:
List lista = new ArrayList<>();
Set conjunto = new HashSet<>();
Map mapa = new HashMap<>();
Enums:
enum Color { ROJO, VERDE, AZUL }
Color c = Color.ROJO;
Wrappers:
Integer i = 42; // autoboxing
int j = i; // unboxing
int k = Integer.parseInt("123");
Test Final de Conceptos
Evalúa tu conocimiento
Responde las siguientes preguntas sobre conceptos intermedios de Java
Pregunta 1 de 10