2016-01-24 13 views
7

Modifica: la mia domanda ha avuto risposta. Per riassumere, ero confuso sull'uso di riferimenti al metodo non statici. Lì l'interfaccia funzionale e il metodo di riferimento hanno un numero diverso di parametri.Uso di doppi punti - differenza tra i riferimenti di metodo statici e non statici

Ciò che ha risposto alla mia domanda è comment e la risposta accettata.


Attualmente sto leggendo il tutorial Java sui metodi di riduzione del flusso (https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html). Lì ho trovato un pezzo di codice che pensavo fosse sbagliato, quindi ho fatto un codice più semplice per essere sicuro.

// 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; 
    } 
} 

La ragione per cui ho pensato che questo non avrebbe funzionato è a causa della linea:

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

Nella documentazione Java per il 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-) si dice che come secondo parametro una funzione che soddisfa è richiesta l'interfaccia funzionale BiConsumer che ha un metodo astratto con due argomenti. Ma Averager.addcount e Averager.combine hanno un solo parametro.

Ho anche verificato con le espressioni lambda:

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

Questo codice funziona anche e come secondo e terzo parametro devo funzioni con due parametri.

Perché esattamente il codice che ho scritto sopra funziona, anche se sono state fornite funzioni con un solo parametro? E perché ci sono messaggi di errore quando cambio sia Averager.addcount e Averager.combine per avere due parametri come questo?

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

Se lo faccio ottengo il seguente messaggio di errore:

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

Si prega di aiutarmi a capire.

+3

l'elemento _corrente_ può essere il primo parametro. Quindi un metodo 'BiConsumer' mi può' (a, b) 'per un metodo' static' o 'a.method (b)' per un metodo di istanza. Nel tuo esempio spezzato; hai passato un metodo ** instance **. –

+2

Vedere anche [Riferimenti del metodo "del tutorial di Oracle"] (http://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html#PageTitle), esp.la sezione "Tipi di riferimenti al metodo". – Holger

risposta

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

Questo va bene. È equivalente a

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

Ricorda ogni metodo non statico ha un parametro nascosto this. In questo caso è (correttamente) vincolante al primo argomento dei callback accumulator e combiner.

E funziona anche con metodi statici, quali:

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

che lo spera più chiaro ciò che sta accadendo.

Ma non è necessario modificare il codice.

Problemi correlati