Home / Lenguajes / Hola Mundo en Java: del método main clásico a Java 25 y 26
Hola Mundo en Java: del método main clásico a Java 25 y 26

Hola Mundo en Java: del método main clásico a Java 25 y 26

4 November 2026 · 18 min de lectura ··

El primer programa en uno de los lenguajes más usados

Escribir un programa que muestre un saludo en pantalla es una tradición que se repite cada vez que alguien empieza con un lenguaje nuevo. Parece un ejercicio trivial, pero cumple una función importante: comprobar que el entorno está bien instalado, que el ciclo de escribir, compilar y ejecutar funciona, y que se entiende la estructura mínima de un programa. En Java, además, ese primer programa ha sido durante décadas una pequeña lección sobre clases, métodos y modificadores que muchos principiantes copiaban sin entender del todo.

Eso ha cambiado. Desde Java 25, la versión de soporte a largo plazo publicada en septiembre de 2025, el lenguaje permite escribir el mismo saludo con muchas menos líneas gracias a los archivos de código compactos y los métodos main de instancia. Java 26, publicada en marzo de 2026, mantiene esas mejoras, y hoy conviven dos formas válidas de empezar: la tradicional, que sigue siendo la base de cualquier aplicación profesional, y la simplificada, pensada para aprender y para scripts pequeños.

En esta guía se recorre todo el proceso: instalar un JDK actual, escribir el programa clásico y entender cada una de sus palabras, compilarlo y ejecutarlo, probar la versión moderna, experimentar con JShell, leer datos del usuario y resolver los errores más frecuentes que aparecen en los primeros pasos.

Preparar el entorno: instalar un JDK actual

Para programar en Java se necesita el JDK, el kit de desarrollo, que incluye el compilador javac, la máquina virtual con el lanzador java y herramientas como jshell. No basta con un entorno de ejecución: hace falta el kit completo.

Existen varias distribuciones gratuitas basadas en OpenJDK, como Eclipse Temurin, Amazon Corretto, Microsoft Build of OpenJDK o la propia de Oracle. Para aprender da igual cuál se elija. Lo recomendable es instalar Java 25, por ser la versión LTS actual, o Java 26 si se quiere la más reciente.

En macOS, con Homebrew:

brew install --cask temurin

En Windows, con el gestor de paquetes WinGet, se puede buscar la distribución deseada e instalarla:

winget search Temurin
winget install EclipseAdoptium.Temurin.25.JDK

En Linux, la forma más cómoda de gestionar varias versiones es SDKMAN, que permite listar e instalar distribuciones concretas:

curl -s "https://get.sdkman.io" | bash
sdk list java
sdk install java <identificador-de-la-version>

Los identificadores exactos varían según la distribución y la versión, por lo que conviene copiarlos de la salida de sdk list java. Muchas distribuciones también ofrecen paquetes en los repositorios oficiales, como openjdk-25-jdk en las versiones recientes de Ubuntu y Debian.

Una vez instalado, se comprueba que tanto el compilador como el lanzador están disponibles:

java -version
javac -version
openjdk version "25.0.x" LTS
OpenJDK Runtime Environment Temurin-25.0.x (build 25.0.x-LTS)
OpenJDK 64-Bit Server VM Temurin-25.0.x (build 25.0.x-LTS, mixed mode, sharing)
javac 25.0.x

Los números de la actualización variarán según el momento de la instalación. Lo importante es que ambos comandos respondan y que la versión principal coincida.

El programa clásico línea por línea

Con el JDK listo, se crea una carpeta para el proyecto y dentro un archivo llamado Saludo.java:

primer-proyecto-java/
└── Saludo.java

El contenido del archivo es el programa tradicional:

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

Son solo cinco líneas con código, pero cada palabra tiene un significado preciso.

La primera línea declara una clase. En Java, todo el código vive dentro de clases, que son las unidades básicas de organización. La palabra public indica que la clase es accesible desde cualquier parte, class declara que se está definiendo una clase y Saludo es su nombre. Por convención, los nombres de clase se escriben en Pascal case, con la primera letra de cada palabra en mayúscula.

Hay una regla importante ligada a esta línea: una clase pública debe guardarse en un archivo con exactamente el mismo nombre y la extensión .java. La clase Saludo va en Saludo.java, respetando mayúsculas y minúsculas. Si no coinciden, el compilador rechaza el programa.

Las llaves { y } delimitan bloques de código. Todo lo que está entre la llave que sigue a Saludo y la llave final pertenece a la clase.

Anatomía del método main

La segunda línea declara el método main, el punto de entrada del programa. Cuando se ejecuta una aplicación Java, la máquina virtual busca este método y empieza por ahí. Cada palabra de su firma cumple una función.

public hace que el método sea accesible desde fuera de la clase, algo necesario para que la máquina virtual pueda invocarlo.

static indica que el método pertenece a la clase y no a un objeto concreto. Esto permite llamarlo sin crear antes una instancia de Saludo, que es justo lo que hace la máquina virtual al arrancar.

void significa que el método no devuelve ningún valor. Si un programa necesita comunicar un código de salida al sistema operativo, lo hace mediante System.exit(), no devolviendo un valor desde main.

main es el nombre que el lanzador busca. Un método llamado Main o inicio no serviría como punto de entrada.

String[] args es el parámetro del método: un arreglo de cadenas que contiene los argumentos escritos en la línea de comandos después del nombre del programa. Se puede usar para que el programa se comporte de forma distinta según cómo se invoque:

public class SaludoPersonalizado {
    public static void main(String[] args) {
        String nombre = args.length > 0 ? args[0] : "desconocido";
        System.out.println("¡Hola, " + nombre + "!");
    }
}
java SaludoPersonalizado.java Lucía
¡Hola, Lucía!

El nombre args es solo una convención; podría llamarse de cualquier otra forma, pero casi todo el código Java usa ese nombre.

Mostrar texto: System.out.println y sus variantes

La línea que realmente produce el saludo es System.out.println("¡Hola, mundo desde Java!");. Se lee de izquierda a derecha: System es una clase de la biblioteca estándar que da acceso a recursos del sistema; out es un campo de esa clase que representa la salida estándar, normalmente la consola; y println es un método que imprime el texto recibido y añade un salto de línea al final.

El texto entre comillas dobles es una cadena de caracteres, un literal de tipo String. Las comillas simples en Java se reservan para caracteres individuales, como 'A', de modo que escribir el saludo entre comillas simples produce un error de compilación.

El punto y coma final indica el término de la instrucción. Olvidarlo es uno de los errores más frecuentes al empezar.

Además de println, existen otras dos variantes útiles. print imprime sin añadir salto de línea, y printf permite formatear el texto con marcadores:

public class Formatos {
    public static void main(String[] args) {
        System.out.print("Sin salto de línea. ");
        System.out.println("Con salto de línea.");

        String lenguaje = "Java";
        int version = 25;
        double precio = 0.0;
        System.out.printf("Aprendiendo %s %d por %.2f euros%n", lenguaje, version, precio);
    }
}
Sin salto de línea. Con salto de línea.
Aprendiendo Java 25 por 0,00 euros

El marcador %n inserta el salto de línea adecuado para el sistema operativo, y el formato decimal depende de la configuración regional del equipo, por eso puede aparecer una coma en lugar de un punto.

Para textos de varias líneas, Java incluye desde hace varias versiones los bloques de texto, delimitados por tres comillas dobles:

public class Bienvenida {
    public static void main(String[] args) {
        String mensaje = """
            Bienvenido a Java
            -----------------
            Versión LTS actual: 25
            """;
        System.out.print(mensaje);
    }
}

Comentarios: código que no se ejecuta

La línea que empieza con // es un comentario. El compilador la ignora por completo; sirve para que las personas que leen el código entiendan su propósito. Java admite tres tipos de comentarios:

// Comentario de una línea

/*
   Comentario de varias líneas,
   útil para explicaciones largas o para desactivar código temporalmente.
*/

/**
 * Comentario de documentación (Javadoc).
 * Se coloca antes de clases y métodos y genera documentación HTML.
 */
public class Documentada {
    /**
     * Punto de entrada de la aplicación.
     * @param args argumentos de la línea de comandos
     */
    public static void main(String[] args) {
        System.out.println("Código documentado");
    }
}

Los comentarios Javadoc son especiales porque la herramienta javadoc, incluida en el JDK, los convierte en documentación navegable. Es la misma documentación que se consulta para la biblioteca estándar de Java.

Compilar y ejecutar desde la terminal

El flujo tradicional de Java tiene dos pasos. Primero, el compilador javac traduce el código fuente a bytecode, un formato intermedio que entiende la máquina virtual:

cd primer-proyecto-java
javac Saludo.java

Si no hay errores, el compilador no muestra nada y crea un archivo Saludo.class junto al original:

primer-proyecto-java/
├── Saludo.class
└── Saludo.java

Después, se ejecuta el programa con el lanzador java, indicando el nombre de la clase sin extensión:

java Saludo
¡Hola, mundo desde Java!

Un error frecuente es escribir java Saludo.class, que falla porque el lanzador espera el nombre de la clase, no el del archivo compilado.

Este modelo de compilar una vez y ejecutar el bytecode en cualquier sistema con una máquina virtual es lo que dio a Java su lema de escribir una vez y ejecutar en cualquier lugar. El mismo archivo Saludo.class funciona en Windows, macOS o Linux sin recompilar.

Ejecutar sin compilar explícitamente

Desde Java 11 existe un atajo muy útil para programas pequeños: el lanzador puede ejecutar directamente un archivo fuente. Compila en memoria y ejecuta sin generar archivos .class:

java Saludo.java
¡Hola, mundo desde Java!

Desde Java 22, este modo admite además programas formados por varios archivos fuente. Si Saludo.java utiliza una clase definida en otro archivo de la misma carpeta, el lanzador la encuentra y la compila automáticamente:

saludo-multiarchivo/
├── Saludo.java
└── Formateador.java
// Formateador.java
public class Formateador {
    public static String enmarcar(String texto) {
        String borde = "*".repeat(texto.length() + 4);
        return borde + "\n* " + texto + " *\n" + borde;
    }
}
// Saludo.java
public class Saludo {
    public static void main(String[] args) {
        System.out.println(Formateador.enmarcar("Hola desde dos archivos"));
    }
}
java Saludo.java
***************************
* Hola desde dos archivos *
***************************

Este modo es ideal para aprender y para pequeñas utilidades, ya que elimina la fricción del paso de compilación. Para proyectos reales, con dependencias externas y pruebas, se siguen utilizando herramientas de construcción como Maven o Gradle.

El Hola Mundo moderno: archivos compactos en Java 25

La novedad más relevante para quien empieza con Java llegó con la versión 25, que incorporó de forma definitiva la característica conocida como archivos de código compactos y métodos main de instancia, recogida en la propuesta JEP 512. Tras varias versiones como funcionalidad en vista previa, ya forma parte estable del lenguaje.

Con ella, el saludo puede escribirse así:

void main() {
    IO.println("¡Hola, mundo desde Java 25!");
}
java Saludo.java
¡Hola, mundo desde Java 25!

Varias cosas han desaparecido. Ya no hace falta declarar una clase: un archivo que contiene métodos sueltos se considera un archivo compacto, y el compilador genera una clase implícita para él. El método main no necesita ser public ni static, y el parámetro String[] args es opcional. Además, la nueva clase java.lang.IO ofrece métodos sencillos para la consola, como println, print y readln, sin tener que recordar la cadena System.out.

Los archivos compactos importan automáticamente todos los paquetes públicos del módulo java.base, de modo que clases como List, Map o LocalDate pueden usarse sin escribir sentencias import:

void main() {
    var lenguajes = List.of("Java", "Kotlin", "Scala");
    var hoy = LocalDate.now();

    IO.println("Lenguajes de la JVM: " + lenguajes);
    IO.println("Fecha de hoy: " + hoy);
}

En un archivo compacto también se pueden declarar campos y otros métodos, lo que permite escribir pequeños programas completos de forma muy directa:

String saludar(String nombre) {
    return "¡Hola, " + nombre + "!";
}

void main() {
    IO.println(saludar("mundo"));
    IO.println(saludar("Java 25"));
}

Estos archivos de código compactos no son un dialecto distinto de Java. Son la puerta de entrada al mismo lenguaje: cuando el programa crece, basta con envolver el código en una declaración de clase para convertirlo en un programa tradicional, sin reescribir nada más.

Métodos main de instancia también en clases normales

La flexibilidad del método main no se limita a los archivos compactos. En una clase declarada explícitamente también se puede usar un main de instancia, sin static y sin parámetros:

class Contador {
    int total = 0;

    void incrementar() {
        total++;
    }

    void main() {
        incrementar();
        incrementar();
        IO.println("Total: " + total);
    }
}

En este caso, el lanzador crea un objeto de la clase usando su constructor sin argumentos y llama a main sobre él. Por eso el método puede acceder directamente al campo total y a incrementar, que no son estáticos.

Cuando una clase tiene varios candidatos, el lanzador aplica un orden de preferencia: primero busca el clásico static void main(String[] args), y solo si no existe recurre a las variantes simplificadas. Esto garantiza que los programas existentes sigan funcionando exactamente igual. Elegir entre la firma clásica del método main y la moderna depende del contexto: para aplicaciones profesionales, frameworks y bibliotecas sigue siendo habitual la forma tradicional; para aprender, enseñar o escribir scripts, la simplificada resulta mucho más limpia.

Leer datos del usuario

Un saludo fijo se queda corto enseguida. El siguiente paso natural es pedir un dato al usuario. Con Java 25, la clase IO lo hace muy sencillo con readln, que muestra un mensaje y devuelve la línea escrita:

void main() {
    String nombre = IO.readln("¿Cómo te llamas? ");
    int anio = Integer.parseInt(IO.readln("¿En qué año naciste? "));
    int edad = LocalDate.now().getYear() - anio;

    IO.println("¡Hola, " + nombre + "! Este año cumples " + edad + " años.");
}
¿Cómo te llamas? Marta
¿En qué año naciste? 1998
¡Hola, Marta! Este año cumples 28 años.

En el estilo tradicional, la herramienta habitual para leer datos de la consola es la clase Scanner:

import java.util.Scanner;

public class SaludoInteractivo {
    public static void main(String[] args) {
        try (Scanner entrada = new Scanner(System.in)) {
            System.out.print("¿Cómo te llamas? ");
            String nombre = entrada.nextLine();
            System.out.println("¡Hola, " + nombre + "!");
        }
    }
}

La estructura try con recursos cierra automáticamente el Scanner al terminar. Si el usuario escribe algo que no es un número cuando se espera uno, Integer.parseInt lanza una excepción NumberFormatException, un buen punto de partida para aprender el manejo de errores.

Experimentar con JShell

El JDK incluye JShell, una consola interactiva en la que se puede escribir código Java y ver el resultado al instante, sin crear archivos ni clases. Es perfecta para probar ideas o comprobar cómo funciona un método:

jshell
|  Welcome to JShell -- Version 25.0.x
|  For an introduction type: /help intro

jshell> System.out.println("Hola desde JShell")
Hola desde JShell

jshell> var saludo = "Hola" + " " + "mundo"
saludo ==> "Hola mundo"

jshell> saludo.toUpperCase()
$3 ==> "HOLA MUNDO"

jshell> /exit
|  Goodbye

En JShell el punto y coma es opcional para expresiones simples, y cada resultado se guarda en una variable temporal que puede reutilizarse. Comandos como /vars, /methods o /list muestran lo que se ha definido durante la sesión.

Usar un IDE o un editor

Aunque todo lo anterior se puede hacer con un editor de texto y la terminal, un entorno de desarrollo integrado facilita mucho el trabajo. IntelliJ IDEA, Eclipse, NetBeans y Visual Studio Code con el paquete de extensiones de Java son las opciones más extendidas. Todos ofrecen autocompletado, detección de errores mientras se escribe, ejecución con un clic y depuración paso a paso.

Para el primer contacto, conviene ejecutar el programa al menos una vez desde la terminal. Entender qué hacen javac y java por debajo ayuda mucho cuando el IDE muestra un error que no parece tener sentido o cuando hay que configurar un servidor de integración continua.

Al crear un proyecto nuevo en un IDE, lo habitual es elegir Maven o Gradle como herramienta de construcción. Ambas generan una estructura estándar de carpetas:

mi-aplicacion/
├── pom.xml
└── src/
    ├── main/
    │   └── java/
    │       └── com/ejemplo/Saludo.java
    └── test/
        └── java/
            └── com/ejemplo/SaludoTest.java

En esta estructura, las clases se organizan en paquetes, y la primera línea del archivo debe declararlo:

package com.ejemplo;

public class Saludo {
    public static void main(String[] args) {
        System.out.println("Hola desde un paquete");
    }
}

Qué ocurre por dentro: bytecode y máquina virtual

Entender qué produce el compilador ayuda a desmitificar Java. El archivo .class no contiene código máquina para un procesador concreto, sino instrucciones de bytecode para la máquina virtual de Java. El JDK incluye la herramienta javap, que permite ver ese bytecode de forma legible:

javac Saludo.java
javap -c Saludo
Compiled from "Saludo.java"
public class Saludo {
  public Saludo();
    Code:
       0: aload_0
       1: invokespecial #1   // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #7   // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #13  // String ¡Hola, mundo desde Java!
       5: invokevirtual #15  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

La salida revela dos detalles interesantes. El primero es que el compilador ha añadido un constructor sin argumentos que no estaba en el código fuente; cuando una clase no declara ninguno, Java genera uno por defecto. El segundo es que la línea del saludo se traduce en tres pasos: obtener el campo estático System.out, cargar la cadena constante e invocar el método println sobre ese objeto.

Cuando se ejecuta el programa, la máquina virtual carga la clase, verifica que el bytecode es seguro y empieza a interpretarlo. Las partes del código que se ejecutan con frecuencia se compilan sobre la marcha a código máquina nativo mediante el compilador JIT, lo que explica por qué las aplicaciones Java ganan velocidad tras unos segundos de funcionamiento. En un saludo de una línea no se aprecia, pero es el mecanismo que permite a Java rendir bien en servidores que funcionan durante meses.

Con un archivo compacto ocurre lo mismo: el compilador genera una clase implícita con un nombre derivado del archivo y un método main de instancia. La máquina virtual no distingue entre ambos estilos, porque lo que ejecuta es siempre bytecode. Comprender esta relación entre compilador y JVM es útil más adelante, cuando se trabaja con otros lenguajes que también generan bytecode, como Kotlin o Scala, y que pueden interoperar con las mismas bibliotecas de Java.

Errores frecuentes y cómo resolverlos

El primer programa casi siempre trae algún error, y aprender a leer sus mensajes es parte del proceso. El más común es el nombre de archivo que no coincide con la clase pública:

Saludo.java:1: error: class Bienvenida is public, should be declared in a file named Bienvenida.java
public class Bienvenida {
       ^
1 error

La solución es renombrar el archivo o la clase para que coincidan, respetando mayúsculas.

El segundo es olvidar el punto y coma:

Saludo.java:3: error: ';' expected
        System.out.println("Hola")
                                  ^
1 error

El compilador indica la línea y la posición exacta donde esperaba el símbolo.

Escribir mal el nombre de una clase o un método también es habitual, por ejemplo system en minúscula o printIn con una i mayúscula en lugar de una ele:

Saludo.java:3: error: package system does not exist
        system.out.println("Hola");
              ^
1 error

Java distingue entre mayúsculas y minúsculas en todos los identificadores, así que System y system son nombres completamente distintos.

Si el sistema responde que no encuentra el comando javac, el JDK no está instalado o su carpeta bin no está en la variable PATH. En ese caso conviene revisar la instalación y la variable de entorno JAVA_HOME:

javac: command not found
echo $JAVA_HOME
which java javac

Otro error clásico aparece al ejecutar una clase compilada con una versión más reciente de Java en una máquina virtual más antigua:

Error: LinkageError occurred while loading main class Saludo
	java.lang.UnsupportedClassVersionError: Saludo has been compiled by a more recent version of the Java Runtime (class file version 69.0), this version of the Java Runtime only recognizes class file versions up to 65.0

El número de versión del archivo de clase indica con qué JDK se compiló. La solución es ejecutar con un JDK igual o más reciente, o compilar indicando la versión de destino con la opción --release:

javac --release 21 Saludo.java

Por último, si se usa la sintaxis compacta con un JDK anterior a la versión 25, el compilador no reconocerá el método suelto ni la clase IO. Comprobar la versión con java -version resuelve la duda de inmediato.

Buenas prácticas desde el primer programa

Aunque el programa sea pequeño, conviene adquirir buenos hábitos desde el principio. Usar nombres descriptivos para clases y variables, seguir las convenciones del lenguaje, como Pascal case para clases y camel case para métodos y variables, y mantener una indentación consistente hace que el código sea legible para cualquier persona.

También es recomendable fijar una versión LTS del JDK para los proyectos que van a mantenerse en el tiempo. Java 25 es la versión LTS vigente y recibirá actualizaciones durante años; las versiones intermedias, como Java 26, son excelentes para probar novedades, pero tienen un ciclo de soporte corto de seis meses.

Otra práctica útil es aprender a leer la documentación oficial de la API. Cada clase de la biblioteca estándar, desde String hasta IO, tiene una página con sus métodos y ejemplos, y consultarla es más fiable que copiar fragmentos de código sin contexto.

Por último, conviene escribir el programa con la sintaxis compacta para entender la lógica y, después, reescribirlo con la estructura clásica para comprender qué hace el compilador por debajo. Dominar ambas formas permite leer tanto el código heredado de proyectos empresariales como los ejemplos modernos de la documentación.

Conclusiones

El Hola Mundo en Java ha pasado de ser una pequeña barrera de palabras clave a convertirse en una entrada mucho más amable al lenguaje. La forma tradicional, con una clase pública y el método public static void main(String[] args), sigue siendo la base de cualquier aplicación profesional y conviene entender cada una de sus partes: la clase como contenedor, public para el acceso, static para no necesitar un objeto, void porque no devuelve nada y args para recibir argumentos.

Desde Java 25, los archivos compactos y los métodos main de instancia permiten escribir el mismo programa con una sola función y la clase IO, sin declarar clases ni importar paquetes básicos. A esto se suman herramientas que reducen la fricción inicial, como la ejecución directa de archivos fuente con java Archivo.java, el soporte para varios archivos desde Java 22 y la consola interactiva JShell.

Con un JDK actual instalado, sea la versión LTS 25 o la más reciente 26, el camino desde el primer saludo hasta programas reales es más corto que nunca. El siguiente paso natural es explorar variables, estructuras de control, colecciones y, a partir de ahí, la programación orientada a objetos que sigue siendo el corazón del lenguaje.