2017-01-29 9 views
14

Mam następujący fragment kodumetoda - nieważne referencyjna metoda - nie może być odniesienie do kontekstu statycznego

StringJoiner joiner = new StringJoiner(", "); 
joiner.add("Something"); 
Function<StringJoiner,Integer> lengthFunc = StringJoiner::length; 
Function<CharSequence,StringJoiner> addFunc = StringJoiner::add; 

Ostatni wiersz spowoduje błąd

Error:(54, 53) java: invalid method reference 
    non-static method add(java.lang.CharSequence) cannot be referenced from a static context 

Rozumiem, że metoda ta nie może być używane w sposób statyczny i powinienem mieć coś takiego:

Function<CharSequence,StringJoiner> addFunc = joiner::add; 

zamiast tego. Jednak nie mogę zrozumieć, dlaczego trzecia linia, z StringJoiner::length; jest dla kompilatora java idealnie poprawne. Czy ktoś może wyjaśnić mi, dlaczego tak jest?

+1

Teraz, gdybyś zamiast stosować 'stolarskie :: add' że _would_ być poprawnym' zakresie funkcji ... –

Odpowiedz

10

Ponieważ StringJoiner.length wykonuje zerowe argumentów więc odniesienie sposób ogólnie przyjmuje StringJoiner (arbitralne wystąpienie) i zwraca Integer. Innymi słowy, pierwszy przypisana metoda ref odpowiada:

Function<StringJoiner, Integer> lengthFunc = new Function<StringJoiner, Integer>() { 

     @Override 
     public Integer apply(StringJoiner stringJoiner) { 
      return stringJoiner.length; 
     } 
} 

nazwałbyś to Function następująco:

StringJoiner sj1 = ... // an arbitrary StringJoiner 
int sjLength1 = lengthFunc.apply(sj1); 

w umowie, StringJoiner.add(CharSequence) przyjmuje jeden argument, więc ogólnie Function musiałyby weź (1) arbirary instancji StringJoiner, (2) CharSequence i zwróć StringJoiner.

Zamiast tego można przypisać odniesienie do BiFunction który to robi:

BiFunction<StringJoiner, CharSequence, StringJoiner> addFunc = StringJoiner::add; 

co jest równoważne:

BiFunction<StringJoiner, CharSequence, StringJoiner> addFunc = new BiFunction<StringJoiner, CharSequence, StringJoiner>() { 

     @Override 
     public StringJoiner apply(StringJoiner stringJoiner, CharSequence charSequence) { 
      return stringJoiner.add(charSequence); 
     } 
} 

i zostaną wykorzystane w następujący sposób:

StringJoiner sj1 = ... // an arbitrary StringJoiner 
sj1 = addFunc.apply(sj1, "a"); // no need to re-assign, but just to show the return type 
+1

co robi średnia arbitrażowa instancja StringJoiner?Rozumiem, że jest on traktowany jako typ obiektu, na który zostanie wywołana metoda apply, ale nie jestem pewien jak to działa –

+1

@ ArturSkrzydło Opracowałem, jak są one równoważne przy użyciu czystych anonimowych klas. Przez arbitralne wystąpienie mam na myśli pewną instancję, która byłaby używana w kontekście wywołania do odwołania do metody. – manouti

+1

Dzięki temu jest to teraz dla mnie jasne. Świetny przykład, jak będzie wyglądać implementacja anonimowych funkcji. –

9
Function<StringJoiner,Integer> lengthFunc = StringJoiner::length; 

lengthFunc to funkcja, która pobiera StringJoiner i zwraca wartość Integer. Dlatego każda metoda instancji o numerze StringJoiner, która nie przyjmuje niczego i zwraca wartość Integer, pasuje do tego interfejsu. Instancja, do której zostanie wywołana metoda, będzie wymagać StringJoiner wymaganej przez Function<StringJoiner,Integer>.

Z drugiej strony w

Function<CharSequence,StringJoiner> addFunc = StringJoiner::add 

addFunc jest Function że bierze CharSequence i zwraca StringJoiner. Żadna metoda instancji interfejsu StringJoiner nie pasuje do tego interfejsu, ponieważ ta funkcja nie ma instancji wejściowej StringJoiner, aby zastosować metodę add.

będzie potrzebował BiFunction dopasować podpis StringJoiner::add:

BiFunction<StringJoiner,CharSequence,StringJoiner> addFunc = StringJoiner::add; 
+2

Zostało to wyjaśnione bardzo dobrze. – CKing

Powiązane problemy