El método main de Java
Qué significa public static void main(String[] args), por qué cada modificador es obligatorio y cómo se pasan los argumentos de línea de comandos.
Cada aplicación Java comienza dentro de un método con una firma muy específica: public static void main(String[] args). La JVM busca esa firma, la llama una vez y tu programa se ejecuta hasta que esa llamada retorna (o el programa se detiene de otra forma). Si cualquier parte de la firma es incorrecta, la JVM se niega a iniciar el programa.
Has escrito esta línea en todos los ejemplos desde Hello World. Este capítulo la descompone para que entiendas qué hace cada palabra y qué flexibilidad tienes.
La firma, palabra por palabra
public static void main(String[] args) { ... }public— la JVM está "fuera" de tu clase. Para llamar amaindesde el exterior, tiene que ser pública. Con cualquier visibilidad más restrictiva (private, package-private), la JVM no puede acceder a ella.static— la JVM no construye una instancia de tu clase primero; llama amaindirectamente sobre la clase. Por esomaindebe pertenecer a la clase, que es lo que significastatic.void—mainno devuelve nada. El código de salida de un programa Java no es un valor de retorno; se establece conSystem.exit(...)o por defecto es0al terminar limpiamente.main— el nombre literal que busca la JVM. Si se escribeMain,miano cualquier otra cosa, la JVM falla al lanzar conError: Main method not found in class ....String[] args— un único parámetro, un array de strings, que contiene los argumentos de línea de comandos. El nombre del parámetro no importa (args,argv,cmdline), solo el tipo.
El array de parámetros también puede escribirse como varargs — String... args — que es el mismo tipo para la JVM y se comporta de forma idéntica:
public static void main(String... args) { ... }Ambas formas funcionan. La mayoría del código usa String[] args por convención.
Argumentos de línea de comandos
Cuando ejecutas un programa Java desde la terminal, todo lo que viene después del nombre de la clase se convierte en elementos del array args:
$ java Greet Ada LovelaceDentro de Greet.main, args es {"Ada", "Lovelace"}:
public class Greet {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("Hello, stranger");
} else {
System.out.println("Hello, " + String.join(" ", args));
}
}
}args.lengthes el número de argumentos —0si no se suministró ninguno.- Cada elemento es siempre un
String. Para usar un argumento numérico como número, hay que convertirlo:int n = Integer.parseInt(args[0]);. - Las comillas agrupan espacios en el shell —
java Foo "hello world"coloca un único elemento"hello world"enargs.
Lo que no está permitido
La firma es fija; pequeñas desviaciones compilan bien pero fallan al lanzar — la JVM imprime un Error: y sale antes de que se ejecute cualquier parte de tu código:
public void main(String[] args)— faltastatic.Error: Main method is not static in class ....void main(String[] args)— faltapublic static. El mismo fallo "not static".public static int main(String[] args)— tipo de retornoint.Error: Main method must return a value of type void in class ....public static void Main(String[] args)—Mmayúscula, o cualquier otro nombre.Error: Main method not found in class ....public static void main(String args)— tipo de parámetro incorrecto (un únicoString, no un array).Error: Main method not found in class ....
Hay que tener en cuenta que estos son errores en tiempo de ejecución, no errores de compilación — javac los acepta todos sin problemas. La comprobación ocurre cuando java intenta encontrar un punto de entrada.
Lo que sí está permitido y es inofensivo:
finalen el parámetro o en el método:public static final void main(final String[] args).- Cláusulas throws:
public static void main(String[] args) throws Exception. A veces conveniente para experimentos rápidos. - Forma vararg:
public static void main(String... args).
Múltiples clases, un único main
Cada clase pública de nivel superior puede tener su propio main. Cuando ejecutas java SomeClass, la JVM busca main en esa clase. Así, un proyecto grande puede tener docenas de clases que llevan un main para pruebas o para puntos de entrada separados; solo el que indiques en la línea de comandos es el punto de entrada de esa ejecución.
// File Greet.java
public class Greet {
public static void main(String[] args) { System.out.println("greet"); }
}
// File Sum.java
public class Sum {
public static void main(String[] args) {
int total = 0;
for (String s : args) total += Integer.parseInt(s);
System.out.println(total);
}
}java Greet ejecuta el primero; java Sum 1 2 3 ejecuta el segundo e imprime 6.
Cómo terminar un programa Java
Cuando main retorna normalmente, el programa termina con código de salida 0. Para salir antes, o para establecer un código de salida distinto de cero (señalando un error a quien ejecutó el programa), usa System.exit:
if (args.length == 0) {
System.err.println("usage: Sum <number>...");
System.exit(1);
}System.exit no retorna — detiene la JVM. Úsalo con moderación; en bibliotecas casi nunca es la herramienta adecuada. En un pequeño programa de línea de comandos es la forma estándar de indicar "no pude hacer mi trabajo".
Un ejemplo práctico
Qué viene a continuación
Con esto se cierra la parte de métodos: puedes escribir métodos, pasar parámetros, sobrecargarlos, recurrir a la recursión, variar el número de argumentos y albergar el punto de entrada que impulsa todo el programa. La siguiente parte presenta el contenedor más grande en el que viven los métodos — clases y objetos — y el primer contacto con el modelo orientado a objetos de Java.