Java Lendo Erros do javac
Todo programador, do iniciante ao veterano, vê erros de compilação todos os dias. A diferença é que o veterano lê a mensagem e sabe o que fazer em segundos. As mensagens do javac são em inglês, mas seguem sempre o mesmo formato e usam um vocabulário pequeno. Nesta aula você aprende a ler esse formato e conhece, um por um, os erros mais comuns de quem começa, com a mensagem real e a correção.
- As partes de uma mensagem do
javac: arquivo, linha, descrição, a linha copiada e o^. - Um método para consertar erros: o primeiro, depois compilar de novo.
- O pequeno vocabulário em inglês das mensagens.
- Os erros mais comuns de iniciante, com código, mensagem real e correção.
- A diferença entre erro de compilação e erro em tempo de execução.
Todos os códigos desta aula têm erros de propósito e foram compilados com o javac 25 na máquina da Ana; as mensagens são copiadas da tela, sem mudar nada.
A ideia: o corretor de redação
Pense numa professora corrigindo uma redação. Ela não reescreve o texto: marca a linha com caneta vermelha, sublinha a palavra e escreve na margem o que está errado ("falta vírgula", "concordância"). O javac faz o mesmo. Ele não conserta nada sozinho, mas diz onde está o problema e o que ele achou de errado. O seu trabalho é ler a anotação com calma.
E um detalhe importante: um erro de compilação não quebra nada. O programa simplesmente não é gerado até o erro ser corrigido. Pode errar à vontade.
Anatomia de uma mensagem
A Ana esqueceu o ponto e vírgula no fim da linha 3:
public class Main {
public static void main(String[] args) {
System.out.println("Olá, Ana")
}
}
$ javac Main.java
Main.java:3: error: ';' expected
System.out.println("Olá, Ana")
^
1 error
- Main.java
- O arquivo onde está o erro. Em projetos com vários arquivos, é a primeira coisa a olhar.
- :3
- O número da linha. Os editores mostram os números na margem; a caixa Experimente também.
- error:
- O tipo da mensagem: erro (impede a compilação). Existe também
warning:("aviso"), que não impede. - ';' expected
- A descrição: "esperava um
;". - System.out.println(…)
- A linha do código copiada, para você não precisar procurar.
- ^
- O acento circunflexo aponta a coluna exata onde o
javacpercebeu o problema. Aqui, logo depois do), onde o;deveria estar. - 1 error
- A contagem: quantos erros no total.
Algumas mensagens têm linhas extras embaixo do ^, com detalhes:
$ javac Main.java
Main.java:4: error: cannot find symbol
System.out.println(ntoa);
^
symbol: variable ntoa « o que ele não achou: uma variável chamada ntoa
location: class Main « onde procurou: na classe Main
1 error
^ mostra onde o javac percebeu, não necessariamente onde você errou
No primeiro exemplo, o erro é da linha 3, e a mensagem diz linha 3. Mas às vezes o compilador só percebe o problema mais adiante: uma chave esquecida no meio do arquivo pode ser acusada só na última linha. Se a linha apontada parece certa, olhe a linha de cima.
O método: o primeiro erro, depois compilar de novo
- Leia só o primeiro erro. Os seguintes muitas vezes são consequência dele.
- Vá à linha indicada e olhe onde o
^aponta (e a linha de cima, se não achar nada). - Traduza a descrição com a tabela de vocabulário abaixo.
- Conserte e compile de novo. Podem aparecer erros novos: é normal, e é progresso.
Veja o passo 4 acontecer. Este código tem dois problemas, na linha 4 e na linha 5:
public class Main {
public static void main(String[] args) {
System.out.println("Oi");
System.out.println("Tchau")
System.out.println(total);
}
}
$ javac Main.java
Main.java:4: error: ';' expected
System.out.println("Tchau")
^
1 error « só um erro?
Só um erro foi mostrado. O javac trabalha em etapas: primeiro confere a "gramática" (pontuação, chaves); só se ela estiver toda certa ele passa a conferir os nomes. Depois de pôr o ;:
$ javac Main.java
Main.java:5: error: cannot find symbol
System.out.println(total);
^
symbol: variable total
location: class Main
1 error « o erro de nome só aparece agora
O contrário também acontece: um único engano gera vários erros. O nome inválido int class = 10; produziu três mensagens na aula Sintaxe e Estrutura. Consertado o engano, as três somem juntas.
Missão: conserte o programa acima usando o método: rode, conserte o primeiro erro, rode de novo. A variável total não existe; apague essa linha ou crie a variável antes dela (int total = 10;).
public class Main {
public static void main(String[] args) {
System.out.println("Oi");
System.out.println("Tchau")
System.out.println(total);
}
}
public class Main {
public static void main(String[] args) {
int total = 10;
System.out.println("Oi");
System.out.println("Tchau");
System.out.println(total);
}
}
O vocabulário das mensagens
Com umas vinte palavras, você entende quase todas as mensagens:
| Inglês | Quer dizer |
|---|---|
expected | esperado, "esperava encontrar" |
cannot find symbol | não consigo encontrar o símbolo (um nome: variável, método, classe) |
symbol / location | o nome procurado / onde ele foi procurado |
incompatible types | tipos incompatíveis |
cannot be converted to | não pode ser convertido em |
missing | faltando |
unclosed | não fechado |
illegal | inválido, proibido ali |
reached end of file | cheguei ao fim do arquivo |
while parsing | enquanto analisava (lia a estrutura do código) |
not a statement | não é uma instrução |
might not have been initialized | pode não ter recebido valor |
without | sem |
should be declared in | deveria estar declarada em |
does not exist | não existe |
already defined | já definido (nome repetido) |
Os erros mais comuns de iniciante
Cada erro abaixo tem o código com o problema, a mensagem real, o que ela quer dizer e como consertar. Nos programas de verdade eles aparecem dentro de public class Main e do main; aqui, para economizar espaço, alguns mostram só o trecho importante, mas a mensagem é a do programa completo.
1. ';' expected
$ javac Main.java
Main.java:3: error: ';' expected
System.out.println("Olá, Ana")
^
1 error
Quer dizer: "esperava um ponto e vírgula". A instrução acabou e o ; não veio. Conserto: ponha o ; onde o ^ aponta. Variação: com um espaço no meio de um nome (Sys tem.out) ou um nome inválido (int nota final), o javac também pede um ;, porque acha que a instrução acabou antes do espaço (veja Sintaxe e Estrutura).
2. cannot find symbol: erro de digitação
int nota = 8; System.out.println(ntoa);
$ javac Main.java
Main.java:4: error: cannot find symbol
System.out.println(ntoa);
^
symbol: variable ntoa
location: class Main
1 error
Quer dizer: "não encontrei nada chamado ntoa". O symbol: diz o que faltou e de que tipo (variable, method, class). Conserto: compare a grafia com a da declaração (nota). Também aparece quando a variável ainda não foi criada, foi criada mais abaixo, ou quando você esqueceu as aspas de um texto (println(Olá)).
3. cannot find symbol: maiúscula e minúscula
$ javac Main.java
Main.java:3: error: cannot find symbol
string nome = "Ana";
^
symbol: class string
location: class Main
1 error
$ javac Main.java
Main.java:3: error: cannot find symbol
System.out.Println("Oi");
^
symbol: method Println(String)
location: variable out of type PrintStream
1 error
Quer dizer: no primeiro, "não existe a classe string" (o certo é String); no segundo, "não existe o método Println que recebe um String, no out" (o certo é println). Conserto: o Java diferencia maiúsculas: String, System, println. Com system minúsculo, a mensagem é outra: error: package system does not exist.
4. class Main is public, should be declared in a file named Main.java
$ javac Ola.java
Ola.java:1: error: class Main is public, should be declared in a file named Main.java
public class Main {
^
1 error
Quer dizer: "a classe Main é pública e deveria estar num arquivo chamado Main.java". Conserto: renomeie o arquivo ou a classe para ficarem iguais, com as mesmas maiúsculas (veja Olá, Mundo).
5. incompatible types: String cannot be converted to int
int idade = "29";
$ javac Main.java
Main.java:3: error: incompatible types: String cannot be converted to int
int idade = "29";
^
1 error
Quer dizer: "tipos incompatíveis: um texto (String) não pode ser convertido em inteiro (int)". Com aspas, "29" é texto, e a caixa idade só aceita números inteiros. Conserto: tire as aspas (int idade = 29;). Se o número vem mesmo de um texto (do teclado, por exemplo), ele precisa ser convertido (veja Conversão de Tipos). Outras combinações aparecem com o mesmo começo: ao guardar 2.5 num int, a mensagem é incompatible types: possible lossy conversion from double to int ("possível perda na conversão de double para int").
6. reached end of file while parsing
public class Main {
public static void main(String[] args) {
System.out.println("Oi");
}
$ javac Main.java
Main.java:4: error: reached end of file while parsing
}
^
1 error
Quer dizer: "cheguei ao fim do arquivo enquanto analisava": faltou fechar uma chave, e o arquivo acabou com um bloco ainda aberto. O ^ aponta para depois da última chave. Conserto: conte as chaves; com o recuo certo, é fácil ver qual { ficou sem par (aqui, a da classe). Uma aspa ou um comentário /* sem fechar podem causar o mesmo erro.
7. missing return statement
public class Main {
static int dobro(int n) {
int r = n * 2;
}
public static void main(String[] args) {
System.out.println(dobro(4));
}
}
$ javac Main.java
Main.java:4: error: missing return statement
}
^
1 error
Quer dizer: "falta a instrução return". O método dobro promete devolver um int (está escrito int dobro), mas chega à chave final sem devolver nada. Você vai criar métodos assim em Métodos e Valores de Retorno. Conserto: devolva o valor (return r;) antes da }. Se o método não deve devolver nada, ele deve ser void.
8. unclosed string literal
$ javac Main.java
Main.java:3: error: unclosed string literal
System.out.println("Olá, Ana);
^
1 error
Quer dizer: "texto não fechado": uma aspa abriu um texto e a linha acabou antes da aspa de fechamento. O ^ aponta a aspa que abriu. Repare que tudo depois dela, inclusive o );, virou parte do texto. Conserto: feche as aspas: "Olá, Ana". Com aspas simples num texto ('Olá'), o erro parecido é unclosed character literal: em Java, aspas simples são só para um caractere (veja char e boolean).
9. not a statement
int nota = 8; nota;
$ javac Main.java
Main.java:4: error: not a statement
nota;
^
1 error
Quer dizer: "isto não é uma instrução": a linha tem um valor solto, que não faz nada (não escreve, não guarda, não chama ninguém). Conserto: diga o que fazer com o valor: System.out.println(nota); ou nota = nota + 1;. Também aparece em nomes inválidos, como int 2notas = 10;. No JShell, ao contrário, um valor solto é permitido: ele mostra o valor.
10. 'else' without 'if'
int nota = 8;
if (nota >= 7);
System.out.println("Aprovada");
else
System.out.println("Reprovada");
$ javac Main.java
Main.java:6: error: 'else' without 'if'
else
^
1 error
Quer dizer: "um else sem if". O if está lá, mas o ; logo depois do if (nota >= 7) encerrou o if ali mesmo, com uma instrução vazia. O println("Aprovada") virou uma linha comum, e o else ficou órfão. Você vai estudar o if em if, else if, else. Conserto: tire o ; depois do parêntese e use chaves:
if (nota >= 7) {
System.out.println("Aprovada");
} else {
System.out.println("Reprovada");
}
11. variable nota might not have been initialized
int nota; System.out.println(nota);
$ javac Main.java
Main.java:4: error: variable nota might not have been initialized
System.out.println(nota);
^
1 error
Quer dizer: "a variável nota pode não ter recebido um valor". Ela foi criada (int nota;), mas a caixa está vazia, e o Java não deixa usar uma caixa vazia. Conserto: dê um valor antes de usar: int nota = 8; (veja Variáveis).
Missão: este programa junta três erros da lista (um ;, uma maiúscula e uma variável sem valor). Rode, identifique cada um pela mensagem e conserte até aparecer Nota: 8.
public class Main {
public static void main(String[] args) {
int nota;
String texto = "Nota: "
system.out.println(texto + nota);
}
}
public class Main {
public static void main(String[] args) {
int nota = 8;
String texto = "Nota: ";
System.out.println(texto + nota);
}
}
Resumo dos erros
| Mensagem | Causa mais comum | Conserto |
|---|---|---|
';' expected | Faltou ; | Pôr o ; no fim da instrução |
cannot find symbol | Nome digitado errado, maiúscula, variável não criada, texto sem aspas | Conferir a grafia com a declaração |
package system does not exist | system minúsculo | System |
class X is public, should be declared in a file named X.java | Nome do arquivo ≠ nome da classe | Renomear um dos dois |
incompatible types | Valor do tipo errado (texto numa caixa de número) | Usar o tipo certo; tirar as aspas |
reached end of file while parsing | Faltou fechar } | Contar as chaves |
missing return statement | Método sem return | return valor; ou void |
unclosed string literal | Aspa sem par | Fechar as aspas |
not a statement | Valor solto; nome inválido | Usar o valor (println, atribuição) |
'else' without 'if' | ; depois do if (…) | Tirar o ;, usar chaves |
might not have been initialized | Variável usada sem valor | Dar um valor ao criar |
A lista completa, com dezenas de outras mensagens, fica na referência Erros do Compilador.
Erro de compilação × erro em tempo de execução
Tudo nesta aula é erro de compilação: o javac recusa o código e nenhum programa é gerado. Existe outro tipo: código que compila sem reclamação, mas quebra enquanto roda, quando tenta fazer algo impossível. Esse é um erro em tempo de execução, e em Java ele aparece como uma exceção:
$ javac Div.java « compilou sem erro nenhum $ java Div Exception in thread "main" java.lang.ArithmeticException: / by zero at Div.main(Div.java:3)
| Erro de compilação | Erro em tempo de execução (exceção) | |
|---|---|---|
| Quando aparece | Ao compilar (javac) | Ao rodar (java) |
| Quem avisa | O compilador | A JVM |
| Formato | Main.java:3: error: … + linha + ^ | Exception in thread "main" java.lang.NomeDaExcecao: … + at …(Main.java:3) |
| O programa rodou? | Não; nem existe .class novo | Sim, até a linha do problema |
| Causa típica | Escrita: pontuação, nomes, tipos | Situação: divisão por zero, posição que não existe numa lista, valor vazio (null) |
| Código de saída | javac devolve 1 | java devolve 1 |
| Onde estudar | Esta aula e Erros do Compilador | O que são Exceções e Exceções Comuns |
Os erros de compilação são os "bons": aparecem cedo, sempre, com a linha marcada. Um dos motivos de o Java conferir tantas coisas na compilação (como os tipos das variáveis) é transformar erros que só apareceriam rodando, talvez na frente de um cliente, em erros que aparecem na sua tela antes.
Missão: aqui o objetivo é o contrário: provoque o erro unclosed string literal. Apague a aspa de fechamento do texto e rode. Ver o erro de propósito ajuda a reconhecê-lo depois.
public class Main {
public static void main(String[] args) {
System.out.println("Olá, Ana");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("Olá, Ana);
}
}
Exercícios
1. A linha do erro
A mensagem é Loja.java:12: error: ';' expected. Em que linha está o problema?
2. O que faltou
A mensagem é error: reached end of file while parsing. Que símbolo provavelmente faltou?
3. O javac mostrou 5 erros. Qual é a melhor estratégia?
4. int idade = "29"; dá qual erro?
5. Em cannot find symbol … symbol: variable totl, o que provavelmente aconteceu?
6. Exception in thread "main" java.lang.ArithmeticException é…
Resumo
- Formato:
Arquivo.java:LINHA: error: descrição, a linha copiada, um^na coluna, e a contagem. - Leia o primeiro erro, conserte, compile de novo. Erros novos depois de um conserto são normais.
- O
^marca onde ojavacpercebeu; se a linha parece certa, olhe a de cima. - Os mais comuns:
';' expected,cannot find symbol,class … is public,incompatible types,reached end of file,missing return statement,unclosed string literal,not a statement,'else' without 'if',might not have been initialized. - Erro de compilação: nada roda. Exceção: rodou e quebrou. A referência completa é Erros do Compilador.