Argumentos de la línea de órdenes en Java

Los argumentos llegan en un String[] y no hay nada más: ni banderas, ni valores por omisión, ni ayuda. Todo eso se escribe, y con el switch moderno cabe en veinte líneas.

Lo que llega

void main(String[] args) {
    IO.println("recibí " + args.length + " argumentos");
    for (int i = 0; i < args.length; i++) IO.println("  [" + i + "] " + args[i]);
}
java Args.java -v -o resultado.txt entrada1.txt entrada2.txt
salidarecibí 5 argumentos
  [0] -v
  [1] -o
  [2] resultado.txt
  [3] entrada1.txt
  [4] entrada2.txt

Fíjate en que args[0] es el primer argumento, no el nombre del programa. En C o en Python eso no es así, y es un despiste clásico.

Esto funciona también en un archivo fuente compacto, de los que se ejecutan con java Archivo.java: el main puede declararse con String[] args o sin nada, y en ambos casos vale.

Un analizador en veinte líneas

boolean verboso = false;
String salida = null;
var sueltos = new ArrayList<String>();

for (int i = 0; i < args.length; i++) {
    switch (args[i]) {
        case "-v", "--verboso" -> verboso = true;
        case "-o", "--salida"  -> {
            if (i + 1 >= args.length) {
                IO.println("error: " + args[i] + " necesita un valor");
                System.exit(2);
            }
            salida = args[++i];
        }
        case "-h", "--ayuda"   -> { IO.println(USO); System.exit(0); }
        default -> {
            if (args[i].startsWith("-")) {
                IO.println("error: opción desconocida " + args[i]);
                System.exit(2);
            }
            sueltos.add(args[i]);
        }
    }
}
salidaverboso=true  salida=resultado.txt  archivos=[entrada1.txt, entrada2.txt]

Las tres piezas que lo hacen funcionar: agrupar la forma corta y la larga con una coma en el mismo case; avanzar el índice con args[++i] cuando la opción lleva valor; y distinguir en el default entre lo que empieza por guion —una opción que no conoces, y eso es un error— y lo que no.

La ayuda

static final String USO = """
        uso: herramienta [-v] [-o ARCHIVO] entrada...
          -v, --verboso   más detalle
          -o, --salida    dónde escribir
          -h, --ayuda     esto""";
salidauso: herramienta [-v] [-o ARCHIVO] entrada...
  -v, --verboso   más detalle
  -o, --salida    dónde escribir
  -h, --ayuda     esto

Los bloques de texto con """ quitan solos la sangría común, así que el texto se puede escribir alineado con el código y sale pegado a la izquierda. Era eso o concatenar seis cadenas con \n.

Códigos de salida

echo $?-h          -> 0
sin args    -> 0
opción mala -> 2

La convención de Unix: 0 si todo fue bien, distinto de 0 si no. El 2 suele reservarse para «me has llamado mal» y el 1 para «lo intenté y falló». Pedir la ayuda no es un error y tiene que salir con 0, o cualquier guion que compruebe el código se confundirá.

System.exit() termina la máquina virtual en el acto: no se ejecutan los finally pendientes ni se cierra nada que estuviera abierto. Por eso, en un programa con algo de tamaño, lo sensato es que el trabajo esté en un método que devuelva un código y que main sea lo único que llama a exit.

Cuando ya no caben en un switch

En cuanto la herramienta tiene subórdenes, autocompletado y veinte opciones, esto se queda corto. Lo habitual entonces es picocli, que genera el analizador y la ayuda a partir de anotaciones. Pero para una utilidad de un solo propósito, el switch de arriba no tiene ninguna dependencia y se entiende de un vistazo.

Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.