Como sabemos, a linguagem Java é uma linguagem de programação orientada a objetos. Em outras palavras, o conceito fundamental, ou seja, o fundamento do fundamento, é que tudo é um objeto. Objetos são descritos usando classes. As classes, por sua vez, definem o estado e o comportamento. Por exemplo, uma conta bancária pode ter estado na forma da quantidade de dinheiro na conta e ter comportamentos que aumentam e diminuem o saldo da conta. Em Java, os comportamentos são implementados por meio de métodos. Aprender como definir métodos vem logo no início de seus estudos de Java. Por exemplo, no tutorial oficial da Oracle, sob o título " Definindo Métodos ". Há duas coisas importantes a serem observadas aqui:
  • Cada método tem uma assinatura. A assinatura consiste no nome do método e seus parâmetros de entrada.
  • Um tipo de retorno deve ser especificado para métodos. Você declara o tipo de retorno de um método em sua declaração de método.
O tipo de retorno não faz parte da assinatura do método. Novamente, isso é consequência do fato de que Java é uma linguagem fortemente tipada e o compilador deseja saber quais tipos são usados ​​e onde, com antecedência e o máximo possível. Novamente, isso é para nos salvar de erros. Basicamente, é tudo por uma boa causa. E me parece que isso mais uma vez incute em nós uma cultura de manipulação de dados. Portanto, o tipo do valor de retorno é especificado para os métodos. E a palavra-chave return em Java é usada para realmente fazer o retorno. Palavra-chave de retorno Java - 1

O que return faz em Java

A palavra-chave return é uma instrução de fluxo de controle, conforme descrito no tutorial Oracle aqui . Você também pode ler sobre como retornar valores na seção " Retornando um valor de um método " do tutorial oficial. O compilador monitora cuidadosamente se pode garantir que o valor de retorno de um método corresponda ao tipo de retorno especificado do método. Vamos usar o IDE on-line do Tutorialspoint para considerar um exemplo. Vejamos o exemplo primitivo:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}
Como podemos ver, aqui é executado o método main , que é o ponto de entrada do programa. As linhas de código são executadas de cima para baixo. Nosso método principal não pode retornar um valor. Se tentarmos retornar um valor lá, obteremos um erro: "Error: Main method must return a value of type void" . Consequentemente, o método simplesmente exibe na tela. Agora vamos mover a string literal para um método separado para gerar a mensagem:

public class HelloWorld {

    public static void main(String[] args) {
        System.out.println(getHelloMessage());
    }
    
    public static String getHelloMessage() {
        return "Hello World";
    }
    
}
Como podemos ver, usamos a palavra-chave return para indicar o valor de retorno, que então passamos para o método println . A declaração do método getHelloMessage indica que o método retornará uma String . Isso permite que o compilador verifique se as ações do método são consistentes com a forma como ele é declarado. Naturalmente, o tipo de retorno especificado em uma declaração de método pode ser mais amplo do que o tipo do valor realmente retornado no código, ou seja, o importante é que uma conversão de tipo seja possível. Caso contrário, obteremos um erro em tempo de compilação: "Error: tipos incompatíveis" . A propósito, você provavelmente tem uma pergunta: por que o retornoconsiderada uma declaração de fluxo de controle? Porque pode interromper o fluxo normal de cima para baixo de um programa. Exemplo:

public class HelloWorld {

    public static void main(String[] args) {
        if (args.length == 0) {
            return;
        }
        for (String arg : args) {
            System.out.println(arg);
        }
    }
    
}
Como você pode ver no exemplo, interrompemos o método main no programa Java se ele for chamado sem argumentos. É importante lembrar que se você tiver código após uma instrução de retorno , ele não estará acessível. Nosso compilador inteligente notará isso e impedirá que você execute esse programa. Por exemplo, este código não compila:

public static void main(String[] args) {
        System.out.println("1");
        return;
// we use output method after return statement, which is incorrect 
        System.out.println("2");
 }
Há um truque sujo para contornar isso. Por exemplo, para fins de depuração ou por algum outro motivo. O código acima pode ser corrigido agrupando a instrução return em um bloco if :

if (2==2) {
    return;
}

Declaração de retorno durante o tratamento de erros

Há outra coisa muito complicada - podemos usar o retorno em conjunto com o tratamento de erros. Quero dizer imediatamente que usar uma instrução return em um bloco catch é uma forma muito, muito ruim, então você deve evitá-la. Mas precisamos de um exemplo, certo? Aqui está:

public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Value: " + getIntValue());
    }
    
    public static int getIntValue() {
        int value = 1;
        try {
            System.out.println("Something terrible happens");
            throw new Exception();
        } catch (Exception e) {
            System.out.println("Cached value: " + value);
            return value;
        } finally {
            value++;
            System.out.println("New value: " + value);
        }
    }
    
}
À primeira vista, parece que 2 deveria ser retornado, já que o final é sempre executado. Mas não, o valor de retorno será 1 e a alteração da variável no bloco final será ignorada. Além disso, suponha que value contenha um objeto e digamos value = null no bloco final . Então esse objeto, não nulo, seria retornado no bloco catch . Mas uma instrução return funcionaria corretamente no bloco final . Obviamente, seus colegas de trabalho não vão agradecer por pequenas surpresas envolvendo declarações de retorno.

void.class

E finalmente. Existe esta construção estranha que você pode escrever: void.class . Hum. Por que e o que significa? Realmente existem vários frameworks e casos complicados envolvendo a API Java Reflection onde isso pode ser muito útil. Por exemplo, você pode verificar qual tipo um método retorna:

import java.lang.reflect.Method;

public class HelloWorld {

    public void getVoidValue() {
    }

    public static void main(String[] args) {
        for (Method method : HelloWorld.class.getDeclaredMethods()) {
            System.out.println(method.getReturnType() == void.class);
        }
    }
}
Isso pode ser útil em estruturas de teste em que você precisa substituir o código real em métodos. Mas para fazer isso, você precisa entender como um método se comporta (ou seja, que tipo ele retorna). Há também uma segunda maneira de implementar o método main no código acima:

public static void main(String[] args) {
        for (Method method : HelloWorld.class.getDeclaredMethods()) {
            System.out.println(method.getReturnType() == Void.TYPE);
        }
 }
Você pode ler uma discussão bastante interessante sobre a diferença entre os dois no Stack Overflow: Qual é a diferença entre java.lang.Void e void?