2016-01-24 9 views
7

Bearbeiten: Meine Frage wurde hier beantwortet. Zusammenfassend war ich verwirrt über die Verwendung von nicht-statischen Methodenreferenzen. Dort haben die funktionale Schnittstelle und die referenzierte Methode eine unterschiedliche Anzahl von Parametern.Verwendung von doppelten Doppelpunkten - Unterschied zwischen statischen und nicht-statischen Methodenreferenzen

Was beantwortet meine Frage ist die comment und die angenommene Antwort.


ich zur Zeit das Lesen der Java Tutorial über Stream-Reduktionsmethoden (https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html). Dort habe ich einen Code gefunden, den ich für falsch gehalten habe, also habe ich einen einfacheren Code erstellt, um sicherzugehen.

// B.java file 
import java.util.*; 

public class B 
{ 
    public static void main(String[] args) 
    { 
    List<Integer> zahlen = new LinkedList<Integer>(); 
    zahlen.add(1); 
    zahlen.add(2); 
    zahlen.add(3); 
    Averager averageCollect = zahlen.stream() 
     .collect(Averager::new, Averager::addcount, Averager::combine); 
    System.out.println(averageCollect.average()); 
    } 
} 

// Averager.java from the official Java tutorial 
public class Averager 
{ 
    private int total = 0; 
    private int count = 0; 

    public double average() { 
     return count > 0 ? ((double) total)/count : 0; 
    } 

    public void addcount(int i) { total += i; count++;} 
    public void combine(Averager other) { 
     total += other.total; 
     count += other.count; 
    } 
} 

Der Grund, warum ich dachte, dies wäre, weil die Linie nicht:

Averager averageCollect = zahlen.stream() 
    .collect(Averager::new, Averager::addcount, Averager::combine); 

In der Java-Dokumentation für die Stream.collect (https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#collect-java.util.function.Supplier-java.util.function.BiConsumer-java.util.function.BiConsumer-) heißt es, dass als zweiten Parameter eine Funktion, die übereinstimmt die funktionale Schnittstelle BiConsumer wird benötigt, die eine abstrakte Methode mit zwei Argumenten hat. Aber Averager.addcount und Averager.combine haben nur einen Parameter.

ich auch mit Lambda-Ausdrücke geprüft:

Averager averageCollect = zahlen.stream() 
    .collect(Averager::new, (a,b) -> a.addcount(b), (a,b) -> a.combine(b)); 

Dieser Code funktioniert auch und als zweiten und dritten Parameter Ich habe Funktionen mit zwei Parametern.

Warum genau funktioniert der Code, den ich oben geschrieben habe, obwohl Funktionen mit nur einem Parameter angegeben wurden? Und warum gibt es Fehlermeldungen, wenn ich sowohl Averager.addcount als auch Averager.combine ändere, um so zwei Parameter zu haben?

public void addcount(Averager one, Integer i) 
public void combine(Averager one, Averager other) 

Wenn ich tun, dass ich die folgende Fehlermeldung erhalten:

B.java:12: error: no suitable method found for collect(Averager::new,Averager::addcount,Averager::combine) 
     .collect(Averager::new, Averager::addcount, Averager::combine); 
    ^
    method Stream.collect(Supplier,BiConsumer,BiConsumer) is not applicable 
     (cannot infer type-variable(s) R#1 
     (argument mismatch; invalid method reference 
      cannot find symbol 
      symbol: method addcount(R#1,Integer) 
      location: class Averager)) 
    method Stream.collect(Collector) is not applicable 
     (cannot infer type-variable(s) R#2,A 
     (actual and formal argument lists differ in length)) 
    where R#1,T,R#2,A are type-variables: 
    R#1 extends Object declared in method collect(Supplier,BiConsumer,BiConsumer) 
    T extends Object declared in interface Stream 
    R#2 extends Object declared in method collect(Collector) 
    A extends Object declared in method collect(Collector) 
1 error

Bitte helfen Sie mir zu verstehen.

+3

Das _current item_ kann der erste Parameter sein. Also kann ein 'BiConsumer' mir' Methode (a, b) 'für eine' statische' Methode oder 'a.Methode (b)' für eine Instanzmethode geben. In deinem gebrochenen Beispiel; Sie haben eine ** Instanz ** -Methode bestanden. –

+2

Siehe auch [Oracle Tutorial "Methodenreferenzen"] (http://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html#PageTitle), insb.der Abschnitt "Arten von Methodenreferenzen". – Holger

Antwort

6
Averager averageCollect = zahlen.stream() 
    .collect(Averager::new, Averager::addcount, Averager::combine); 

Das ist in Ordnung. Es entspricht

Averager averageCollect = zahlen.stream() 
    .collect(() -> new Averager(), 
      (myAverager, n) -> myAverager.addcount(n), 
      (dst, src) -> dst.combine(src)) 

Denken Sie daran, jede nicht-statische Methode einen versteckten this Parameter hat. In diesem Fall bindet es dies (richtig) an das erste Argument der Callbacks accumulator und combiner.

Es wird auch mit statischen Methoden arbeiten wie:

public static void addcount(Averager a, int i) { 
    a.total += i; 
    a.count++; 
} 
public static void combine(Averager dst, Averager src) { 
    dst.total += src.total; 
    dst.count += src.count; 
} 

die hoffentlich macht es klarer, was geschieht.

Aber es ist nicht notwendig, den Code zu ändern.

Verwandte Themen