2017-03-05 40 views
5

Próbuję utworzyć klasę kolejki pracy (FooQueue), która posiada:przejściu i wykonywania funkcji członka w java

  • zestaw członków funkcyjnych wykonywania pracy (do *). Każdy z nich przyjmuje jeden parametr o tym samym typie (FooItem).
  • funkcja "dodaj", która przyjmuje 2 parametry: jedną z powyższych funkcji i element FooItem. Co najważniejsze, funkcja dodawania powinna mieć możliwość przyjęcia funkcji składowej klasy FooQueue, a nie funkcji składowej innej klasy o podobnym sygnaturze:

Kod kompiluje się, gdy funkcja do jest statyczna, ale nie wtedy, gdy funkcja jest niestatyczna, nawet zgodnie z this definicja elementu funkcji instancji jest poprawna.

Co należy zmienić, aby skompilować/uruchomić?

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"); 
    } 
} 

Odpowiedz

7

To nie jest związane z metodą statyczną/non-statycznej, ani leków generycznych, ale tylko do BiConsumer definicji.

BiConsumer wymaga dwóch parametrów, więc potrzebujesz lambda, która wymaga dwóch parametrów i nie zwraca żadnych.

Aby to naprawić, należy użyć metody instancji odwołanie:

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

Nie należy mylić go ze statycznej metody odniesienia. FooQueue::do1 jest cukier syntatic dla lambda:

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

Takie podejście pozwala zaakceptować tylko metody z FooQueue.

Zauważ, że q:do1 nie jest kompatybilny z BiConsumer jak to przekształca się:

(item) -> q.do1(item) 

Przeczytaj więcej o Instance method reference


Pełny przykład z różnych klas

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

dziękuję s. Czy istnieje sposób na wymuszenie funkcji FooQueue :: add przyjmujących tylko funkcje członkowskie FooQueue (podczas kompilacji)? Niestety, użycie Consumer wymusi parametr (y), ale nie członkostwo w klasie, co jest głównym problemem, który chciałbym rozwiązać. – daniel

+2

@daniel Teraz lepiej zrozumiałem problem, który próbujesz rozwiązać. Przepisałem odpowiedź na odpowiedni przykład. Jeśli to pomoże, to daj mi znać. –