El método main en Java: por qué public static void, y qué cambió en Java 25

3 min de lectura

Durante casi treinta años, todo programa de Java empezó por public static void main(String[] args). ¿Por qué cada una de esas palabras? ¿Qué pasa si lo declaras privado? Y una novedad: desde Java 25 ya no hace falta escribirlo así.

Si es privado, no arranca

public class Privado {
    private static void main(String[] args) {
        System.out.println("hola");
    }
}
javac Privado.java
java Privado
salidaError: Main method not found in class Privado, please define the main method as:
   public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application
[código 1]

Compila sin protestar, porque para el compilador es un método privado más. El que falla es el lanzador, el programa java, al buscar por dónde empezar: no encuentra un main que pueda llamar y termina con código 1. Es el mismo mensaje en Java 21 y en Java 25.

Cada palabra, y por qué está

PalabraPor qué
publicQuien llama al método es el lanzador, desde fuera de la clase y del paquete. Necesita poder verlo.
staticAl arrancar no existe ningún objeto de la clase. Un método estático se puede llamar sin crear uno.
voidEl programa no devuelve su resultado con return. El código de salida que ve el sistema operativo se fija con System.exit(n).
String[] argsLos argumentos de la línea de órdenes, ya separados. args[0] es el primero, no el nombre del programa.

El void es el que más se explica mal. No tiene que ver con que Java sea multiplataforma: un int es igual en todas partes. Es una decisión de diseño. En Java el programa puede tener varios hilos, y terminar main no tiene por qué terminar el programa, así que no tendría sentido que su return fuera el código de salida. Para eso está System.exit:

public class Codigo {
    public static void main(String[] args) {
        if (args.length == 0) {
            System.err.println("falta el nombre del archivo");
            System.exit(2);
        }
        System.out.println("procesando " + args[0]);
    }
}
java Codigo  /  java Codigo datos.csvfalta el nombre del archivo
[código 2]
procesando datos.csv
[código 0]

Si main termina con normalidad, el código es 0. Si se escapa una excepción, el programa termina con código 1, sin necesidad de llamar a nada:

java Fallaantes del error
Exception in thread "main" java.lang.NumberFormatException: For input string: "doce"
	at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
	at java.base/java.lang.Integer.parseInt(Integer.java:565)
	at java.base/java.lang.Integer.parseInt(Integer.java:662)
	at Falla.main(Falla.java:4)
[código 1]

Lo que cambió en Java 25

Java 25 incorpora de forma definitiva los archivos fuente compactos y los main de instancia. Para un programa pequeño basta con esto:

void main() {
    IO.println("hola desde un main de Java 25");
}
java Moderno.javahola desde un main de Java 25

Sin clase, sin public, sin static y sin args. El compilador envuelve el archivo en una clase implícita, e IO.println es un atajo nuevo para escribir en la consola. Dentro de una clase normal, el main también puede ser de instancia:

public class Instancia {
    private final String saludo = "hola desde un main de instancia";

    void main() {
        System.out.println(saludo);
    }
}
java Instanciahola desde un main de instancia

Si el main no es estático, el lanzador crea primero un objeto con el constructor sin parámetros y después llama al método. Por eso aquí se puede usar el campo saludo directamente.

En Java 21 nada de esto funciona sin activar las funciones en pruebas: el archivo compacto no compila, y la clase Instancia da el mismo «Main method not found» que la de antes.

javac Moderno.java  —  Java 21Moderno.java:1: error: unnamed classes are a preview feature and are disabled by default.
void main() {
^
  (use --enable-preview to enable unnamed classes)

Las reglas nuevas

FormaJava 21Java 25
public static void main(String[] args)SíSí
static void main(), sin public ni parámetrosNoSí
void main() de instancia, en una claseNoSí
void main() suelto, sin claseNoSí
private static void main(String[] args)NoNo

El main puede ser público, protegido o de paquete, pero nunca privado. Y si una clase tiene dos main válidos, gana el que recibe String[] args:

public class Ambos {
    public static void main(String[] args) {
        System.out.println("el de String[] args");
    }
    static void main() {
        System.out.println("el que no tiene parámetros");
    }
}
java Ambosel de String[] args

La forma clásica sigue funcionando igual, y es la que encontrarás en casi todo el código existente. Las nuevas están pensadas para empezar y para programas cortos, como los de nuestro curso de Java.

Entrada publicada en 2012 y revisada en octubre de 2026. Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio; las salidas están copiadas de esa ejecución.

4 comentarios en «El método main en Java: por qué public static void, y qué cambió en Java 25»

Deja un comentario