189 votes

Exécutable avec un paramètre ?

J'ai besoin d'un "Runnable qui accepte un paramètre" bien que je sache qu'un tel runnable n'existe pas vraiment.

Cela peut indiquer un défaut fondamental dans la conception de mon application et/ou un blocage mental dans mon cerveau fatigué. J'espère donc trouver ici quelques conseils sur la façon d'accomplir quelque chose comme ce qui suit, sans violant les principes fondamentaux de l'OO :

  private Runnable mOneShotTask = new Runnable(String str) {
    public void run(String str) {
       someFunc(str);
    }
  };  

Avez-vous une idée de la façon dont on peut réaliser quelque chose comme ce qui précède ?

12 votes

Vous pouvez maintenant utiliser Consumer<T> .

1 votes

J'ai lu les différentes réponses à cette question. Il me semble étrange que personne n'ait dit que vous pouvez ajouter à votre projet les Runnables dont vous avez besoin (avec un, deux, trois ou plusieurs args) en ajoutant simplement une interface appropriée. J'ai créé un gist commenté ici pour ceux qui sont intéressés : gist.github.com/jsfan3/3a66e711fd0fd233c5e4c467184adb7a

0 votes

Ceci n'est PAS un double de "Comment puis-je passer un paramètre à un thread Java". Et la réponse moderne est, comme le dit @Alex78191 : utiliser Consumer<T>

243voto

corsiKa Points 39442

Cela fait presque 9 ans que j'ai posté cette question et, pour être honnête, Java a fait quelques améliorations depuis. Je vais laisser ma réponse originale ci-dessous, mais il n'est pas nécessaire que les gens fassent ce qu'elle contient. Il y a 9 ans, pendant la revue de code, j'aurais demandé pourquoi ils l'ont fait et peut-être approuvé, peut-être pas. Avec les lambdas modernes disponibles, il est irresponsable d'avoir une réponse si fortement votée recommandant une approche désuète (qui, en toute justice, était douteuse au départ...) Dans le Java moderne, cette revue de code serait immédiatement rejetée, et ceci serait suggéré :

void foo(final String str) {
    Thread t = new Thread(() -> someFunc(str));
    t.start();
}

Comme précédemment, les détails comme le traitement de ce fil de manière significative sont laissés comme un exercice pour le lecteur. Mais pour dire les choses crûment, si vous avez peur d'utiliser des lambdas, vous devriez avoir encore plus peur des systèmes multithreads.

Réponse originale, juste parce que :

Vous pouvez déclarer une classe directement dans la méthode

void Foo(String str) {
    class OneShotTask implements Runnable {
        String str;
        OneShotTask(String s) { str = s; }
        public void run() {
            someFunc(str);
        }
    }
    Thread t = new Thread(new OneShotTask(str));
    t.start();
}

0 votes

Merci à tous ! Toutes les solutions proposées vont dans le même sens, mais je ne peux en accepter qu'une seule. Je dois être très fatigué de ne pas être capable de trouver cette solution moi-même. +1 à tous.

20 votes

En fait, la plupart des gens ne savent pas que l'on peut déclarer une classe à l'intérieur d'une méthode. Certains considèrent que c'est un manque de style. Je suppose que c'est une question de goût :)

3 votes

Public interface ResultRunnable<T> { public void run(T result) ; }

50voto

HaoQi Li Points 2200

Vous pourriez le mettre dans une fonction.

String paramStr = "a parameter";
Runnable myRunnable = createRunnable(paramStr);

private Runnable createRunnable(final String paramStr){

    Runnable aRunnable = new Runnable(){
        public void run(){
            someFunc(paramStr);
        }
    };

    return aRunnable;

}

(Lorsque j'ai utilisé ceci, mon paramètre était un ID entier, que j'ai utilisé pour faire un hashmap de ID --> myRunnables. De cette façon, je peux utiliser le hashmap pour poster/supprimer différents objets myRunnable dans un handler).

3 votes

Merci d'avoir partagé le code - j'aime quand les gens font ça au lieu de simplement blablater. Une question : l'approche ci-dessus est-elle acceptable en ce qui concerne les fuites de mémoire ? Toutes les références que vous passez seront correctement éliminées ?

2 votes

@kape123 La réponse est "cela dépend". Tant qu'un Runnable retourné par la méthode existe quelque part, l'objet paramStr ne seront probablement pas éligibles à la collecte des ordures. Il est possible que si l'objet existe mais ne peut plus jamais être exécuté, le JIT (ou même javac) peut décider de le retirer de la portée, mais nous ne devrions pas compter sur de telles optimisations car elles peuvent changer dans le futur.

1 votes

"Merci de partager le code - j'aime quand les gens font ça au lieu de juste blablater." - Quoi ?

34voto

Tommi Rouvali Points 31
theView.post(new Runnable() {
    String str;
    @Override                            
    public void run() {
        par.Log(str);                              
    }
    public Runnable init(String pstr) {
        this.str=pstr;
        return(this);
    }
}.init(str));

Créez la fonction init qui renvoie l'objet lui-même et initialise les paramètres avec lui.

3 votes

Malheureusement vous ne pourrez pas l'assigner à une variable et appeler init()

11voto

ubiquibacon Points 3212

J'utilise la classe suivante qui implémente la fonction Runnable interface. Avec cette classe, vous pouvez facilement créer de nouveaux threads avec des arguments

public abstract class RunnableArg implements Runnable {

    Object[] m_args;

    public RunnableArg() {
    }

    public void run(Object... args) {
        setArgs(args);
        run();
    }

    public void setArgs(Object... args) {
        m_args = args;
    }

    public int getArgCount() {
        return m_args == null ? 0 : m_args.length;
    }

    public Object[] getArgs() {
        return m_args;
    }
}

2 votes

Comment utiliseriez-vous cette classe abstraite pour exécuter un runnable avec un paramètre ?

0 votes

Je préfère utiliser un constructeur avec un ou plusieurs paramètres. public RunnableArg(Object... args) { setArgs(args); } puis décrire la classe locale : class ActionArg extends RunnableArg { public ActionArg(Object... arg) { super(arg); } @Override public void run() { /* getArgs() and process them */ } } et l'utiliser Thread t = new Thread(new ActionArg( %param_object(s)% )); t.start();

10voto

rlibby Points 4061

Vous avez deux options :

  1. Définir une classe nommée. Passez votre paramètre au constructeur de la classe nommée.

  2. Demandez à votre classe anonyme de fermer votre "paramètre". Assurez-vous de le marquer comme final .

0 votes

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X