web-dev-qa-db-fra.com

Callable sera-t-il préféré à Runnable?

J'ai compris la différence entre les interfaces Runnable et Callable en Java. Depuis Java 1.5, des fonctionnalités supplémentaires ont été ajoutées à l'interface Runnable et ont été appelées Callable afin de maintenir la compatibilité en amont. 

Ma question est maintenant que nous avons l'interface Callable, allons-nous toujours l'utiliser? Quels sont les cas d'utilisation de la non-utilisation de Callable et de l'utilisation de Runnable

( Ceci est un bon article sur les différences entre eux) 

37
sheidaei

Les deux ont leurs utilisations et sont pris en charge par la structure Executor dans Java.util.concurrent. Runnable existe depuis plus longtemps, mais il est toujours utilisé et non découragé.

Callables peut générer des exceptions et renvoyer des valeurs, ce qui en fait la meilleure abstraction pour les tâches portant des résultats (telles que l'extraction d'une ressource sur le réseau, le calcul coûteux d'une valeur, etc.) [from Java Concurrency in Practice de Goetz, Bloch et. al., le travail standard sur la concurrence de Java].

Donc, si vous concevez une API, je suggérerais d'utiliser Callables lorsque cela est possible. Si vous êtes certain que les tâches ne renverront pas de valeurs et ne liront pas d'exceptions, alors Runnables constitue également un choix valide. Il n’ya pas de noir et blanc ici, en particulier parce que Runnables peut facilement être encapsulé dans Callables et inversement.

En passant, notez que votre implémentation Callable ne doit pas déclarer throws Exception; le fait que Callable lui-même le déclare, c'est uniquement pour permettre aux développeurs de renvoyer les exceptions vérifiées. Les appelants de votre Callable qui comptent uniquement sur l'interface Callable devront cependant écrire le code de traitement des exceptions.
Notez également que Callables n’a pas besoin de renvoyer de valeur; vous pouvez simplement déclarer que votre appelable doit retourner Void (avec la majuscule 'V').

33
Thomas Jensen

IMHO, Runnable est un meilleur type à utiliser pour prendre en argument une fonction qui

  • n'a pas de valeur retournée, mais seulement des effets secondaires
  • doit gérer les exceptions, et non les propager

N'oubliez pas que Callable.call() lève une exception. Cela signifie que si vous prenez un objet appelable comme argument, cet objet appelable peut renvoyer n'importe quel type d'exception et vous devez disposer d'un moyen de toutes les gérer de manière correcte. Si vous ne pouvez pas faire cela, il est préférable de laisser l'implémenteur de Callable gérer l'exception à sa guise et de définir l'argument en Runnable pour que cela soit clair.

8
JB Nizet

Cas d'utilisation de Callable: ScheduledExecutorService.scheduleAtFixedRate et scheduleWithFixedDelay n'accepte que Runnable

7
Evgeniy Dorofeev

Je préfère Callables, mais dans les rares cas où vous pourriez avoir besoin de Callable pour être Runnable, vous pouvez facilement implémenter les deux en ajoutant une méthode run() comme celle-ci à votre Callable.

public void run(){
    try{
        call();
    } catch (Exception e){
        e.printStackTrace(); // or however you log errors
    }
}

En Java 8, vous pouvez également créer une interface pour faire la même chose pour vous:

public interface CallableRunnable<T> extends Callable<T>, Runnable {
    default void run(){
        try {
            call();
        } catch (Exception e) {
            e.printStackTrace(); // or however you log errors
        }
    }
}

Ensuite, il vous suffit de changer tout ce qui implements Callable<T> en implements CallableRunnable<T>. Ainsi, vos travaux pourront toujours être appelés par toute méthode nécessitant l'une ou l'autre. Bien sûr, si vous avez besoin d'une gestion d'erreur spécifique, vous pouvez toujours remplacer la méthode run () pour gérer les exceptions émises par votre méthode call(). Vous pouvez même implémenter une méthode pour le faire:

public interface CallableRunnable<T> extends Callable<T>, Runnable {
    default void run(){
        try {
            call();
        } catch (Exception e) {
            handleCallExceptions(e);
        }
    }

    default void handleCallExceptions(Exception e){
        e.printStackTrace();
    }
}

Ensuite, toute gestion d’exception spéciale ne doit implémenter que sa propre méthode handleExceptions(Exception) ... mais vous n’êtes pas obligée de le faire si vous n’en avez pas besoin. Je préfère cela car cela vous permet d'avoir une implémentation qui utilise votre cadre de journalisation, etc.

6
Steve K

Callable et Runnable _ les deux sont similaires et peuvent être utilisés pour implémenter des threads. Si vous implémentez Runnable, vous devez implémenter la méthode run (), mais dans le cas callable, vous devez implémenter la méthode call (), les deux méthodes fonctionnent de manière similaire. méthodes appelables call () ont plus de flexibilité. Il existe quelques différences entre elles. 

Différence entre exécutable et appelable comme ci-dessous-- 

1) La méthode run () de exécutable renvoie void signifie que si vous voulez que votre thread retourne quelque chose que vous pouvez utiliser, vous avez alors non choix avec Runnable run () méthode. Il y a une solution 'Callable', si vous voulez retourner quelque chose sous la forme de objet, alors vous devez utiliser Callable au lieu de Runnable. Les interfaces appelables ont la méthode 'call ()') qui renvoie Object.

Méthode signature - Runnable-> 

public void run(){}

Callable-> 

public Object call(){}

2) Dans le cas de la méthode Runnable run (), si une exception vérifiée survient, vous devez alors doit être géré avec try catch block, mais dans le cas de Callable call () méthode vous peut lever une exception cochée comme ci-dessous 

 public Object call() throws Exception {}

3) Runnable _ provient de l'ancienne version {Java 1.0, mais appelable est entré dans Java 1.5 version avec le framework Executer .

Si vous connaissez bien Executers, vous devriez alors utiliser Callable au lieu de Runnable.

J'espère que tu as compris.

0
Sudhakar Pandey