Je joue avec Java 8 pour découvrir comment fonctionne en tant que citoyen de première classe. J'ai l'extrait suivant:
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);
}
}
Ce que j'essaie de faire, c'est de passer la méthode displayInt
à la méthode en myForEach
utilisant une référence de méthode. Le compilateur génère l'erreur suivante:
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
Le compilateur s'en plaint void cannot be converted to Void
. Je ne sais pas comment spécifier le type de l'interface de fonction dans la signature de myForEach
telle sorte que le code se compile. Je sais que je pourrais simplement changer le type de retour de displayInt
à Void
, puis revenir null
. Cependant, il peut y avoir des situations où il n'est pas possible de modifier la méthode que je veux passer ailleurs. Existe-t-il un moyen simple de réutiliser displayInt
tel quel?
Block
été changé pour lesConsumer
dernières versions de l'API JDK 8MethodHandle
), et en utilisant cela, le compilateur Java est capable de produire du code plus efficace, par exemple en implémentant des lambdas sans fermeture en tant que méthodes statiques, empêchant ainsi la génération de classes supplémentaires.Function<Void, Void>
estRunnable
.Runnable
et lesCallable
interfaces, il est écrit qu'ils sont censés être utilisés en conjonction avec des threads . La conséquence ennuyeuse de cela est que certains outils d'analyse statique (comme Sonar) se plaindront si vous appelez larun()
méthode directement.Lorsque vous devez accepter une fonction comme argument qui ne prend aucun argument et ne renvoie aucun résultat (void), à mon avis, il est toujours préférable d'avoir quelque chose comme
quelque part dans votre code. Dans mes cours de programmation fonctionnelle, le mot «thunk» a été utilisé pour décrire ces fonctions. Pourquoi ce n'est pas dans java.util.function est au-delà de ma compréhension.
Dans d'autres cas, je trouve que même lorsque java.util.function a quelque chose qui correspond à la signature que je veux - cela ne me semble toujours pas correct lorsque le nom de l'interface ne correspond pas à l'utilisation de la fonction dans mon code. Je suppose que c'est un point similaire qui est fait ailleurs ici concernant 'Runnable' - qui est un terme associé à la classe Thread - donc bien qu'il puisse avoir la signature dont j'ai besoin, il est toujours susceptible de dérouter le lecteur.
la source
Runnable
n'autorise pas les exceptions vérifiées, ce qui le rend inutile pour de nombreuses applications. Comme ceCallable<Void>
n'est pas utile non plus, vous devez définir le vôtre semble-t-il. Laid.Définir le type de retour sur au
Void
lieu devoid
etreturn null
OU
la source
Je pense que vous devriez utiliser l'interface consommateur au lieu de
Function<T, R>
.Un consommateur est essentiellement une interface fonctionnelle conçue pour accepter une valeur et ne rien renvoyer (c'est-à-dire vide)
Dans votre cas, vous pouvez créer un consommateur ailleurs dans votre code comme ceci:
Ensuite, vous pouvez remplacer votre
myForEach
code par l'extrait ci-dessous:Vous traitez myFunction comme un objet de première classe.
la source