Estou brincando com o Java 8 para descobrir como funciona como cidadãos de primeira classe. Eu tenho o seguinte trecho:
package test;
import java.util.*;
import java.util.function.*;
public class Test {
public static void myForEach(List<Integer> list, Function<Integer, Void> myFunction) {
list.forEach(functionToBlock(myFunction));
}
public static void displayInt(Integer i) {
System.out.println(i);
}
public static void main(String[] args) {
List<Integer> theList = new ArrayList<>();
theList.add(1);
theList.add(2);
theList.add(3);
theList.add(4);
theList.add(5);
theList.add(6);
myForEach(theList, Test::displayInt);
}
}
O que estou tentando fazer é passar método displayInt
para método myForEach
usando uma referência de método. Para o compilador produz o seguinte erro:
src/test/Test.java:9: error: cannot find symbol
list.forEach(functionToBlock(myFunction));
^
symbol: method functionToBlock(Function<Integer,Void>)
location: class Test
src/test/Test.java:25: error: method myForEach in class Test cannot be applied to given ty
pes;
myForEach(theList, Test::displayInt);
^
required: List<Integer>,Function<Integer,Void>
found: List<Integer>,Test::displayInt
reason: argument mismatch; bad return type in method reference
void cannot be converted to Void
O compilador reclama disso void cannot be converted to Void
. Não sei como especificar o tipo da interface da função na assinatura, de myForEach
modo que o código seja compilado. Eu sei que poderia simplesmente alterar o tipo de retorno de displayInt
para Void
e depois retornar null
. No entanto, pode haver situações em que não é possível alterar o método que desejo passar para outro lugar. Existe uma maneira fácil de reutilizar displayInt
como é?
Block
foi alterado paraConsumer
nos últimos lançamentos da API do JDK 8MethodHandle
) e, usando isso, o compilador Java pode produzir código mais eficiente, por exemplo, implementando lambdas sem fechamento como métodos estáticos, impedindo a geração de aulas adicionais.Function<Void, Void>
éRunnable
.Runnable
eCallable
interfaces, está escrito que eles devem ser usados em conjunto com threads . A conseqüência irritante disso é que algumas ferramentas de análise estática (como o Sonar) irão reclamar se você chamar orun()
método diretamente.Quando você precisa aceitar uma função como argumento que não aceita argumentos e não retorna resultado (vazio), na minha opinião ainda é melhor ter algo como
em algum lugar do seu código. Nos meus cursos de programação funcional, a palavra 'thunk' foi usada para descrever essas funções. Por que não está no java.util.function está além da minha compreensão.
Em outros casos, acho que mesmo quando o java.util.function tem algo que coincide com a assinatura que eu quero - ainda nem sempre parece certo quando a nomeação da interface não corresponde ao uso da função no meu código. Eu acho que é um argumento semelhante que é feito em outro lugar aqui sobre 'Runnable' - que é um termo associado à classe Thread -, portanto, embora possa ter a assinatura de que eu preciso, ainda é provável que confunda o leitor.
fonte
Runnable
, não permite exceções verificadas, tornando-o inútil para muitos aplicativos. ComoCallable<Void>
também não é útil, você precisa definir o que parece. Feio.Defina o tipo de retorno como em
Void
vez devoid
ereturn null
OU
fonte
Eu sinto que você deveria estar usando a interface Consumer em vez de
Function<T, R>
.Um consumidor é basicamente uma interface funcional projetada para aceitar um valor e não retornar nada (ou seja, nulo)
No seu caso, você pode criar um consumidor em outro lugar no seu código, assim:
Em seguida, você pode substituir seu
myForEach
código pelo snippet abaixo:Você trata myFunction como um objeto de primeira classe.
fonte