web-dev-qa-db-fra.com

Existe-t-il une interface similaire à Callable mais avec des arguments?

Existe-t-il une interface Java similaire à l'interface Callable, pouvant accepter un argument pour sa méthode call?

Ainsi:

public interface MyCallable<V> {
  V call(String s) throws Exception;
}

Je préférerais éviter de créer un nouveau type s'il existe déjà quelque chose que je peux utiliser. Ou existe-t-il une meilleure stratégie pour que plusieurs clients implémentent et connectent une routine appelable?

Copié à partir d'ici http://www.programmingforums.org/thread27905.html

50
raisercostin

Depuis Java 8, il existe tout un ensemble d'interfaces de type fonction dans le package Java.util.function . Celui que vous demandez spécifiquement est simplement Function .

Avant Java 8, il n'existait pas d'interface intégrée polyvalente pour cela, mais certaines bibliothèques le fournissaient.

Par exemple, Guava a l'interface Function<F,T> avec la méthode T apply(F input). Il fait également utilisation intensive de cette interface à plusieurs endroits.

39
Joachim Sauer

au début, il pensait que cela se faisait avec une interface, mais j’ai alors trouvé que cela devait être fait avec une classe abstraite.

je l'ai résolu de cette façon:


edit: dernièrement, je viens d'utiliser ceci:

    public static abstract class callback1<T>{
         public abstract  void run(T value);
    }

    public static abstract class callback2<T,J>{
         public abstract  void run(T value,J value2);
    }

    public static abstract class callback3<T,J,Z>{
         public abstract  void run(T value,J value2,Z value3);
    }


    public static abstract class callbackret1<R,T>{
         public abstract  R run(T value);
    }

    public static abstract class callbackret2<R,T,J>{
         public abstract  R run(T value,J value2);
    }

    public static abstract class callbackret3<R,T,J,Z>{
         public abstract  R run(T value,J value2,Z value3);
    }

CallBack.Java

public abstract class CallBack<TRet,TArg> {
    public abstract TRet call(TArg val);
}

définir une méthode:

class Sample2 
{
    CallBack<Void,String> cb;
    void callcb(CallBack<Void,String> CB)
    {
     cb=CB; //save the callback
     cb.call("yes!"); // call the callback
    }
}

méthode d'utilisation:

sample2.callcb(new CallBack<Void,String>(){
        @Override
        public Void call(String val) {
            // TODO Auto-generated method stub
            return null;
        }
    });

exemple de deux arguments: CallBack2.Java

public abstract class CallBack2<TRet,TArg1,TArg2> {
    public abstract TRet call(TArg1 val1,TArg2 val2);
}

notez que lorsque vous utilisez le type de retour Void, vous devez utiliser return null; Voici donc une variante permettant de résoudre ce problème, car les rappels ne renvoient habituellement aucune valeur.

vide comme type de retour: SimpleCallBack.Java

public abstract class SimpleCallBack<TArg> {
    public abstract void call(TArg val);
}

void as return type 2 args: SimpleCallBack2.Java

public abstract class SimpleCallBack<TArg1,TArg2> {
    public abstract void call(TArg1 val1,TArg2 val2);
}

l'interface n'est pas utile pour cela.

les interfaces permettent à plusieurs types de correspondre au même type. en ayant un ensemble prédéfini partagé de fonctions.

les classes abstraites permettent aux fonctions vides qu’elles contiennent d’être complétées ultérieurement. à l'extension ou l'instanciation. 

9
Shimon Doodkin

J'ai eu la même exigence récemment. Comme d'autres l'ont expliqué, de nombreuses bibliothèques fournissent des méthodes «fonctionnelles», mais elles ne génèrent pas d'exceptions. 

La bibliothèque RxJava est un exemple de la manière dont certains projets ont fourni une solution. Ils utilisent des interfaces telles que ActionX, où 'X' vaut 0 ... N, le nombre d'arguments de l'appel call méthode. Ils ont même une interface varargs, ActionN.

Mon approche actuelle consiste à utiliser une interface générique simple:

public interface Invoke<T,V>  {     
    public T call(V data) throws Exception;     
//  public T call(V... data) throws Exception;    
}

La deuxième méthode est préférable dans mon cas, mais elle présente le problème redouté suivant: "Type sécurité: pollution potentielle importante via des données de paramètre varargs" dans mon IDE, ce qui est un tout autre problème.

Une autre approche consiste à utiliser des interfaces existantes telles que Java.util.concurrent.Callable qui ne génèrent pas d’exception, et dans mon implémentation, les exceptions encapsulées dans des exceptions non vérifiées.

5
Josef.B

Depuis Java 1.8, il existe une interface Supplier<T>. Il a une méthode get() au lieu de call() et ne déclare aucune exception levée.

1
Shadow

La réponse est ambiguë. Strictement parlant, c’est-à-dire «dans le même but que l’interface Callable», il n’en existe pas.

Il existe des classes similaires, et selon ce que vous voulez, elles peuvent être ou ne pas être pratiques. L'un d'eux est le SwingWorker . Cependant, comme son nom l'indique, il a été conçu pour être utilisé dans le cadre de Swing. Il pourrait être utilisé à d'autres fins, mais ce serait un choix de conception médiocre.

Mon meilleur conseil est d’en utiliser une fournie par une bibliothèque d’extensions (Jakarta-Commons, Guava, etc.), en fonction des bibliothèques que vous utilisez déjà dans votre système.

1
Filipe Fedalto

Je viens d'avoir le même problème. vous pouvez envelopper n'importe quelle méthode pour retourner un appelable, et exécuter sa valeur renvoyée .

 main {    
    Callable<Integer> integerCallable = getIntegerCallable(400);
    Future<Integer> future = executor.submit(integerCallable);
}

private Callable<Integer> getIntegerCallable(int n) {
    return () -> {
            try {
                TimeUnit.SECONDS.sleep(n);
                return 123;
            } catch (InterruptedException e) {
                throw new IllegalStateException("task interrupted", e);
            }
        };
}
0
shemerk

Normalement, les arguments ne sont pas requis car la méthode peut avoir un nombre quelconque d'arguments dans son constructeur.

final int i = 5;
final String Word = "hello";

Future<String> future = service.submit(new Callable<String>() {
    public String call() {
        return Word + i;
    }
});

Dans cet exemple, i et Word ont été utilisés, mais vous pouvez "transmettre" un nombre quelconque de paramètres.

0
Peter Lawrey