Por que a seguinte conversão com referência de método não produz um erro de compilação? [duplicado]

24
public class SomeClass{

    public static int someFunction(int a) {
        return a;
    }

    public static void main(String[] args) {    
        Consumer<Integer> c = SomeClass::someFunction; 
    }
}

Não estou entendendo o porquê: Consumer<Integer> c = SomeClass::someFunction; não está produzindo um erro de compilação, desde que a função someFunction é um método com valor de retorno, e o consumidor está representando métodos sem valor de retorno

    
por eitann 08.03.2018 в 13:40
fonte

2 respostas

26

De a especificação :

  

Se o corpo de um lambda for uma expressão de instrução (isto é, um   expressão que seria permitido ficar sozinho como uma declaração), é   compatível com um tipo de função produtora de vazios; qualquer resultado é simplesmente   descartado.

O mesmo é verdadeiro para referências de métodos.

É mais flexível assim. Suponha que foi um erro do compilador não usar um valor de retorno quando você chamou um método normalmente - isso seria incrivelmente irritante . Você acabaria tendo que usar variáveis falsas com as quais não se importava em alguns casos.

public class SomeClass
{
    public static int someFunction(int a) {
        return a;
    }

    public static void main(String[] args) {    
        someFunction(3); // "error" - ignoring return type
        int unused = someFunction(3); // "success"
    }
}

Se você quiser uma definição formal completa do que é aceitável, consulte 15.13.2. Tipo de referência de método .

    
por Michael 08.03.2018 / 13:42
fonte
12

Isso é chamado de especial void compatibility rule . Por exemplo, quantas vezes você realmente se importou com o tipo de retorno List#add ? Mesmo se ele retornar true/false .

Praticamente a mesma coisa aqui, você pode invocar um método, mas ignorar seu resultado. Se você reescrever seu consumidor como uma expressão lambda, faz mais sentido:

Consumer<Integer> c = x -> {
   SomeClass.someFunction(x);
   return;     
}

Se bem me lembro do JLS, existem apenas alguns tipos permitidos para isso.

 increment/decrement operations
 method invocation
 assignment 
 instance creation
    
por Eugene 08.03.2018 / 15:10
fonte