web-dev-qa-db-fra.com

interface fonctionnelle java8 pour gérer le rappel

J'ai une méthode privée générique qui effectue des tâches courantes et est utilisée par d'autres méthodes. La méthode générique a des conditions if et else pour prendre en charge d'autres méthodes appelées. Exemple:

private void myGenericMethod(String name, int age){
  common task1;
  common task2;
  if(name!= null && name.length > 0){
     specific task 1;
     specific task 2;
  } else{
     specific task 3;
     specific task 4;
  }
  if(age > 18){
     specific task 1`;
     specific task 2`;
  }
}

Je veux utiliser Java 8 lambda et j'ai créé une interface fonctionnelle appelée Invoker avec une méthode invoke.

public interface Invoker{
  public void invoke()
}

Maintenant, ma méthode générique ressemble à ceci et la méthode publique gère correctement le rappel de la fonction invoke:

private void myGenericMethod(Invoker invoker){
  common task1;
  common task2;
  invoker.invoke();
}  

Y a-t-il une interface fonctionnelle dans le JDK que je peux utiliser au lieu de créer cette interface par moi-même?

9
zilcuanu

Package Java.util.function ne contient pas d'interface fonctionnelle avec une méthode qui ne nécessite aucun paramètre et renvoie void. Mais vous pouvez utiliser l'interface Runnable à la place.

private void myGenericMethod(Runnable runnable){
    common task1;
    common task2;
    //consider checking if runnable != null to avoid NPE
    runnable.run();
}  

L'invocation serait alors assez simple:

myGenericMethod(() -> {
    //do something fancy
    System.out.println("Hello, world!");
});

Autres options

Il existe d'autres interfaces fonctionnelles qui pourraient vous intéresser, par exemple:

  • Supplier<T> si vous souhaitez renvoyer une valeur de T sans passer aucun paramètre
  • Function<T,R> si vous voulez passer une valeur de T et renvoyer une valeur de R
  • Consumer<T> si vous voulez passer la valeur T comme paramètre et retourner void

Pourquoi il n'y a pas d'alternative pour l'interface Runnable?

L'utilisation de l'interface Runnable pour un lambda qui ne retourne rien et n'attend aucun paramètre peut sembler controversée pour de nombreux programmeurs. Runnable a été inventé pour exécuter un code dans un thread séparé et de nombreux programmeurs identifient cette classe avec le multithreading. Même documentation dit:

L'interface Runnable doit être implémentée par n'importe quelle classe dont les instances sont destinées à être exécutées par un thread.

Quelqu'un déjà posé une question similaire il y a 2 ans et si vous regardez ce commentaire et la réaction de Brian Goetz à cela, vous comprendrez que Java ont conclu qu'il n'était pas nécessaire de créer une autre interface fonctionnelle qui imite l'implémentation de l'interface Runnable.

24
Szymon Stepniak

Il y a aussi la possibilité d'utiliser Consumer<Void>. Cela pourrait ressembler à ceci

public void init(Consumer<Void> callback) {
    callback.accept(null);
}

init((Void) -> done());
2
Murat Karagöz

Je suggère d'utiliser Consumer comme interface de rappel. En le comparant au langage JavaScript, les rappels sont liés avec une étendue. Par conséquent, si vous utilisez l'interface Consumer, vous pouvez transmettre la portée en tant que paramètre à la fonction. Ex:

public void startTracer(String tracerName, Event boundEvent) {
    executeOnTracer(tracer -> tracer.startTracer(tracerName, boundEvent));
}
...
private void executeOnTracer(Consumer<Tracer> callback) {
    TracerController tracer = null;
    if (isTracerActive()) {
        tracer = getTracer();
    }
    Optional.ofNullable(tracer).ifPresent(callback::accept);
}
0
João Pedro Schmitt