2017-03-05 1 views
5

Je suis en train de créer une classe de file d'attente (FooQueue) qui a:adoptant et en appliquant une fonction de membre en java

  • un ensemble de membres de la fonction faisant le travail (faire *). Chacun d'eux prend un paramètre, ayant le même type (FooItem).
  • une fonction 'add' qui prend 2 paramètres: l'une des fonctions ci-dessus, et un FooItem. Plus important encore, la fonction d'ajout ne devrait être en mesure de prendre en une fonction membre de la classe FooQueue, plutôt qu'une fonction de membre d'une autre classe avec la signature similaire

Le code compile lorsque le fonctionnons est statique, mais pas lorsque la fonction est non-statique, même si, selon this, la définition du membre de la fonction d'instance est correcte.

Ce qui devrait être changé pour le faire compiler/exécuter?

public class App { 
    public static void main(String[] args) { 
     FooQueue q = new FooQueue(); 
     q.add(FooQueue::dos, new FooItem()); // this compiles 
     q.add(q::do1, new FooItem());   // this does not: 
                // does not consider q::do1 'delegate' 
                // as taking 2 parameters, 
                // with q being the first one 
     FooQueue q2 = new FooQueue2(); 
     q.add(FooQueue2::dos, new FooItem()); // want this to give compiler error 
     q.add(FooQueue2::do1, new FooItem()); // want this to give compiler error 
    } 
} 

public class FooQueue { 
    public static void dos(FooQueue q, FooItem item) { 
     System.out.println("FooQueue:sdo"); 
    } 
    public void do1(FooItem item) { 
     System.out.println("FooQueue:do1"); 
    } 
    public void add(java.util.function.BiConsumer<FooQueue,FooItem> func, FooItem wi) { 
     System.out.println("FooQueue:addWorkItem2"); 
     func.accept(this, wi); 
    } 
} 
public class FooItem { 
} 
public class FooQueue2 { 
    public static void dos(FooQueue2 q2, FooItem item) { 
     System.out.println("FooQueue2:sdo"); 
    } 
    public void do1(FooItem item) { 
     System.out.println("FooQueue2:do1"); 
    } 
} 

Répondre

7

Il n'est pas lié à la méthode statique/non-statique, ni génériques, mais seulement à BiConsumer définition.

BiConsumer nécessite deux paramètres, donc vous avez besoin de lambda qui nécessite deux paramètres et n'en renvoie pas.

Pour corriger cela, utilisez la méthode de référence instance:

FooQueue q = new FooQueue(); 
q.add(FooQueue::do1, new FooItem()); 

Ne confondez pas avec référence méthode statique. FooQueue::do1 est le sucre syntactique pour lambda:

(qInstance, item) -> qInstance.do1(item)); 

Cette approche vous permet d'accepter uniquement les méthodes de FooQueue.

Notez que q:do1 n'est pas compatible avec BiConsumer comme il est converti en:

(item) -> q.do1(item) 

En savoir plus sur Instance method reference


de Exemple complet avec des classes différentes

public class App { 
    public static void main(String[] args) { 
     FooQueue q = new FooQueue(); 
     FooQueue2 q2 = new FooQueue2(); 

     q.add(FooQueue::do1, new FooItem()); 
     // Equals to: 
     q.add((qInstance, item) -> qInstance.do1(item), new FooItem()); 

     // q.add(FooQueue2::do1, new FooItem()); // not compile 
    } 
} 

class FooQueue { 
    void do1(FooItem item) { 
     System.out.println("FooQueue:do1"); 
    } 

    void add(BiConsumer<FooQueue, FooItem> func, FooItem wi) { 
     System.out.println("FooQueue:addWorkItem"); 
     func.accept(this, wi); 
    } 
} 

// class that pretends to be FooQueue 
class FooQueue2 { 
    void do1(FooItem item) { 
     System.out.println("FooQueue2:do1"); 
    } 
} 

class FooItem { 
} 
+3

Remerciez s. Est-il possible d'appliquer FooQueue :: add en n'acceptant que les fonctions membres FooQueue (au moment de la compilation)? Malheureusement, l'utilisation de Consumer va imposer le (s) paramètre (s), mais pas l'appartenance à la classe, qui est le problème racine que je voudrais résoudre. – daniel

+2

@daniel Maintenant, j'ai mieux compris le problème que vous essayez de résoudre. J'ai réécrit ma réponse avec un exemple approprié. Faites-moi savoir si cela vous a été utile. –