☕ ¿Qué es Java?

Definición

Java es un lenguaje de programación de propósito general, concurrente, fuertemente tipado y orientado a objetos, diseñado específicamente para tener tan pocas dependencias de implementación como fuera posible.

Su lema es "Write Once, Run Anywhere" (Escribe una vez, ejecuta donde sea).

Breve Historia

Fue desarrollado por James Gosling en Sun Microsystems (ahora parte de Oracle) y lanzado en 1995. Su sintaxis deriva de C y C++, pero tiene menos utilidades de bajo nivel (como punteros explícitos).

Ecosistema Core

Entender las siglas clave de Java:

  • JDK (Java Development Kit): Herramientas para programar (compilador javac, etc).
  • JRE (Java Runtime Environment): Entorno para ejecutar programas ya compilados.
  • JVM (Java Virtual Machine): Máquina virtual que ejecuta el bytecode.

Ventajas Clave

  • 🟠 Independencia de plataforma gracias a la JVM.
  • 🟠 Fuerte gestión de memoria (Garbage Collector).
  • 🟠 Multihilo (Multi-threading) integrado.
  • 🟠 Gran comunidad y ecosistema inmenso (Spring, Maven, Gradle).
  • 🟠 Orientado a Objetos desde la base.

📖 Fundamentos del Lenguaje

Variables y Tipos

Tipos de Datos Primitivos

Java es fuertemente tipado, debes declarar el tipo de la variable. Tiene 8 tipos primitivos básicos que no son objetos.

int (32 bits) double (64 bits) boolean char byte long
int edad = 25;
double precio = 19.99;
boolean esValido = true;
char letra = 'A';
Control de Flujo

Condicionales y Bucles

Estructuras clásicas para controlar la lógica del programa.

if / else switch for while
if (edad >= 18) {
    System.out.println("Mayor");
}

for (int i = 0; i < 5; i++) {
    System.out.println(i);
}
Métodos

Funciones / Métodos

En Java, las funciones se llaman métodos porque siempre pertenecen a una clase. Deben definir qué tipo de dato retornan.

public static void return
public int sumar(int a, int b) {
    return a + b;
}
Estructuras

Arrays (Arreglos)

Estructuras de tamaño fijo que almacenan múltiples elementos del mismo tipo en memoria contigua.

int[] length Índice 0
int[] numeros = {10, 20, 30};
int primer = numeros[0]; // 10
int tamano = numeros.length; // 3
Seguridad

Manejo de Excepciones

Mecanismo para manejar errores en tiempo de ejecución asegurando que el programa no se detenga abruptamente.

try / catch finally throw
try {
    int x = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("Error matemático");
}
Organización

Paquetes e Imports

Agrupan clases relacionadas para evitar colisiones de nombres y controlar el acceso (funcionan como carpetas).

package import java.util.*
package com.miapp.util;

import java.util.Scanner;

public class Lector { }

🔍 Explicación Detallada

1. Control de Flujo (Condicionales y Bucles)

Condicionales (if / switch): Permiten tomar decisiones. Usa if-else cuando evalúas condiciones complejas o rangos. Usa switch cuando comparas una única variable contra muchos valores exactos (ideal para menús u opciones cerradas).

Ejemplo Condicional
int dia = 2;
switch (dia) {
    case 1: System.out.println("Lunes"); break;
    case 2: System.out.println("Martes"); break; // Imprime esto
    default: System.out.println("Otro día");
}

Bucles (for / while): Repiten bloques de código. Usa for cuando sabes exactamente cuántas veces vas a iterar (ej: recorrer un arreglo). Usa while cuando no sabes cuántas veces se ejecutará, sino que depende de una condición (ej: leer datos hasta que el usuario escriba "salir").

Ejemplo Bucle
// for: Se ejecuta 3 veces exactas
for (int i = 1; i <= 3; i++) {
    System.out.println("Iteración: " + i);
}

// while: Se ejecuta mientras la condición sea verdadera
int contador = 5;
while (contador > 0) {
    System.out.println(contador);
    contador--;
}

2. Tipos de Funciones (Métodos)

Los métodos pueden clasificarse según lo que devuelven y cómo reciben parámetros. Un método con void ejecuta una acción y no devuelve nada. Si tiene un tipo (ej. int, String), debe usar la palabra return. También existen métodos static (se llaman directamente desde la clase) y métodos de instancia (necesitan un objeto creado con new).

Tipos de Métodos
// Método que NO retorna valor (void)
public void saludar(String nombre) {
    System.out.println("Hola " + nombre);
}

// Método que SÍ retorna valor (int)
public int multiplicar(int a, int b) {
    return a * b;
}

3. Cómo recorrer Arrays (Arreglos)

Para recorrer arreglos en Java, lo más común es usar un bucle for clásico (cuando necesitas acceder mediante un número de índice exacto) o un bucle for-each (más limpio y directo cuando necesitas leer todos los elementos secuencialmente sin importar su posición).

Recorriendo Arreglos
String[] frutas = {"Manzana", "Pera", "Uva"};

// Forma clásica (cuando necesitas el índice)
for (int i = 0; i < frutas.length; i++) {
    System.out.println(i + ": " + frutas[i]);
}

// Forma for-each (más limpia y recomendada para solo lectura)
for (String f : frutas) {
    System.out.println(f);
}

4. Excepciones y Manejo de Errores

Las excepciones ocurren cuando algo sale mal en tiempo de ejecución (ej: un archivo no existe o se divide por cero). En lugar de que el programa "explote", lo "atrapamos" con try-catch. El bloque opcional finally se usa para ejecutar código pase lo que pase (ej: para asegurar que se cierre la conexión a una base de datos).

Manejo Try-Catch-Finally
try {
    int[] nums = {1, 2, 3};
    System.out.println(nums[5]); // ¡Error! El índice 5 no existe
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("Te saliste del límite del arreglo: " + e.getMessage());
} finally {
    System.out.println("Esto se imprime SIEMPRE, haya error o no.");
}

5. Paquetes e Importaciones

Para usar funcionalidades o clases de Java que no están en su paquete básico por defecto (java.lang), debes importarlas. Por ejemplo, para leer datos ingresados por el usuario desde el teclado usamos la clase Scanner, la cual vive dentro del paquete java.util.

Ejemplo Import y Scanner
import java.util.Scanner; // 1. Importar la clase externa

public class Entrada {
    public static void main(String[] args) {
        // 2. Crear el objeto Scanner leyendo del sistema (teclado)
        Scanner sc = new Scanner(System.in);
        
        System.out.print("Escribe tu nombre: ");
        String nombre = sc.nextLine(); // Leer línea de texto
        
        System.out.println("Hola, " + nombre);
        sc.close(); // Buena práctica: liberar el recurso
    }
}

6. Funciones Predeterminadas más Importantes

Java incluye miles de "funciones" (métodos) ya programadas dentro de sus librerías básicas. No necesitas programarlas desde cero, simplemente las usas. Aquí están los 4 grupos más indispensables para el día a día:

Manipulación de Textos (Clase String)

Sirven para transformar o analizar cadenas de texto (letras, palabras, frases).

String texto = "Hola Java";
texto.length();        // 9 (Devuelve la cantidad de caracteres)
texto.toUpperCase();   // "HOLA JAVA" (Convierte todo a mayúsculas)
texto.substring(0, 4); // "Hola" (Extrae un pedazo del texto)
texto.equals("java");  // false (Compara si dos textos son idénticos)

Operaciones Matemáticas (Clase Math)

Funciones listas para realizar cálculos complejos o de probabilidad sin tener que usar fórmulas manualmente.

Math.max(10, 20);      // 20 (Devuelve el número mayor)
Math.sqrt(64);         // 8.0 (Calcula la raíz cuadrada)
Math.pow(2, 3);        // 8.0 (Potencia: 2 elevado a 3)
Math.random();         // 0.741... (Genera un número aleatorio entre 0.0 y 1.0)

Utilidades para Arreglos (Clase Arrays)

Requiere import java.util.Arrays; y te ahorra tener que hacer bucles manuales para ordenar o comparar arreglos.

int[] numeros = {5, 1, 9};
Arrays.sort(numeros);                 // Ordena el arreglo internamente a: {1, 5, 9}
Arrays.toString(numeros);             // Convierte a texto: "[1, 5, 9]" (Muy útil para imprimir)
Arrays.equals(arreglo1, arreglo2);    // Devuelve true si ambos arreglos tienen lo mismo

Consola y Sistema (Clase System)

Permite interactuar con el entorno donde corre el programa (como la terminal).

System.out.println("Texto");        // Imprime en consola y hace un salto de línea
System.out.print("Texto");          // Imprime sin salto de línea
System.currentTimeMillis();         // Devuelve el tiempo actual en milisegundos (útil para cronómetros)
System.exit(0);                     // Apaga y finaliza el programa entero

🧱 Programación Orientada a Objetos (POO)

Clases y Objetos

Una Clase es un molde (plantilla) que define atributos y métodos. Un Objeto es una instancia real creada a partir de esa clase usando la palabra clave new.

class new Instancia

Encapsulamiento

Ocultar el estado interno de un objeto y requerir que toda interacción se realice mediante métodos (getters/setters). Protege los datos.

private public getters / setters

Herencia

Permite crear una nueva clase basada en una existente (padre), heredando sus atributos y métodos, fomentando la reutilización de código.

extends super Subclase

Polimorfismo

La capacidad de un objeto de tomar muchas formas. Permite tratar a objetos de clases derivadas como si fueran de su clase base, llamando métodos sobreescritos.

@Override Sobrecarga Sobreescritura

Abstracción

Ocultar los detalles de implementación complejos y mostrar solo las características esenciales. Se logra usando clases abstractas o interfaces.

abstract class

Interfaces

Un contrato de métodos vacíos. Si una clase implementa una interfaz, debe proveer el código para esos métodos. Permite "herencia múltiple" de tipos en Java.

interface implements

🔍 POO en Acción (Ejemplos)

1. Clases y Objetos

Piensa en la clase como el "plano" de una casa, y en los objetos como "casas reales" construidas a partir de ese plano. La palabra clave new reserva espacio en memoria para instanciar (crear) ese nuevo objeto.

Creación e Instanciación
// 1. El plano (Clase)
public class Coche {
    String marca;
    public void arrancar() {
        System.out.println("Brum brum!");
    }
}

// 2. Creando la casa real (Objeto)
Coche miAuto = new Coche();
miAuto.marca = "Toyota";
miAuto.arrancar();

2. Encapsulamiento

Ocultamos las variables directamente usando private para que nadie pueda modificarlas con valores inválidos (por ejemplo, poner un saldo negativo en un banco). Usamos métodos public (conocidos como getters y setters) como intermediarios seguros.

Getters y Setters
public class CuentaBancaria {
    private double saldo; // ¡Protegido de modificaciones directas!

    public void setSaldo(double cantidad) {
        if (cantidad >= 0) {
            this.saldo = cantidad;
        } else {
            System.out.println("Error: El saldo no puede ser negativo");
        }
    }
    
    public double getSaldo() {
        return this.saldo;
    }
}

3. Herencia y Polimorfismo

La herencia (extends) permite reutilizar atributos y métodos de una clase padre. El polimorfismo (@Override) permite que una clase hija modifique cómo funciona exactamente un método del padre para adaptarlo a su propia naturaleza.

Extends & Override
// Clase Padre
public class Animal {
    public void hacerSonido() {
        System.out.println("Sonido genérico...");
    }
}

// Clase Hija (Aplica Herencia)
public class Perro extends Animal {
    // Polimorfismo: Modifico y sobreescribo el comportamiento
    @Override
    public void hacerSonido() {
        System.out.println("¡Guau, Guau!");
    }
}

4. Abstracción e Interfaces

Una interface dicta qué debe hacerse, pero no cómo. Es como firmar un contrato. Cualquier clase que la implemente (implements) está obligada a escribir el código exacto de esos métodos vacíos.

Implementando Contratos
// El contrato: Todas las bases de datos deben saber cómo conectarse
public interface ConexionDB {
    void conectar();
}

// Cumpliendo el contrato obligatoriamente
public class MySQL implements ConexionDB {
    @Override
    public void conectar() {
        System.out.println("Conectando a base de datos MySQL en el puerto 3306...");
    }
}

🗂️ API de Colecciones

Estructuras de datos dinámicas en Java. A diferencia de los Arrays básicos, las colecciones pueden crecer y reducir su tamaño automáticamente.

List (Listas)

Colección ordenada que permite elementos duplicados. El elemento más común es ArrayList.

List<String> lista = new ArrayList<>();
lista.add("Java");
lista.add("Python");
String lenguaje = lista.get(0); // "Java"

Set (Conjuntos)

Colección que NO permite duplicados. HashSet es el más rápido pero no mantiene un orden garantizado.

Set<Integer> numeros = new HashSet<>();
numeros.add(1);
numeros.add(1); // Ignorado
boolean tiene = numeros.contains(1); // true

Map (Mapas / Diccionarios)

Estructura clave-valor. La clave no puede estar duplicada. HashMap es la implementación estrella.

Map<String, Integer> edades = new HashMap<>();
edades.put("Ana", 25);
int edad = edades.get("Ana"); // 25

Streams API (Java 8+)

Procesamiento funcional de colecciones. Permite filtrar, mapear y reducir datos de forma elegante.

lista.stream()
     .filter(lang -> lang.startsWith("J"))
     .forEach(System.out::println);

💻 Tu Primer Programa (Hello World)

Paso 1: Escribir el código

1

Crea un archivo llamado HolaMundo.java. Importante: El nombre del archivo debe coincidir exactamente con el nombre de la clase public.

2

El punto de entrada de todo programa Java es el método public static void main(String[] args).

HolaMundo.java
public class HolaMundo {
    public static void main(String[] args) {
        // Imprime un mensaje en la consola
        System.out.println("¡Hola, Mundo desde Java!");
    }
}

Paso 2: Compilar y Ejecutar en Terminal

3

Compilar transforma tu código humano (.java) en bytecode (.class) que la JVM entiende, usando el comando javac.

4

Ejecutar arranca la JVM para correr tu archivo .class generado, usando el comando java (sin la extensión).

TERMINAL CLI
# 1. Compilar
javac HolaMundo.java

# (Esto generará un archivo HolaMundo.class)

# 2. Ejecutar
java HolaMundo
📋 Copiar