Saltar a contenido

3. Estructura de un programa Java

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.1 — Se han identificado los bloques que componen la estructura de un programa informático.
CE 1.9 — Se han introducido comentarios en el código.
Marco normativo RD 405/2023 · RD 450/2010 · RD 659/2023
Tecnología base Java 25 LTS — implicitly declared classes e instance main methods estables (JEP 512: Compact Source Files and Instance Main Methods).

Introducción de la sección

En la Sección 2 escribiste tu primer programa Java 25 con cuatro líneas y la verdad es que no te expliqué qué significaba casi nada de lo que pusiste. Esa era la idea: primero pruebes que el entorno funciona y luego, una vez has visto que un void main() es capaz de imprimir "Hola, mundo", entenderemos qué pinta tiene un programa Java por dentro, palabra por palabra. Esta es la sección en la que eso ocurre.

El objetivo es que al terminar sepas descomponer cualquier programa Java sencillo en sus piezas: la clase (que en Java 25 puede ser implícita), el método main (que es la puerta de entrada), las instrucciones de salida por consola (println, print, printf), las reglas sintácticas que no puedes saltarte (punto y coma, llaves, sensibilidad a mayúsculas), los tres tipos de comentarios que admite el lenguaje y las convenciones de nomenclatura que todo programador Java respeta. Verás también los cinco o seis errores que comete el 99% de los principiantes en sus primeros días, para que los reconozcas en cuanto el compilador te los escupa a la cara. Cuando acabes, leer el App.java de la Sección 2 te parecerá trivial.


3.1 Elementos léxicos del lenguaje Java: el mapa antes del territorio

Antes de abrir el capó de un programa Java y mirar el motor (la clase, el método main, las instrucciones de salida), conviene ver el mapa completo de las piezas que puedes encontrar. Un programa Java está construido a partir de seis categorías de elementos léxicos: palabras reservadas, identificadores, literales, separadores, operadores y comentarios. Conocer esta taxonomía te ahorrará confusión cuando, en las próximas secciones, veas aparecer cada uno por separado.

Analogía

Aprender un lenguaje de programación se parece a aprender un idioma natural. En español hay sustantivos, verbos, adjetivos, preposiciones y signos de puntuación; cada categoría tiene sus reglas. En Java pasa lo mismo: hay palabras reservadas (los verbos irregulares del lenguaje, que Java se reserva para sí mismo), identificadores (los sustantivos que tú eliges), literales (los valores concretos como 42 o "hola"), separadores (los signos de puntuación), operadores (las conjunciones que combinan valores) y comentarios (las acotaciones del autor que el compilador ignora). Saber qué categoría es cada cosa es la mitad del trabajo para entender un programa.

3.1.1 Palabras reservadas (keywords)

Las palabras reservadas son términos que el lenguaje Java usa para sí mismo y que tú no puedes usar como identificadores (nombres de variables, clases, métodos...). Java 25 tiene alrededor de 50 palabras reservadas, agrupadas por función:

Categoría Palabras
Tipos primitivos byte, short, int, long, float, double, boolean, char
Control de flujo if, else, switch, case, default, for, while, do, break, continue, return
Orientación a objetos class, interface, enum, record, extends, implements, new, this, super, instanceof
Modificadores public, protected, private, static, final, abstract, synchronized, volatile, transient, native, strictfp
Manejo de errores try, catch, finally, throw, throws
Paquetes package, import
Otros void, assert, goto, const

Cuidado

goto y const están reservadas pero no se usan en Java (existen por compatibilidad histórica con C/C++). Si intentas usarlas como identificadores, el compilador las rechaza.

Además, Java tiene palabras contextuales (restricted keywords) que solo son reservadas en ciertos contextos: var (desde Java 10), record (Java 16), sealed y permits (Java 17), yield (Java 14). Y los literales booleanos true, false y el literal nulo null también están reservados, aunque técnicamente no son keywords.

3.1.2 Identificadores

Un identificador es el nombre que tú eliges para una variable, constante, método, clase, paquete o parámetro. Debe cumplir dos reglas:

  1. Empezar por una letra (incluida la ñ y letras Unicode), un guion bajo _ o el símbolo dólar $.
  2. Continuar con letras, dígitos, guiones bajos o dólares (sin espacios ni otros símbolos).
1
2
3
4
5
6
7
8
int edad;              // identificador válido
int nota_media;        // válido (usa _)
int $contador;         // válido (usa $, pero desaconsejado)
int año2026;           // válido (letras Unicode permitidas)
int 2edad;             // ERROR: empieza por dígito
int nota-media;        // ERROR: contiene guion
int nota media;        // ERROR: contiene espacio
int public;            // ERROR: palabra reservada

Pista

Aunque Java permite _ y $ en identificadores, las convenciones de Oracle los desaconsejan (excepto _ en constantes UPPER_SNAKE_CASE y $ en código generado automáticamente). Las convenciones de nomenclatura completas (camelCase, PascalCase, UPPER_SNAKE_CASE) se ven en la Sección 3.7 Convenciones de nomenclatura.

3.1.3 Literales

Un literal es un valor escrito directamente en el código: 42, 3.14, "hola", true, 'A'. Java tiene literales enteros, decimales, booleanos, de carácter y de cadena. Su tratamiento en profundidad (rangos, sufijos L/f/d, separador _, notación hexadecimal/binaria/octal) corresponde a la Sección 4 (Variables y tipos primitivos) y a la Sección 5 (El tipo String).

3.1.4 Separadores

Los separadores son símbolos que estructuran el código. Java tiene nueve:

Símbolo Uso típico
( ) Delimitar parámetros, agrupar expresiones, llamadas a método
{ } Delimitar bloques (clase, método, if, for...)
[ ] Declarar y acceder a arrays
; Finalizar una instrucción
, Separar elementos (parámetros, declaraciones múltiples...)
. Acceso a miembros (objeto.metodo(), Clase.CAMPO)
... Varargs (parámetros de número variable)
@ Anotaciones

3.1.5 Operadores

Los operadores son símbolos que realizan operaciones sobre valores: +, -, *, /, ==, &&, ++, ?:, ::, ... Java tiene más de 40 operadores repartidos en categorías (aritméticos, relacionales, lógicos, bit a bit, asignación). Su tratamiento completo corresponde a la Sección 7 (Operadores).

3.1.6 Comentarios

Los comentarios son texto que el compilador ignora y que sirve para documentar el código. Java admite tres tipos: // (línea), /* */ (bloque) y /** */ (Javadoc). Se tratan en detalle en la Sección 3.6 Comentarios.

Mapa mental de los elementos léxicos

mindmap
  root((Elementos léxicos<br/>de Java))
    Palabras reservadas
      Tipos primitivos
      Control de flujo
      OO (class, new, this)
      Modificadores
      Manejo de errores
      Paquetes
    Identificadores
      Variables
      Constantes
      Métodos
      Clases
      Paquetes
    Literales
      Enteros
      Decimales
      Booleanos
      Carácter
      Cadena
    Separadores
      Paréntesis
      Llaves
      Corchetes
      Punto y coma
      Coma, punto
    Operadores
      Aritméticos
      Relacionales
      Lógicos
      Bit a bit
      Asignación
    Comentarios
      Línea
      Bloque
      Javadoc

3.2 De la clase clásica al main moderno: evolución del punto de entrada

La ceremonia histórica de Java

Si abres cualquier manual de Java escrito antes de 2024, tu primer programa se parecerá a este:

1
2
3
4
5
public class HolaMundo {
    public static void main(String[] args) {
        System.out.println("Hola, mundo");
    }
}

Cinco líneas, cuatro palabras clave raras (public, class, static, void), un nombre obligatorio (main), un parámetro obligatorio (String[] args) y una clase obligatoria con el mismo nombre que el fichero. Para alguien que nunca ha programado, eso es mucha ceremonia antes de poder imprimir "Hola". Históricamente, se ha pedido simplificar el primer contacto con el lenguaje, porque la curva de entrada era una de las cosas que alejaba a la gente de Java frente a Python.

La buena noticia es que, en Java 25, todo eso es opcional. El mismo programa se escribe ahora así:

1
2
3
void main() {
    IO.println("Hola, mundo");
}

Tres líneas, dos palabras clave (void, main), sin clase visible y sin parámetros. Esto es posible gracias a dos características que llegaron como preview en Java 21 (JEP 445) y se estabilizaron en Java 25 con el JEP 512: Compact Source Files and Instance Main Methods: las implicitly declared classes (clases declaradas implícitamente, también llamadas compact source files en la primera versión del JEP) y los instance main methods (métodos main de instancia, sin static). El compilador, por debajo, te envuelve todo en una clase implícita que toma el nombre del fichero; tú no la ves declarada, pero existe.

La evolución, en un diagrama

timeline
    title Evolución del punto de entrada en Java
    1996 (Java 1.0) : public static void main(String[] args) - Forma clásica obligatoria durante 27 años
    2023 (Java 21 preview) : void main() - JEP 445 primera preview, opt-in
    2024 (Java 22-23 preview) : void main() - Segunda y tercera preview con ajustes
    2025 (Java 25 LTS) : void main() - ESTABLE (JEP 512), sin --enable-preview

Diagrama 3.1 — Evolución del método main en Java, desde la forma clásica de 1996 hasta la forma moderna estable de 2025.

¿Cuándo usar cada forma?

Esta es una pregunta con matices. La forma moderna void main() es perfecta para aprender, para programas pequeños, para ejemplos de documentación y para herramientas de prototipado. La forma clásica public static void main(String[] args) sigue siendo necesaria cuando:

  • Estás escribiendo código que tiene que correr en versiones anteriores a Java 25 (por ejemplo, en una empresa que aún usa Java 17 LTS).
  • El programa va a crecer y quieres declarar la clase explícitamente desde el principio para tenerlo todo organizado.

En este ciclo empezaremos con la forma moderna para que la curva de entrada sea suave, e iremos introduciendo la forma clásica cuando el contexto lo pida (a partir de UD4, cuando definamos clases propias con campos y métodos). Lo importante es que no hay una forma "incorrecta": ambas producen el mismo bytecode y se ejecutan igual.

Analogía

La forma clásica con public class es como escribir una carta formal con membrete, fecha, encabezado "Estimado Sr." y despedida "Atentamente". Es lo que toca en un contexto formal. La forma moderna void main() es como escribir un WhatsApp a un amigo: vas al grano, sin protocolo. Las dos comunican lo mismo; la diferencia es el contexto y la audiencia.


3.3 Anatomía de una clase y del método main

Vamos a despiezar el programa clásico pieza por pieza. Aunque en Java 25 puedas omitir la clase, conviene saber qué significaba cada palabra clave, porque en UD4 las vas a usar todas y porque el 90% del código Java que encuentres en internet y en empresas sigue la forma clásica.

flowchart TD
    A["public class HolaMundo {"] --> B["public - la clase es visible desde cualquier otro paquete"]
    A --> C["class - palabra clave para declarar una clase"]
    A --> D["HolaMundo - nombre de la clase en PascalCase"]
    A --> E["{ - abre el bloque de la clase"]

    F["public static void main(String[] args) {"] --> G["public - el método es visible desde fuera"]
    F --> H["static - método de clase, no necesita crear un objeto"]
    F --> I["void - no devuelve ningún valor"]
    F --> J["main - nombre obligatorio, lo busca la JVM"]
    F --> K["String[] args - parámetros: argumentos de línea de comandos"]
    F --> L["{ - abre el bloque del método"]

    E -.->|contiene| F
    L -.->|contiene| M["System.out.println(...);"]
    M --> N["} - cierra el método"]
    N --> O["} - cierra la clase"]

    style A fill:#1565c0,color:#fff,stroke:#0d47a1
    style F fill:#2e7d32,color:#fff,stroke:#1b5e20
    style M fill:#e65100,color:#fff,stroke:#bf360c
    style B fill:#e3f2fd,stroke:#1565c0,color:#000
    style C fill:#e3f2fd,stroke:#1565c0,color:#000
    style D fill:#e3f2fd,stroke:#1565c0,color:#000
    style E fill:#e3f2fd,stroke:#1565c0,color:#000
    style G fill:#e8f5e9,stroke:#2e7d32,color:#000
    style H fill:#e8f5e9,stroke:#2e7d32,color:#000
    style I fill:#e8f5e9,stroke:#2e7d32,color:#000
    style J fill:#e8f5e9,stroke:#2e7d32,color:#000
    style K fill:#e8f5e9,stroke:#2e7d32,color:#000
    style L fill:#e8f5e9,stroke:#2e7d32,color:#000

Diagrama 3.2 — Anatomía completa de un programa Java clásico: cada palabra clave explicada.

La clase como contenedor obligatorio

En Java, todo el código ejecutable vive dentro de una clase. No existen funciones sueltas como en C o Python; cualquier instrucción que se ejecute tiene que estar dentro de un método, y cualquier método tiene que estar dentro de una clase. Esto es una decisión de diseño del lenguaje vinculada a su naturaleza 100% orientada a objetos. En Java 25, las implicitly declared classes simplemente ocultan esta clase de tu vista: el compilador la crea por ti, le pone como nombre el del fichero (por ejemplo, Main.java → clase Main) y la registra. Pero la clase existe.

Palabra Significado ¿Obligatoria en Java 25 moderno?
public Modificador de acceso: visible desde cualquier paquete No (la clase implícita no es pública)
class Palabra clave para declarar una clase No (la añade el compilador)
HolaMundo Nombre de la clase, debe coincidir con el nombre del fichero No (clase implícita sin nombre)
{ } Llaves que delimitan el bloque de la clase Sí, aunque implícitas

El método main como punto de entrada

El método main es la puerta de entrada que busca la JVM cuando ejecutas un programa. La JVM arranca, busca una clase (explícita o anónima) que tenga un método llamado main con una firma concreta, y empieza a ejecutar desde ahí. Si no lo encuentra, el programa no arranca.

Palabra Significado ¿Obligatoria en Java 25 moderno?
public El método es accesible desde la JVM (que está "fuera" de tu clase) No (el launcher la infiere; se recomienda en forma clasica)
static Método de clase, no requiere crear un objeto para llamarse No (instance main)
void El método no devuelve ningún valor
main Nombre obligatorio, la JVM lo busca
String[] args Parámetros: argumentos pasados por línea de comandos Opcional
{ } Llaves que delimitan el bloque del método

Analogía

Imagina que tu programa es un edificio y la JVM es el repartidor que llega con un paquete. El repartidor no sabe por dónde entrar; busca una puerta con un cartel que diga "ENTRADA". En Java, ese cartel es la palabra main. Si no la encuentra, se da la vuelta y se va (y te muestra un error). El parámetro String[] args sería el portero que te pide el paquete de datos que has traído desde la línea de comandos; si no necesitas pasarle nada, puedes omitirlo en Java 25.

No te preocupes ahora por entender static a fondo: en UD4, cuando veamos clases y objetos, entenderás la diferencia entre métodos de clase (static) y métodos de instancia. Por ahora basta con que sepas que en Java 25 ya no hace falta para que main arranque.

La regla del nombre del fichero

Una regla que sí sigue vigente en Java 25: si declaras una clase public (es decir, escribes public class HolaMundo), el fichero donde vive debe llamarse exactamente HolaMundo.java, con las mismas mayúsculas y minúsculas. Si no coinciden, el compilador se queja. En cambio, con una implicitly declared class (sin public class explícito), el fichero debe llamarse igual que la clase implícita resultante (por ejemplo, Main.java produce una clase Main).

1
2
3
4
5
6
// Fichero: HolaMundo.java  (ojo: el nombre del fichero debe coincidir)
public class HolaMundo {
    public static void main(String[] args) {
        System.out.println("Hola, mundo");
    }
}
1
2
3
4
// Fichero: loquequieras.java  (sin clase pública, sin restricción de nombre)
void main() {
    IO.println("Hola, mundo");
}

3.4 Salida por consola: println, print y printf

Ya sabes imprimir texto con System.out.println("Hola"). Vamos a ver las tres variantes que ofrece Java para sacar información por consola, porque cada una tiene su caso de uso y conviene elegir bien. Además, desde la versión 25, una de las aportaciones complementarias más importantes del JEP 512: la introducción de la clase utilitaria java.lang.IO que nos va a permitir usar la entrada y salida de la información de una forma más sencilla.

Las tres variantes

Método Qué hace Salto de línea al final Cuándo usar
System.out.println(x)
IO.println(x)
Imprime x y salta de línea Caso general, mensajería simple
System.out.print(x)
IO.print(x)
Imprime x sin saltar de línea No Cuando quieres componer una línea en varios pasos
System.out.printf(fmt, args) Imprime con formato (estilo C) No (hay que añadir %n) Cuando necesitas alinear columnas, decimales, etc.

println vs print

La diferencia entre println y print es solo el salto de línea final, pero cambia bastante el comportamiento:

1
2
3
4
5
IO.print("Hola, ");
IO.print("esto sale ");
IO.print("en una sola línea.");
IO.println();          // println sin argumentos solo salta de línea
IO.println("Y esto en otra.");

Salida:

Hola, esto sale en una sola línea.
Y esto en otra.

println sin argumentos es un truco útil cuando quieres un salto de línea "limpio" sin imprimir nada más.

printf: cuando necesitas formatear

printf (print formatted) es la opción potente para cuando necesitas controlar el formato: número de decimales, alineación, relleno con ceros, etc. Funciona con especificadores de formato que empiezan por %:

1
2
3
4
5
String nombre = "Ana";
int edad = 23;
double notaMedia = 8.75;

System.out.printf("Alumna: %s, edad: %d, nota: %.2f%n", nombre, edad, notaMedia);

Salida:

Alumna: Ana, edad: 23, nota: 8,75

Los especificadores más usados en este curso son:

Especificador Tipo Ejemplo Salida
%s String printf("Hola, %s", "Ana") Hola, Ana
%d Entero (int, long) printf("Edad: %d", 23) Edad: 23
%f Decimal (float, double) printf("PI: %f", 3.14159) PI: 3,141590
%.2f Decimal con 2 decimales printf("PI: %.2f", 3.14159) PI: 3,14
%n Salto de línea portable printf("Línea%n") Línea + salto
%% Un símbolo % literal printf("100%%") 100%
%5d Entero en 5 caracteres printf("[%5d]", 42) [ 42]
%-5d Entero en 5 caracteres, alineado a la izquierda printf("[%-5d]", 42) [42 ]

Info

Las veremos y usaremos poco a poco en las siguientes secciones.

Pista

En Java 15+ también tienes el método formatted sobre Strings, que es más legible cuando tienes varios valores: "Alumna: %s, edad: %d".formatted(nombre, edad). Internamente hace lo mismo que printf, pero devuelve el String en lugar de imprimirlo. Útil cuando quieres formatear sin imprimir todavía.

Cuidado con la coma decimal. En sistemas con locale español, printf usa la coma como separador decimal (8,75); en sistemas con locale inglés, usa el punto (8.75). Si necesitas que el formato sea consistente independientemente del país, puedes forzar el locale: System.out.printf(java.util.Locale.US, "PI: %.2f", 3.14159) siempre producirá PI: 3.14.


3.5 Reglas sintácticas: mayúsculas, punto y coma, bloques

Java es un lenguaje de sintaxis estricta, lo que significa que el compilador no perdona casi nada. Esto asusta al principio, pero es una virtud: te obliga a ser preciso y te ahorra sorpresas en producción. Hay cuatro reglas que no puedes saltarte.

Regla 1: sensibilidad a mayúsculas y minúsculas

Java distingue entre mayúsculas y minúsculas en todo: nombres de variables, clases, métodos, palabras clave. edad, Edad y EDAD son tres identificadores distintos para Java. system.out.println no compila; tiene que ser System.out.println. Esto es lo primero que se le olvida a quien viene de Python o HTML, donde la cosa es más laxa.

Código ¿Compila? Por qué
System.out.println("hola") System con mayúscula inicial
system.out.println("hola") No system en minúscula no existe
int edad = 18; System.out.println(Edad) No Edad y edad son distintas
public class Main en main.java No La clase Main no coincide con el fichero main.java

Regla 2: el punto y coma es obligatorio

Cada instrucción en Java debe terminar con punto y coma (;). Es como el punto y seguido en español: indica que la frase termina ahí. Si te dejas uno, el compilador te lo dirá con un mensaje tipo ';' expected. Si pones uno de más, también se queja.

1
2
3
4
int edad = 18;                              // bien
System.out.println("Tienes " + edad);       // bien
int altura = 175                            // MAL: falta punto y coma
System.out.println("Altura: " + altura);    // bien

Regla 3: los bloques se delimitan con llaves { }

Un bloque es un conjunto de instrucciones agrupadas entre llaves { y }. Los bloques definen el cuerpo de una clase, el cuerpo de un método, el cuerpo de un if, etc. Las llaves deben estar equilibradas: cada { tiene que tener su } correspondiente. IntelliJ te los marca en color y te permite saltar entre ellos con Ctrl+M (o Cmd+M en macOS).

1
2
3
4
5
6
7
public class Ejemplo {              // abre bloque clase
    public static void main(String[] args) {   // abre bloque método
        if (true) {                  // abre bloque if
            System.out.println("sí");
        }                            // cierra bloque if
    }                                // cierra bloque método
}                                    // cierra bloque clase

Analogía

Las llaves son como las paredes de las habitaciones de una casa. La clase es la casa entera; el método main es una habitación dentro de la casa; el if es un armario dentro de la habitación. Cada { es una puerta que entra a un espacio más pequeño; cada } es la puerta que sale. Si te dejas una } sin cerrar, la "casa" se queda abierta y el compilador no sabe dónde termina cada cosa.

Regla 4: el espacio en blanco es libre (casi)

Java no le importa cuántos espacios o saltos de línea pongas entre tokens, salvo dentro de strings. Estos tres programas son equivalentes para el compilador:

// Forma compacta (no recomendada, ilegible)
public class A{public static void main(String[] a){System.out.println("hola");}}
1
2
3
4
5
6
// Forma espaciada (recomendada)
public class A {
    public static void main(String[] a) {
        System.out.println("hola");
    }
}
// Forma extravagante (compila pero tu profesor te suspenderá)
public
    class
        A
{
    public
        static
            void
                main
                    (String[] a)
    {
        System.out.println("hola");
    }
}

Los tres compilan. El que tu profesor (y tus compañeros, y tú mismo dentro de tres meses) querrá leer es el segundo. Por eso existen convenciones de estilo: no son obligatorias para el compilador, pero sí para trabajar en equipo. En IntelliJ, Ctrl+Alt+L (o Cmd+Option+L en macOS) formatea el código automáticamente según las convenciones de Oracle.


3.6 Comentarios: //, /* */ y Javadoc /** */

Los comentarios son texto que el compilador ignora. Sirven para que tú (o quien venga detrás) entendáis qué hace el código y por qué. Java admite tres tipos, cada uno con su propósito.

flowchart LR
    COM["Comentarios en Java"] --> LINE["// Comentario de línea"]
    COM --> BLOCK["/* Comentario<br/>de bloque */"]
    COM --> DOC["/** Comentario<br/>Javadoc */"]

    LINE --> L1["Notas rápidas, aclaraciones puntuales"]
    LINE --> L2["El más usado en el día a día"]

    BLOCK --> B1["Varias líneas seguidas"]
    BLOCK --> B2["Comentar código temporalmente (mejor evitarlo)"]

    DOC --> D1["Documentación de API pública"]
    DOC --> D2["Genera HTML con la herramienta javadoc"]
    DOC --> D3["Soporta etiquetas: @param, @return, @author..."]

    style COM fill:#1565c0,color:#fff,stroke:#0d47a1
    style LINE fill:#e8f5e9,stroke:#2e7d32,color:#000
    style BLOCK fill:#fff3e0,stroke:#e65100,color:#000
    style DOC fill:#f3e5f5,stroke:#6a1b9a,color:#000

Diagrama 3.3 — Los tres tipos de comentarios en Java y sus casos de uso.

Comentario de línea: //

El más usado. Todo lo que va desde // hasta el final de la línea es ignorado por el compilador.

1
2
3
int edad = 18;  // edad del alumno en años
// La línea siguiente calcula la nota media ponderada
double nota = (examen1 * 0.4) + (examen2 * 0.6);

Comentario de bloque: /* ... */

Para comentarios que ocupan varias líneas. Puede ir en cualquier posición (incluso en medio de una línea, aunque no es recomendable).

1
2
3
4
5
/* Este programa calcula el área de un círculo
   a partir de su radio, introducido por teclado.
   Fórmula: área = PI * radio * radio
*/
double area = Math.PI * radio * radio;

Cuidado

No uses comentarios de bloque para "comentar" código que ya no quieres ejecutar. IntelliJ tiene un atajo mucho mejor: selecciona el código y pulsa Ctrl+/ (comentar/descomentar con //) o Ctrl+Shift+/ (con /* */). Y si el código ya no sirve, bórralo: para eso está git. Código comentado es ruido que confunde a quien lee.

Javadoc: /** ... */

Es un tipo especial de comentario que documenta tu código. Empieza con /** (doble asterisco) y contiene etiquetas como @param, @return, @author, @see, @throws. La herramienta javadoc (que viene con el JDK) procesa estos comentarios y genera documentación HTML navegable, como la del API oficial de Java.

/**
 * Calcula el área de un círculo dado su radio.
 *
 * @param radio el radio del círculo, en metros (debe ser positivo)
 * @return el área del círculo, en metros cuadrados
 * @throws IllegalArgumentException si el radio es negativo
 * @author DAM 26-27
 * @see Math#PI
 */
public double areaCirculo(double radio) {
    if (radio < 0) {
        throw new IllegalArgumentException("El radio no puede ser negativo");
    }
    return Math.PI * radio * radio;
}

No te agobies por las etiquetas: las verás en detalle en UD2 (cuando uses clases del API) y UD4 (cuando escribas las tuyas). Por ahora basta con que sepas que existen y que IntelliJ te las autocompleta cuando escribes /** y pulsas Enter encima de una declaración.

Cuándo comentar y cuándo no

Una buena regla: el código bien escrito se explica a sí mismo; los comentarios deben explicar el por qué, no el qué. Si tienes que escribir // incrementa i en 1 encima de i++, el comentario sobra. Si escribes // se suma 1 porque el ID 0 está reservado para el sistema, ese comentario sí aporta valor.

Tipo de comentario Útil para Evita
Explicar el qué Casi nunca // asigna 5 a x
Explicar el por qué Decisiones de diseño, workarounds
Documentar API pública Clases y métodos públicos (Javadoc) Documentar lo obvio
Marcar TODOs // TODO: refactorizar cuando esté UD4 Acumular decenas sin hacerlos

3.7 Convenciones de nomenclatura: camelCase, PascalCase, UPPER_SNAKE_CASE

Java no te obliga por ley a llamar a los elementos de tu programa de una manera concreta, pero toda la industria sigue las convenciones de Oracle (heredadas de Sun). Respetarlas no es opcional en la práctica: si las sigues, tu código se lee como "Java de verdad"; si no, se lee como "código de alguien que viene de otro lenguaje y no se ha adaptado o que no sabe programar".

Los tres estilos

flowchart TD
    N["Nomenclatura Java"] --> C["camelCase"]
    N --> P["PascalCase"]
    N --> U["UPPER_SNAKE_CASE"]
    N --> PKG["todo.en.minusculas"]

    C --> C1["Variables y métodos"]
    C --> C2["edad, calcularNotaMedia, nombreCompleto"]

    P --> P1["Clases, interfaces, records, enums"]
    P --> P2["Alumno, CalculadoraNotas, ListaCompras"]

    U --> U1["Constantes (final o static final)"]
    U --> U2["MAX_INTENTOS, PI, IVA_GENERAL"]

    PKG --> PKG1["Paquetes"]
    PKG --> PKG2["jams.programacion.ud1"]

    style N fill:#1565c0,color:#fff,stroke:#0d47a1
    style C fill:#e8f5e9,stroke:#2e7d32,color:#000
    style P fill:#fff3e0,stroke:#e65100,color:#000
    style U fill:#ffebee,stroke:#c62828,color:#000
    style PKG fill:#f3e5f5,stroke:#6a1b9a,color:#000

Diagrama 3.4 — Convenciones de nomenclatura en Java y cuándo usar cada una.

Tabla resumen

Elemento Estilo Ejemplos Notas
Variables camelCase edad, nombreCompleto, notaMedia Empieza en minúscula, cada palabra siguiente en mayúscula
Métodos camelCase calcular(), obtenerNotaMedia() Verbos en infinitivo
Clases PascalCase Alumno, CalculadoraNotas Sustantivos
Interfaces PascalCase Comparable, List A veces adjetivos (Runnable)
Records PascalCase Punto, Coordenada Como clases
Enums PascalCase (tipo), UPPER_SNAKE (valores) DiaSemana.LUNES Los valores en mayúsculas
Constantes UPPER_SNAKE_CASE MAX_INTENTOS, PI, IVA_GENERAL final o static final
Paquetes todo.minusculas.sin.guiones jams.programacion.ud1 Dominio invertido

Por qué importa tanto

Analogía

Las convenciones de nomenclatura son como la forma de vestir en un contexto profesional. No hay ninguna ley que te obligue a ir con camisa a una entrevista, pero si vas en chándal, el entrevistador se hace una idea de ti antes de que abras la boca. Con el código pasa lo mismo: si tus clases se llaman alumno (minúscula) o ALUMNO (mayúsculas) o alumno_clase (snake case), cualquier programador Java experimentado pensará "no ha programado en Java de verdad". Si las llamas Alumno, encajas en la comunidad y tu código se lee natural.

Reglas adicionales

  • Los nombres deben ser significativos: edad sí, e no (salvo en bucles muy cortos como for (int i = 0; ...)).
  • Evita abreviaturas oscuras: calcularNotaMedia sí, calcNM no.
  • Los nombres booleanos suelen ser preguntas: esMayorEdad, tienePermiso, puedeConducir.
  • No uses _ como prefijo (_nombre) ni $ salvo en código generado automáticamente.

3.8 Paquetes y la sentencia package

Qué es un paquete y por qué existe

Un paquete en Java es un namespace (espacio de nombres) que agrupa clases relacionadas. Cumple tres funciones: organiza el código en estructuras jerárquicas, evita colisiones entre clases con el mismo nombre y controla la visibilidad entre clases de distintos paquetes.

Analogía

Un paquete es como una carpeta en un archivador. Si todos los documentos estuvieran en una sola carpeta, encontrarías el caos: decenas de ficheros con nombres parecidos, sin saber cuál pertenece a qué proyecto. Los paquetes permiten organizar el código igual que organizas tus apuntes: una carpeta para jams/, dentro otra para programacion/, dentro otra para ud1/, y dentro los ficheros de cada ejercicio.

La sentencia package

La primera línea (no vacía, sin contar comentarios) de cualquier fichero .java que declare una clase debe indicar a qué paquete pertenece:

1
2
3
4
5
6
package jams.programacion.ud1;

public class Main {
    IO.println("Inicio");
    // ...
}

Esta sentencia es obligatoria en todo fichero que declare una clase explícita (con public class o class). La única excepción son las implicitly declared classes de Java 25, donde puedes omitirla y la clase queda en el "paquete por defecto" (sin nombre); pero esta práctica se desaconseja en proyectos reales porque impide importar la clase desde otros paquetes.

Correspondencia paquete ↔ directorio

Java exige una correspondencia exacta entre el nombre del paquete y la estructura de carpetas:

Paquete declarado Ruta del fichero
jams.programacion.ud1 jams/programacion/ud1/Main.java
es.instituto.dam es/instituto/dam/Alumno.java
(sin paquete, paquete por defecto) cualquier carpeta

En un proyecto Maven, las clases van dentro de src/main/java/, así que el fichero completo sería src/main/java/jams/programacion/ud1/App.java. IntelliJ crea esta estructura automáticamente cuando le indicas el paquete al crear la clase.

Convención de nomenclatura: dominio invertido

La convención universal en Java para nombrar paquetes es usar el dominio de internet invertido como prefijo, para garantizar unicidad global:

Organización Dominio Paquete
Proyecto personal midominio.com midominio.com com.midominio.proyecto
IES (imaginemos instituto.es) instituto.es es.instituto.dam
Apache Software Foundation apache.org org.apache.commons
Este ciclo jams.programacion.ud1 (forma corta por simplicidad)

Las partes del paquete van en minúsculas (nunca Jams.Programacion.UD1), sin guiones (usa el punto como separador) y sin palabras reservadas de Java (int, class, new... no pueden ser partes de paquete).

Cómo IntelliJ te ayuda

Cuando creas una clase nueva con Alt+Insert → Java Class en IntelliJ y le pones como nombre jams.programacion.ud1.Calculadora, IntelliJ:

  1. Crea automáticamente las carpetas jams/programacion/ud1/ si no existen.
  2. Genera el fichero Calculadora.java en la ruta correcta.
  3. Añade la sentencia package jams.programacion.ud1; al inicio del fichero.

Pista

Si mueves un fichero a otro paquete arrastrándolo en el árbol de IntelliJ, este actualiza automáticamente la sentencia package del fichero movido. Si lo hicieras a mano con el explorador de archivos, tendrías que cambiar la sentencia package tú mismo o el código no compilaría.


3.9 La sentencia import

Qué es y para qué sirve

La sentencia import permite usar clases de otros paquetes sin tener que escribir su nombre completo (fully qualified name) cada vez. Sin import, para usar Scanner tendrías que escribir:

java.util.Scanner sc = new java.util.Scanner(System.in);   // farragoso

Con import, basta una vez al inicio del fichero:

1
2
3
4
import java.util.Scanner;   // import al inicio

// ... más abajo en el código
Scanner sc = new Scanner(System.in);   // usa el nombre corto

Sintaxis

La sentencia import va siempre después de package y antes de la declaración de la clase. Hay dos formas:

1
2
3
4
5
6
7
// Import específico (recomendado): una sola clase
import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;

// Import wildcard (comodín): todas las clases de un paquete
import java.util.*;   // importa Scanner, List, ArrayList, Map, etc.

Pista

IntelliJ usa por defecto import específico (mejor para saber de dónde viene cada clase y para no sobrecargar el binario). El import wildcard se ve sobre todo en código antiguo o en tutoriales; evítalo en proyectos nuevos porque dificulta saber qué clases se están usando realmente.

Import estático

Existe una variante, el import estático, que permite usar miembros estáticos (constantes y métodos) sin cualificar con el nombre de la clase:

1
2
3
4
5
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;

double area = PI * 5 * 5;        // sin Math. delante
double raiz = sqrt(25);          // sin Math. delante

Útil cuando usas mucho una constante o método estático (como PI en cálculos geométricos), pero puede reducir la legibilidad si se abusa. En este ciclo lo verás aplicado sobre todo en UD6 (colecciones con import static).

Lo que NO necesitas importar

Java importa automáticamente el paquete java.lang, así que las clases más básicas están siempre disponibles sin import:

Clase Paquete ¿Import necesario?
String java.lang.String No (automático)
System java.lang.System No
Math java.lang.Math No
Integer, Double, Boolean java.lang.* No
Scanner java.util.Scanner
List, ArrayList, Map java.util.*
LocalDate java.time.LocalDate

Cómo IntelliJ gestiona los imports

IntelliJ hace prácticamente todo el trabajo por ti:

  • Añadir import automáticamente: cuando escribes Scanner y pulsas Alt+Enter, IntelliJ añade import java.util.Scanner; al inicio del fichero.
  • Optimizar imports: con Ctrl+Alt+O elimina los imports que no se usan y ordena los restantes.
  • Auto-import al pegar: si pegas código que usa clases no importadas, IntelliJ te pregunta si quieres añadirlas.

Cuidado

Si ves una clase subrayada en rojo en IntelliJ con el mensaje "Cannot resolve symbol", casi siempre es que falta el import. Pulsa Alt+Enter sobre la clase y IntelliJ te propone el import correcto. Es una de las soluciones más mágicas del IDE.


3.10 Errores típicos del primer programa y cómo leerlos

Vamos a cerrar la sección con lo que más vas a ver en tus primeras semanas: mensajes de error del compilador. No te asustes: son tus amigos, no tus enemigos. Java tiene uno de los compiladores con mejores mensajes de error del mundo, y aprender a leerlos es una habilidad que te ahorrará horas.

Los cinco errores del 99% de los principiantes

Error Mensaje típico Causa Solución
Falta punto y coma error: ';' expected Te dejaste un ; al final de una instrucción Añádelo en la línea que indica el error
Llave sin cerrar error: reached end of file while parsing Falta un } en algún sitio Cuenta { y }; IntelliJ los resalta emparejados
Mayúscula incorrecta error: cannot find symbol: variable Edad Usaste Edad pero declaraste edad Revisa mayúsculas/minúsculas
Clase vs fichero error: class HolaMundo is public, should be declared in a file named HolaMundo.java Declaraste public class HolaMundo en un fichero con otro nombre Renombra el fichero o la clase para que coincidan
String sin cerrar error: unclosed string literal Abriste comillas " y no las cerraste Cierra las comillas en la misma línea

Cómo leer un mensaje de error

Un error del compilador tiene normalmente tres partes: el fichero, la línea y la descripción. Por ejemplo:

1
2
3
4
/src/main/java/dam/programacion/ud1/Main.java:5: error: ';' expected
        System.out.println("Hola")
                                ^
1 error

Léelo así:

  1. Fichero: Main.java — dónde está el problema.
  2. Línea 5 — en qué línea (ojo: a veces el error está en la línea anterior y se detecta al llegar a esta).
  3. Descripción: ';' expected — qué esperaba el compilador.
  4. El cursor ^ — dónde exactamente dentro de la línea.

Pista

Cuando IntelliJ subraya en rojo una línea, sitúa el cursor encima y aparecerá un tooltip con la explicación. Si pulsas Alt+Enter sobre el error, IntelliJ te propone la solución (añadir el ;, importar la clase, cambiar el nombre...). Es lo más parecido a magia que vas a encontrar en programación.

Errores de compilación vs errores de ejecución

Distinción importante que verás a lo largo del curso:

  • Errores de compilación (compile-time): los detecta javac antes de ejecutar. Falta de punto y coma, llaves, tipos incorrectos, variables no declaradas... El programa ni llega a ejecutarse.
  • Errores de ejecución (runtime): el programa compila bien pero falla al ejecutarse. Dividir por cero, acceder a un índice fuera de rango, llamar a un método sobre null... Producen una excepción que verás en consola con un stack trace.
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at dam.programacion.ud1.Main.main(Main.java:7)

Este ArithmeticException es un error de ejecución: el programa compiló, pero al intentar dividir por cero la JVM detuvo la ejecución. El stack trace te dice exactamente qué pasó y en qué línea (Main.java:7). En UD3 aprenderás a manejar excepciones con try-catch; por ahora, basta con que sepas leer el mensaje.


Resumen de la sección 3

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

  1. En Java 25 puedes escribir void main() { ... } sin public class ni static gracias a las implicitly declared classes y los instance main methods estables (JEP 512: Compact Source Files and Instance Main Methods). La forma clásica public static void main(String[] args) sigue siendo válida y necesaria en código pre-Java 25 y en proyectos con Maven.
  2. Un programa Java clásico se compone de clase → método main → instrucciones. La clase es el contenedor obligatorio (aunque implícito en Java 25); main es la puerta de entrada que busca la JVM.
  3. Para imprimir por consola tienes tres opciones: println (con salto de línea), print (sin salto) y printf (con formato). printf usa especificadores como %s, %d, %.2f, %n.
  4. Java es sensible a mayúsculas, exige punto y coma al final de cada instrucción y delimita bloques con llaves { } equilibradas.
  5. Hay tres tipos de comentarios: // (línea), /* */ (bloque) y /** */ (Javadoc, que genera documentación HTML con javadoc). Comenta el por qué, no el qué.
  6. Las convenciones de nomenclatura de Oracle son: camelCase para variables y métodos, PascalCase para clases, UPPER_SNAKE_CASE para constantes, todo.minusculas para paquetes. Respetarlas es obligatorio en la práctica profesional.
  7. Los errores del compilador tienen fichero, línea y descripción. Aprende a leerlos y usa Alt+Enter en IntelliJ para que te proponga soluciones automáticamente.