O JLS especifica que
Se o resultado do tipo de função for nulo, o corpo lambda é uma expressão de instrução (§14.8) ou um bloco compatível com nulo.
Agora vamos ver isso em detalhes,
Uma vez que seu takeBiConsumer
método é do tipo void, o receptor lambda new String("hi")
irá interpretá-lo como um bloco como
{
new String("hi");
}
que é válido em um vazio, daí a primeira compilação de caso.
No entanto, no caso em que o lambda é -> "hi"
, um bloco como
{
"hi";
}
não é uma sintaxe válida em java. Portanto, a única coisa a fazer com "oi" é tentar devolvê-lo.
{
return "hi";
}
que não é válido em um vazio e explica a mensagem de erro
incompatible types: bad return type in lambda expression
java.lang.String cannot be converted to void
Para um melhor entendimento, note que se você alterar o tipo de takeBiConsumer
para String, -> "hi"
será válido pois simplesmente tentará retornar diretamente a string.
Observe que, a princípio, achei que o erro era causado pelo lambda estar em um contexto de invocação incorreto, portanto, compartilharei essa possibilidade com a comunidade:
JLS 15.27
É um erro em tempo de compilação se uma expressão lambda ocorre em um programa em algum lugar diferente de um contexto de atribuição (§5.2), um contexto de invocação (§5.3) ou um contexto de lançamento (§5.5).
No entanto, em nosso caso, estamos em um contexto de invocação correto.