Java Valores de Retorno
Até aqui, os seus métodos só faziam coisas: imprimiam na tela. Muitas vezes, porém, você quer que o método calcule algo e entregue o resultado para quem chamou, que decide o que fazer com ele. Esse resultado é o valor de retorno, e a palavra que o entrega é return.
- Como declarar o tipo de retorno (
int,double,String,boolean…) no lugar dovoid. - O que o
returnfaz: devolve o valor e encerra o método. - Como usar o valor devolvido: imprimir, guardar numa variável, usar numa conta ou num
if. - O
return;sozinho, para sair cedo de um métodovoid. - Os erros reais:
missing return statement,unexpected return value,unreachable statemente outros.
A ideia antes do código: a calculadora e o papel
Imagine que a Ana pede para o Bruno calcular a média de duas notas. Há dois jeitos de o Bruno responder:
- Ele grita o resultado: "7,5!". Todo mundo ouve, mas a Ana não tem o número na mão. Se ela quiser saber se a média passa de 7, precisa ter prestado atenção e anotar. É o que um método
voidque imprime faz. - Ele escreve o resultado num papel e entrega para a Ana. Agora ela pode guardar, comparar, somar com outra coisa, imprimir quando quiser. É o que um método com retorno faz.
O System.out.println é o grito; o return é o papel entregue na mão.
Seu primeiro método com retorno
public class Main {
static double media(double nota1, double nota2) {
double resultado = (nota1 + nota2) / 2;
return resultado;
}
public static void main(String[] args) {
System.out.println(media(7.0, 8.0));
double mediaBruno = media(6.5, 9.0);
System.out.println("Média do Bruno: " + mediaBruno);
if (media(5.0, 6.0) >= 7) {
System.out.println("Carla: aprovada");
} else {
System.out.println("Carla: em recuperação");
}
}
}
$ javac Main.java && java Main 7.5 Média do Bruno: 7.75 Carla: em recuperação « média 5.5: não chegou a 7
- static
- Como sempre nesta fase: método da classe (veja Por que static?).
- double
- O tipo de retorno. No lugar do
void("não devolve nada") agora está o tipo do valor que o método entrega: umdouble. - media(double nota1, double nota2)
- Nome e parâmetros, como você já conhece.
- return resultado;
- "Devolva o valor de
resultado". O valor vai para o lugar da chamada, e o método termina ali.
Repare no main: a chamada media(7.0, 8.0) funciona como se fosse o próprio número 7.5. Por isso ela pode ir em qualquer lugar onde caberia um double:
| Onde a chamada aparece | O que acontece com o valor |
|---|---|
System.out.println(media(7.0, 8.0)); | Vai direto para o println, que o imprime. |
double mediaBruno = media(6.5, 9.0); | É guardado numa variável, para usar depois. |
"Média: " + media(…) | Entra numa conta ou concatenação. |
if (media(5.0, 6.0) >= 7) | É comparado numa condição. |
media(media(7, 8), 10) | Vira argumento de outra chamada. |
Dá para encurtar: em vez de criar a variável resultado, o return pode receber a conta direto. As duas formas são equivalentes:
static double media(double nota1, double nota2) {
return (nota1 + nota2) / 2;
}
O return aceita qualquer expressão: uma variável, um número, uma conta, uma comparação, a chamada de outro método. O Java calcula a expressão e devolve o resultado.
Missão: escreva o método static int dobro(int numero) que devolva (com return, sem imprimir) o dobro do número. O main já imprime os resultados: 10 e 42.
public class Main {
// escreva o método dobro aqui
public static void main(String[] args) {
System.out.println(dobro(5));
int resposta = dobro(21);
System.out.println(resposta);
}
}
public class Main {
static int dobro(int numero) {
return numero * 2;
}
public static void main(String[] args) {
System.out.println(dobro(5));
int resposta = dobro(21);
System.out.println(resposta);
}
}
Qualquer tipo pode ser devolvido
O tipo de retorno pode ser qualquer tipo do Java. Três exemplos da escola da Ana:
public class Main {
static boolean aprovado(double nota) {
return nota >= 7;
}
static String situacao(double nota) {
if (nota >= 7) {
return "aprovado";
} else if (nota >= 5) {
return "recuperação";
} else {
return "reprovado";
}
}
static int dobro(int numero) {
return numero * 2;
}
public static void main(String[] args) {
System.out.println(aprovado(8.5));
System.out.println(aprovado(4.0));
System.out.println("Nota 6: " + situacao(6));
System.out.println("Nota 9.5: " + situacao(9.5));
System.out.println("Nota 3: " + situacao(3));
System.out.println(dobro(dobro(5)));
}
}
$ javac Main.java && java Main true false Nota 6: recuperação Nota 9.5: aprovado Nota 3: reprovado 20 « dobro(5) = 10; dobro(10) = 20
boolean aprovado:nota >= 7já é umtrueoufalse(veja Expressões Booleanas), então dá para devolvê-la direto. Não precisa deif (nota >= 7) return true; else return false;.String situacao: o método tem trêsreturn, um em cada caminho doif. Só um deles roda em cada chamada: o primeiro que for alcançado encerra o método.dobro(dobro(5)): a chamada de dentro roda primeiro e devolve10; esse valor vira o argumento da chamada de fora.
Não existe return a, b; em Java. Se você precisa devolver várias informações (nome e média de um aluno, por exemplo), devolva um array, ou melhor, um objeto que agrupe tudo. A forma mais curta de criar esse objeto é um record, que você verá mais adiante.
O return encerra o método
O return faz duas coisas ao mesmo tempo: entrega o valor e sai do método. Nenhuma linha depois dele, no mesmo caminho, é executada. Isso explica por que o método situacao funciona: quando a nota é 9.5, o primeiro return já encerra tudo, e os outros nem são olhados.
return; sozinho em métodos void
Um método void não devolve nada, mas pode usar return; (sem valor) só para sair mais cedo. É comum para tratar um caso especial logo no começo:
public class Main {
static void mostrarRaiz(double numero) {
if (numero < 0) {
System.out.println(numero + " é negativo: não tem raiz real.");
return;
}
System.out.println("Raiz de " + numero + " = " + Math.sqrt(numero));
}
public static void main(String[] args) {
mostrarRaiz(16);
mostrarRaiz(-4);
mostrarRaiz(2);
}
}
$ javac Main.java && java Main Raiz de 16.0 = 4.0 -4.0 é negativo: não tem raiz real. « o return; impediu a linha do Math.sqrt Raiz de 2.0 = 1.4142135623730951
Com -4, o if imprime o aviso e o return; encerra o método; a linha do Math.sqrt não roda. Esse padrão ("se o caso é ruim, avise e saia") se chama cláusula de guarda e evita ifs dentro de ifs.
| Tipo do método | return valor; | return; | Sem nenhum return |
|---|---|---|---|
void | Erro: unexpected return value | Permitido (sai cedo) | Permitido: termina no } |
int, String, … | Obrigatório em todo caminho | Erro: missing return value | Erro: missing return statement |
Imprimir ou devolver?
Esta é a dúvida mais comum de quem começa. Compare dois métodos que parecem fazer a mesma coisa:
| Imprime | Devolve |
|---|---|
static void mostrarMedia(double a, double b) { | static double media(double a, double b) { |
O valor vai para a tela e some. O main não consegue comparar, guardar nem somar. | O valor volta para o main, que decide: imprimir, guardar, comparar, mandar para outro método. |
| Útil para métodos cuja tarefa é mostrar (um cabeçalho, um menu, um relatório). | Útil para métodos cuja tarefa é calcular ou decidir. |
Uma boa regra: métodos que calculam devolvem; quem decide o que mostrar é o main (ou outro método de "tela"). Assim o mesmo media serve para imprimir, para um if e para uma planilha.
Ignorar o valor devolvido
O Java deixa você chamar um método que devolve algo e não usar o resultado. Compila e roda, sem aviso:
public class Main {
static double media(double nota1, double nota2) {
return (nota1 + nota2) / 2;
}
public static void main(String[] args) {
media(7.0, 8.0);
System.out.println("Calculei a média... mas onde ela está?");
}
}
$ javac Main.java && java Main Calculei a média... mas onde ela está?
A média (7.5) foi calculada e jogada fora: ninguém pegou o papel que o método entregou. É um engano comum: o return não imprime nada. Para ver o valor, imprima-o (System.out.println(media(7.0, 8.0));) ou guarde-o numa variável.
No JShell, o valor devolvido aparece sozinho
O JShell mostra o valor de toda expressão. É um jeito rápido de ver o que um método devolve:
$ jshell
| Welcome to JShell -- Version 25.0.4.1
| For an introduction type: /help intro
jshell> int dobro(int n) { return n * 2; }
| created method dobro(int)
jshell> dobro(21)
$2 ==> 42
jshell> void saudar() { System.out.println("Oi!"); }
| created method saudar()
jshell> saudar()
Oi!
jshell> int x = dobro(5) + 1
x ==> 11
jshell> /exit
| Goodbye
Compare: dobro(21) mostra $2 ==> 42, um valor que o JShell guardou na variável automática $2. Já saudar() mostra só Oi!, que foi impresso; não há ==> porque um método void não devolve nada.
Missão: no JShell, declare boolean par(int n) { return n % 2 == 0; } e chame par(10). O JShell deve mostrar o valor devolvido, true.
boolean par(int n) { return n % 2 == 0; }
par(10)
Formas diferentes de escrever o mesmo retorno
Os três métodos abaixo devolvem a mesma coisa. Todos estão certos:
// 1. if com return e um return final
static String situacao(double nota) {
if (nota >= 7) {
return "aprovado";
}
return "reprovado";
}
// 2. operador ternário
static String situacaoTernario(double nota) {
return nota >= 7 ? "aprovado" : "reprovado";
}
// 3. variável e um único return no fim
static String situacaoVariavel(double nota) {
String resultado;
if (nota >= 7) {
resultado = "aprovado";
} else {
resultado = "reprovado";
}
return resultado;
}
Num main que chama os três métodos, um ao lado do outro, com a nota 8 e depois com a nota 5:
$ javac Main.java && java Main aprovado aprovado aprovado reprovado reprovado reprovado
| Forma | Quando usar |
|---|---|
1. return dentro do if + return final | Vários casos, cada um com sua saída. A mais comum. Note que, depois do if com return, o else é desnecessário. |
2. Ternário ? : | Escolha simples entre dois valores, que cabe numa linha. |
3. Variável + um return no fim | Quando o valor é montado em etapas, ou quando você quer um ponto único de saída para depurar. |
switch com setas: return switch (…) { … }; | Muitos casos com valores fixos (dia da semana, código de produto). |
Quando dá errado
public class Main {
static String situacao(double nota) {
if (nota >= 7) {
return "aprovado";
} else if (nota < 7) {
return "reprovado";
}
}
public static void main(String[] args) {
System.out.println(situacao(8));
}
}
$ javac Main.java
Main.java:8: error: missing return statement
}
^
1 error
O que aconteceu: "falta a instrução return". Para você, nota >= 7 e nota < 7 cobrem todos os casos. Mas o compilador não analisa o significado das condições: ele vê um if e um else if sem else e conclui que existe um caminho em que nenhum return roda. A setinha aponta para a chave que fecha o método: é ali que o método "cairia" sem valor.
Como resolver: troque o último else if (…) por else, ou coloque um return depois do if. Regra: num método com tipo de retorno, todo caminho possível precisa terminar num return (ou num throw, que você verá em throw e throws).
public class Main {
static void saudar(String nome) {
return "Olá, " + nome;
}
public static void main(String[] args) {
saudar("Ana");
}
}
$ javac Main.java
Main.java:3: error: incompatible types: unexpected return value
return "Olá, " + nome;
^
1 error
O que aconteceu: "valor de retorno inesperado". O método é void (promete não devolver nada) e tenta devolver um texto.
Como resolver: decida o que o método deve fazer. Se é para devolver o texto, troque void por String: static String saudar(String nome). Se é só para mostrar, troque o return por System.out.println(…).
return)
public class Main {
static int dobro(int numero) {
return numero * 2;
System.out.println("Calculei o dobro!");
}
public static void main(String[] args) {
System.out.println(dobro(5));
}
}
$ javac Main.java
Main.java:4: error: unreachable statement
System.out.println("Calculei o dobro!");
^
1 error
O que aconteceu: "instrução inalcançável". O return encerra o método; a linha de baixo nunca poderia rodar. Em vez de ignorá-la em silêncio, o Java recusa o código, porque quase sempre isso é um engano.
Como resolver: coloque a linha antes do return, ou apague-a.
$ javac Main.java
Main.java:3: error: incompatible types: missing return value
return;
^
1 error
O que aconteceu: o método é static int dobro(int numero), mas o return; não tem valor. Um método int precisa sempre devolver um int.
Como resolver: return numero * 2;.
$ javac Main.java
Main.java:3: error: incompatible types: possible lossy conversion from double to int
return (a + b) / 2.0;
^
1 error
O que aconteceu: o método promete devolver int, mas (a + b) / 2.0 é um double (o 2.0 faz a conta virar decimal). Passar de double para int perderia as casas decimais, e o Java não faz isso sozinho.
Como resolver: mude o tipo de retorno para double ou converta de propósito com (int) (veja Conversão de Tipos).
void
$ javac Main.java
Main.java:7: error: incompatible types: void cannot be converted to String
String frase = saudar("Ana");
^
1 error
$ javac Main.java
Main.java:7: error: 'void' type not allowed here
System.out.println(saudar("Ana"));
^
1 error
O que aconteceu: saudar é void: não há valor para guardar numa variável nem para mandar ao println. A primeira mensagem diz "void não pode ser convertido em String"; a segunda, "o tipo void não é permitido aqui".
Como resolver: chame o método sozinho (saudar("Ana");) ou mude-o para devolver um String com return.
Referência
| Escrita | Significado |
|---|---|
static Tipo nome(…) { … return valor; } | Método que devolve um valor do Tipo |
static void nome(…) { … } | Método que não devolve nada |
return expressão; | Calcula a expressão, devolve o resultado e encerra o método |
return; | Encerra um método void antes do fim |
Tipo x = metodo(…); | Guarda o valor devolvido |
metodo(…); (num método com retorno) | Permitido, mas o valor é descartado |
missing return statement | Algum caminho do método termina sem return |
unexpected return value | return valor; num método void |
unreachable statement | Código depois de um return |
missing return value | return; sem valor num método que devolve algo |
Missão final: o conceito da nota
Missão: escreva static String conceito(double nota) que devolva "A" para nota 9 ou mais, "B" para nota 7 ou mais e "C" para o resto. O main já está pronto. Cuidado com o missing return statement!
public class Main {
// escreva o método conceito aqui
public static void main(String[] args) {
double[] notas = {9.5, 7.0, 4.0};
for (double n : notas) {
System.out.println(n + " → " + conceito(n));
}
}
}
public class Main {
static String conceito(double nota) {
if (nota >= 9) {
return "A";
}
if (nota >= 7) {
return "B";
}
return "C";
}
public static void main(String[] args) {
double[] notas = {9.5, 7.0, 4.0};
for (double n : notas) {
System.out.println(n + " → " + conceito(n));
}
}
}
Exercícios
1. O tipo de retorno
Complete para o método devolver a idade em meses (um número inteiro):
2. A palavra que devolve
Complete o corpo do método que devolve o triplo:
3. Guardar o resultado
O método static double media(double a, double b) já existe. Complete para guardar a média de 6 e 8 na variável m:
4. Um método static int f() tem as linhas return 1; e, logo abaixo, return 2;. O que acontece?
5. Qual destas linhas é válida dentro de um método void?
6. O programa chama media(7, 8); numa linha sozinha, e media devolve um double com return. O que aparece na tela?
Resumo
- O tipo de retorno fica antes do nome do método:
static double media(…).voidquer dizer "não devolve nada". return valor;entrega o valor para quem chamou e encerra o método.- A chamada vale o valor devolvido: dá para imprimir, guardar, comparar e passar para outro método.
returnnão imprime nada. Um valor devolvido e não usado é descartado.- Em métodos
void,return;sai mais cedo (cláusula de guarda). - Todo caminho de um método com retorno precisa de
return(missing return statement); código depois doreturnéunreachable statement;return valor;emvoidéunexpected return value. - Calcule com retorno; deixe a impressão para quem chama.