2016-04-03 10 views
12

Viele lambdas für die Function Schnittstelle in FormConverting Verbraucher in die Funktionen

t -> { 
    // do something to t 
    return t; 
} 

ich dies tun, so oft, dass ich eine Methode für sie so geschrieben haben.

static <T> Function<T, T> consumeThenReturn(Consumer<T> consumer) { 
    return t -> { 
     consumer.accept(t); 
     return t; 
    }; 
} 

Dies ermöglicht es mir, wie diese wirklich schöne Dinge zu tun:

IntStream.rangeClosed('A', 'Z') 
     .mapToObj(a -> (char) a) 
     .collect(Collectors.collectingAndThen(Collectors.toList(), consumeThenReturn(Collections::shuffle))) 
     .forEach(System.out::print); 

Gibt es eine andere Art und Weise Umwandlungen wie dies zu tun, ohne auf meine eigene Methode zu verlassen? Gibt es etwas in den neuen APIs, die ich verpasst habe, was meine Methode überflüssig macht?

+4

Ich glaube nicht, dass es ist: werfen Sie einen Blick auf 'Collectors.toList()' Code zum Beispiel, es tut '(links, rechts) -> {left.addAll (rechts); Rückkehr nach links; }, '. Das ist das Problem von Methoden, die ihr Argument mutieren ... (Randbemerkung: Sie können 'UnaryOperator ' anstelle von 'Funktion ') haben. – Tunaki

+3

Ich würde Ihre Funktion in ['tee'] umbenennen (https: //en.wikipedia .org/wiki/Tee_ (Befehl)). – dasblinkenlight

+0

Alles wurde schon gesagt, aber ich arbeite an etwas, das das schon macht. https://github.com/TouK/ThrowingFunction/ jeder Eingang wird geschätzt –

Antwort

6

Es gibt viele potenziell nützliche Methoden, die zu den Schnittstellen Function, Consumer und Supplier hinzugefügt werden können. Sie geben ein gutes Beispiel (Umwandlung einer Consumer in eine Function), aber es gibt viele andere mögliche Konvertierungen oder Dienstprogramme, die hinzugefügt werden könnten. Zum Beispiel unter Verwendung eines Function als Consumer (durch Ignorieren des Rückgabewerts) oder als Supplier (durch Bereitstellen eines Eingabewerts). Oder konvertieren Sie einen BiFunction in einen Function, indem Sie einen der beiden Werte angeben. All dies kann natürlich manuell in Code erfolgen oder über Utility-Funktionen bereitgestellt werden, wie Sie gezeigt haben, aber es wäre wohl von Nutzen, standardisierte Mechanismen in der API zu haben, wie sie in vielen anderen Sprachen existieren.

Es ist Spekulation meinerseits, aber ich würde vermuten, dass dies den Wunsch der Sprachdesigner widerspiegelt, die API so sauber wie möglich zu lassen. Ich bin jedoch fasziniert von dem Kontrast (als Beispiel) zu den sehr reichen Comparator Dienstprogrammen, die von der Sprache bereitgestellt werden, um Befehle umzukehren, nach mehreren Kriterien zu vergleichen, mit Nullwerten usw. umzugehen. Diese könnten auch leicht dem Benutzer überlassen werden aber wurden von der API geliefert. Es würde mich interessieren, von einem der Sprachdesigner zu hören, warum die Ansätze zu diesen Schnittstellen so inkonsistent erscheinen.

+0

Ausgezeichneter Punkt über die neuen Sachen für 'Comparator'.Sie können eine 'Funktion' bereits als' Consumer' behandeln, indem Sie einfach 'function :: apply' übergeben. Ich denke, das Ignorieren des Rückgabewerts ist etwas weniger merkwürdig als das Zurückgeben des ersten Arguments, wenn es keinen Rückgabewert gibt. –

+3

Ein anderes geklingeltes Beispiel wäre 'CompletableFuture', das letzte Mal, als ich es in der Nähe von 60 Methoden überprüft habe ... –

+1

Sie müssen bedenken, dass Comparator eine alte Schnittstelle ist, die sich im Laufe der Zeit entwickelt hat. Das java8 otoh ist das erste Release mit funktionalen Schnittstellen. – the8472

0

Apache Commons Sammlungen 4.x hat, was Sie suchen, denke ich. Ihre Äquivalente für Function und Consumer ist Transformer und Closure ist, und es bietet eine Möglichkeit, sie ClosureTransformer

Verwendung zusammen es trivial ist zwischen äquivalenten funktionellen Typen umzuwandeln, indem das SAM aus einem Aufruf und an den anderen zugewiesen wird. Dass sie alle zusammen, können Sie mit einem Java 8 Function auf diese Weise am Ende:

Consumer<String> c = System.out::println; 
Function<String,String> f = ClosureTransformer.closureTransformer(c::accept)::transform; 

c::accept wandelt die Java 8 Consumer in ein äquivalentes Apache Commons 4 Closure und die endgültige ::transform wandelt der Apache Commons 4 Transformer zu ein gleichwertiges Java 8 Function.