2017-05-01 1 views
5

In der folgenden Klasse übergebe ich die Methodenreferenz WordCounterEx::accumulate als zweiten Parameter an die Methode reduce. Die Signatur der Reduce-Methode lautet:Methodenverweis erfüllt nicht den funktionalen Schnittstellenvertrag, sondern kompiliert. Wie ist das möglich?

<U> U reduce(U identity, 
      BiFunction<U, ? super T, U> accumulator, 
      BinaryOperator<U> combiner); 

Der zweite Parameter der Reduce-Methode muss daher das BiFunction-Rezept erfüllen. Aber die übergebene Akkumulationsmethode ist keine BiFunction (sie hat nur einen Parameter). Warum es noch kompilieren?

public class WordCounterEx { 
    private final int counter; 
    private final boolean lastSpace; 

    public WordCounterEx(int counter, boolean lastSpace) { 
     this.counter = counter; 
     this.lastSpace = lastSpace; 
    } 

    public int countWords(Stream<Character> stream) { 
     WordCounterEx wordCounter = stream.reduce(new WordCounterEx(0, true), 
       //HOW CAN THIS WORK? here must come BiFunction - R apply(T t, U u); 
       WordCounterEx::accumulate, 
       WordCounterEx::combine); 
     return wordCounter.counter; 
    } 

    public WordCounterEx accumulate(Character c) { 
     if(Character.isWhitespace(c)) { 
      return lastSpace ? 
        this : 
        new WordCounterEx(counter, true); 
     } else { 
      return lastSpace ? 
        new WordCounterEx(counter+1, false) : 
        this; 
     } 
    } 

    public WordCounterEx combine(WordCounterEx wordCounter) { 
     return new WordCounterEx(counter + wordCounter.counter 
       ,wordCounter.lastSpace /*does not matter*/); 
    } 
} 

Antwort

3

accumulate() ist eine Instanzmethode, und Sie nennen es nach Klassennamen und Methodennamen (nicht durch Beispiel und Methodennamen). Wenn ich also die Methode aufrufen wollte, die Sie mir geben, würde ich normalerweise myEx.accumulate(myCh) tun. So stelle ich zwei Dinge zur Verfügung, die WordCounterEx Instanz und das Zeichen. Daher gilt die Methode als BiFunction<WordCounterEx, ? super Character, WordCounterEx>.

Wenn Sie stattdessen mir zum Beispiel this::accumulate gegeben hatte, das Objekt, das Verfahren rufen würde gegeben haben (this), und es kann nicht mehr als BiFunction verwendet wird (in meinem Eclipse-ich „Das Verfahren reduzieren (U, BiFunction, BinaryOperator) im Typ Stream ist nicht anwendbar für die Argumente (WordCounterEx, this :: accumulate, WordCounterEx :: combine) ").

+2

Beachten Sie, dass in Java 8 könnten Sie this' als Argument übergeben 'haben muss, was perfekt mit der Signatur übereinstimmt: 'public WordCounterEx accumulate (WordCounterEx this, Character c)'. Dies entspricht der Version ohne "this" als Argument, wie in der Frage. –

1

Die WordCounterEx#countWords Methode kann wie folgt neu geschrieben werden:

public int countWordsWithInstance(Stream<Character> stream) { 
    WordCounterEx wordCounter = stream.reduce(new WordCounterEx(0, true), 
      this::accumulate, 
      WordCounterEx::combine); 
    return wordCounter.counter; 
} 

public WordCounterEx accumulate(WordCounterEx wc,Character c) { 
    if(Character.isWhitespace(c)) { 
     return wc.lastSpace ? 
       wc : 
       new WordCounterEx(wc.counter, true); 
    } else { 
     return wc.lastSpace ? 
       new WordCounterEx(wc.counter+1, false) : 
       wc; 
    } 
} 

In diesem Fall wird die accumulate Methode WordCounterEx wc in seiner Signatur

+2

Das ist wahr. Als eine Variante derselben kannst du 'accumulate()' 'static' deklarieren und es als' WordCounterEx :: accumulate' bezeichnen (wie in deiner Frage) (das funktioniert, weil, wie du weißt, 'static' Methoden ohne aufgerufen werden) ein Objekt). –

Verwandte Themen