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.

Você vai aprender
  • Como declarar o tipo de retorno (int, double, String, boolean…) no lugar do void.
  • O que o return faz: 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étodo void.
  • Os erros reais: missing return statement, unexpected return value, unreachable statement e 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:

  1. 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 void que imprime faz.
  2. 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: um double.
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 apareceO 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 >= 7 já é um true ou false (veja Expressões Booleanas), então dá para devolvê-la direto. Não precisa de if (nota >= 7) return true; else return false;.
  • String situacao: o método tem três return, um em cada caminho do if. 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 devolve 10; esse valor vira o argumento da chamada de fora.
Um método devolve um valor só

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étodoreturn valor;return;Sem nenhum return
voidErro: unexpected return valuePermitido (sai cedo)Permitido: termina no }
int, String, …Obrigatório em todo caminhoErro: missing return valueErro: 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:

ImprimeDevolve
static void mostrarMedia(double a, double b) {
  System.out.println((a + b) / 2);
}
static double media(double a, double b) {
  return (a + b) / 2;
}
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
FormaQuando usar
1. return dentro do if + return finalVá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 fimQuando 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

"missing return statement"
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).

"incompatible types: unexpected return value"
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(…).

"unreachable statement" (código depois do 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.

"incompatible types: missing return value"
$ 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;.

"possible lossy conversion from double to int"
$ 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).

Usar o "valor" de um método 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

EscritaSignificado
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 statementAlgum caminho do método termina sem return
unexpected return valuereturn valor; num método void
unreachable statementCódigo depois de um return
missing return valuereturn; 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):

static emMeses(int anos) { return anos * 12; }

2. A palavra que devolve

Complete o corpo do método que devolve o triplo:

static int triplo(int n) { }

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:

double 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(…). void quer 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.
  • return nã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 do return é unreachable statement; return valor; em void é unexpected return value.
  • Calcule com retorno; deixe a impressão para quem chama.