2014-05-21 13 views
7

Próbuję użyć odwołań metod do przechwytywania wywołań metod i trafiam w pewne ograniczenia. Działa to dobrze:Ograniczenia odwołań metod statycznych w języku Java 8

<T> void capture(Function<T, ?> in) { 
} 

private interface Foo { 
    String getBar(); 
} 

capture(Foo::getBar); 

Ale jeśli zmienić podpis Foo.setBar do czegoś takiego:

private interface Foo { 
    void setBar(String bar); 
} 

capture(Foo::setBar); 

pojawia się błąd:

Cannot make a static reference to the non-static method setBar(String) from the type MyTest.Foo

nie jest jasne dla mnie jakie jest ograniczenie. Idealnie chciałbym użyć referencji metod do przechwytywania wywołań na standardowym ustawiaczu. Czy jest jakiś sposób to zrobić?

+0

Czy to nawet Java? A może ta składnia jest nowa w Java 8? –

+0

Czy możesz wysłać błąd? –

+0

@AnubianNoob To rzeczywiście odwołuje się do metody Java8s itp. ... – Sinkingpoint

Odpowiedz

12

Istnieją dwa problemy:

  • używasz Function, który ma coś do powrotu. setBar nic nie zwraca.
  • Function zajmuje tylko jedno wejście, ale masz dwa wejść: the Foo chcesz zadzwonić setBar on-line, a String argumentem chcesz przejść do setBar.

Jeżeli zmienisz używać BiConsumer zamiast (który ma typ void zwrotny i dwa wejścia) to działa dobrze:

static <T, U> void capture(BiConsumer<T, U> in) { 
} 

Można przeciążać metody capture mieć zarówno Podpisy:

static <T, U> void capture(BiConsumer<T, U> in) { } 
static <T> void capture(Function<T, ?> in) { } 

, a następnie użyj obu odwołań metod:

capture(Foo::setBar); 
capture(Foo::getBar); 
+0

Niezwykle szybka odpowiedź. Dzięki! Gdy tylko pozwoli mi to zaakceptuję twoją odpowiedź. –

+0

tak - dziękuję –

+1

@JoshStone: Cieszę się, że to ma sens. Nie zrobiłem nic z materiałem Java 8 lub nie napisałem o nim, więc zajmie trochę czasu, aby udoskonalić sposób wyjaśnienia. Daj mi znać, jeśli jest coś, co chciałbyś, abym rozwinął. –

3

Expose składni Referencyjna metoda cukier, powinieneś zobaczyć, że

Foo::getBar 

jest równa

(Foo)foo -> foo.getBar() 

która Function <Foo, String>

Ale

Foo::setBar 

jest t jego kontekst funkcja dwóch zmiennych (foo a niektóre String str), więc to nie jest funkcją jednej zmiennej (Function)

dla bardziej wygodnej odpowiedzi powinieneś zobaczyć, gdzie method references są dozwolone: ​​

  1. odniesienie do metody statycznej (nie tym przypadku w ogóle)
  2. odniesienie do sposobu przykład określonego obiektu (nie w tym przypadku w ogóle)
  3. odniesienie do sposobu wystąpienie niepożądanego przedmiotu określonego typ e (w tym przypadku)

    W powyższej instrukcji znajduje się przykład, który jest prawie taki sam jak w twoim przypadku. I mówi się, że równoznaczne, N byłaby przy dwa parametrów (w tym przypadku Foo i String), który nie jest Function

  4. Odniesienie do konstruktora (nie tym przypadku w ogóle)

8

Foo::getBar odpowiada funkcji, która pobiera Foo (obiekt docelowy) i zwraca wartość String. Interfejs Function<Foo, String> może być używany do reprezentowania takiej funkcji.

Z drugiej strony, Foo::setBar odpowiada funkcji, która pobiera dwa argumenty, Foo (obiekt docelowy) i String (pierwszy parametr). Pasujący interfejs to BiConsumer<Foo, String>. To znaczy, że potrzebujesz przeciążenia do: BiConsumer:

<T, U> void capture(BiConsumer<T, U> setter) { 
    // ... 
}