O método main do Java
O que significa public static void main(String[] args), por que cada modificador é obrigatório e como os argumentos de linha de comando são passados.
Toda aplicação Java começa dentro de um método com uma assinatura muito específica: public static void main(String[] args). A JVM procura por essa assinatura, a chama uma vez e o programa é executado até que essa chamada retorne (ou o programa seja encerrado de outra forma). Qualquer erro na assinatura e a JVM se recusa a iniciar o programa.
Você vem escrevendo essa linha em todos os exemplos desde o Hello World. Este capítulo a desmonta para que você saiba o que cada palavra faz e qual flexibilidade você tem.
A assinatura, palavra por palavra
public static void main(String[] args) { ... }public— a JVM está "fora" da sua classe. Para chamarmainde fora, ela precisa ser pública. Qualquer visibilidade mais restrita (private, package-private) e a JVM não consegue alcançá-la.static— a JVM não constrói uma instância da sua classe primeiro; ela chamamainna própria classe. Portanto,maindeve pertencer à classe, que é o questaticsignifica.void—mainnão retorna nada. O código de saída de um programa Java não é um valor de retorno; ele é definido comSystem.exit(...)ou assume o valor padrão0em uma conclusão limpa.main— o nome literal que a JVM procura. EscrevaMain,mianou qualquer outra coisa e a JVM falha ao iniciar comError: Main method not found in class ....String[] args— um único parâmetro, um array de strings, contendo os argumentos da linha de comando. O nome do parâmetro não importa (args,argv,cmdline), apenas o tipo.
O array de parâmetros também pode ser escrito como varargs — String... args — que é o mesmo tipo para a JVM e se comporta de forma idêntica:
public static void main(String... args) { ... }Ambas as formas funcionam. A maioria do código usa String[] args por convenção.
Argumentos de linha de comando
Quando você executa um programa Java a partir do terminal, tudo após o nome da classe se torna elementos do array args:
$ java Greet Ada LovelaceDentro de Greet.main, args é {"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.lengthé o número de argumentos —0se nenhum foi fornecido.- Cada elemento é sempre uma
String. Para usar um argumento numérico como número, faça o parse:int n = Integer.parseInt(args[0]);. - Aspas agrupam espaços no shell —
java Foo "hello world"coloca um único elemento"hello world"emargs.
O que não é permitido
A assinatura é fixa; pequenas variações compilam bem, mas falham na inicialização — a JVM exibe um Error: e sai antes que qualquer parte do seu código seja executada:
public void main(String[] args)— faltastatic.Error: Main method is not static in class ....void main(String[] args)— faltapublic static. O mesmo erro "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)—Mmaiúsculo ou qualquer outro nome.Error: Main method not found in class ....public static void main(String args)— tipo de parâmetro errado (uma únicaString, não um array).Error: Main method not found in class ....
Observe que esses são erros em tempo de execução, não erros de compilação — o javac aceita todos eles sem reclamar. A verificação ocorre quando o java tenta encontrar um ponto de entrada.
O que é permitido e não causa problemas:
finalno parâmetro ou no método:public static final void main(final String[] args).- Cláusulas throws:
public static void main(String[] args) throws Exception. Às vezes útil para experimentos rápidos. - Forma vararg:
public static void main(String... args).
Várias classes, um único main
Cada classe pública de nível superior pode ter seu próprio main. Quando você executa java SomeClass, a JVM procura por main nessa classe. Assim, um projeto grande pode ter dezenas de classes com main para testes ou para pontos de entrada separados; apenas o que você nomeia na linha de comando é o ponto de entrada daquela execução.
// 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 executa o primeiro; java Sum 1 2 3 executa o segundo e exibe 6.
Encerrando um programa Java
main retornando normalmente encerra o programa com código de saída 0. Para sair antecipadamente ou definir um código de saída diferente de zero (sinalizando um erro para quem executou o programa), use System.exit:
if (args.length == 0) {
System.err.println("usage: Sum <number>...");
System.exit(1);
}System.exit não retorna — ele encerra a JVM. Use-o com moderação; em bibliotecas, quase nunca é a ferramenta certa. Em um pequeno programa de linha de comando, é a forma padrão de sinalizar "não consegui fazer meu trabalho."
Um exemplo completo
O que vem a seguir
Isso encerra a parte sobre métodos: você pode escrever métodos, passar parâmetros, sobrecarregá-los, usar recursão, variar a quantidade de argumentos e hospedar o ponto de entrada que comanda todo o programa. A próxima parte apresenta o container maior em que os métodos residem — classes e objetos — e o primeiro contato com o modelo orientado a objetos do Java.