2013-01-22 5 views
13

Ich benutze eine Reihe von Bibliotheken in Clojure, die Funktionen höherer Ordnung erzeugen, die der "clojure.lang.IFn" Schnittstelle entsprechen.Kann ich Clojure-Funktionen als Lambdas in Java 8 verwenden?

Es hat mehrere Arity-Überlastungen, i.e. die Schnittstelle sieht ungefähr so ​​aus:

public interface IFn extends Callable, Runnable{ 
    public Object invoke() ; 
    public Object invoke(Object arg1) ; 
    public Object invoke(Object arg1, Object arg2) ; 
    public Object invoke(Object arg1, Object arg2, Object arg3) ; 
    .... etc. 
    public Object applyTo(ISeq arglist) ; 
} 

Kann ich Objekte dieses Typs in Java direkt 8 als aufrufbare Lambda-Funktionen benutzen?

+5

IIRC, Java 8 lässt Sie Lambdafunktionen nicht auf neue Weise "aufrufen"; Es bietet nur neue Möglichkeiten für _create_ Lambda-Funktionen, bei denen es sich um Einzelfunktionsschnittstellen handeln muss. –

Antwort

7

Was meinen Sie, Objekte dieses Typs als aufrufbare Lambdas verwenden?

In sehr einfach Fällen Java 8 lambdas kann für anonyme Klassen für bestimmte Arten von Schnittstellen, nämlich funktionalen Schnittstellen[1] als syntaktischer Zucker + einige Typinferenz gedacht werden:

Die Schnittstelle ActionListener, oben verwendet, hat nur eine Methode. Viele gemeinsame Callback-Schnittstellen haben diese Eigenschaft, wie zum Beispiel Runnable und Comparator. Wir geben allen Schnittstellen, die nur eine Methode haben, einen Namen: funktionale Schnittstellen.

Bemerkung: lambdas sind wirklich nicht nur ein Zucker; intern werden sie anders als anonyme Klassen implementiert, und es gibt auch einige semantische Unterschiede; Weitere Informationen hierzu finden Sie unter this excellent answer auf ProgrammersExchange. Dies ist jedoch im Zusammenhang mit dieser Frage und Antwort nicht wirklich wichtig.

Überall dort, wo ein Wert einer funktionalen Schnittstelle erwartet wird (Methodenargument, lokale Variable, Felddeklaration usw.), kann kurze Syntax verwendet werden, um eine anonyme Klasse zu erstellen, die diese Methode implementiert, dh ein Lambda Ausdruck:

Runnable r =() -> { 
    System.out.println("Hi"); 
}; 
// Equivalent to 
Runnable r = new Runnable() { 
    public void run() { 
     System.out.println("Hi"); 
    } 
}; 

public interface Function<F, T> { 
    T call(F arg); 
} 

Function<String, char[]> c = s -> ("<" + s + ">").toCharArray(); 
// Equivalent to 
Function<String, char[]> c = new Function<>() { 
    public char[] call(String s) { 
     return ("<" + s + ">").toCharArray(); 
    } 
}; 

So kann Ihre Frage nur in folgenden Weise interpretiert wird: ist es möglich, Objekte des Typs zu schaffen IFn Java 8 Lambda-Syntax?

Die Antwort ist nein. Lambda-Syntax ist nur mit funktionalen Schnittstellen möglich. clojure.lang.IFn keine funktionale Schnittstelle ist, weil es viel mehr als nur einzelne Methode enthält, so wird es nicht möglich sein, so etwas wie

IFn f = (String s) -> s.toLowerCase(); 
+5

Die Idee, dass Java 8 Lambdas syntaktischer Zucker auf anonymen inneren Klassen sind, ist ein Meme, das einfach nicht verschwinden wird. Siehe die Antworten auf diese Frage: http://programmers.stackexchange.com/questions/177879/type-inference-in-java-8, um zu erklären, warum es falsch ist. Dies wird eindeutig eine häufige Frage sein; Ich werde eine Antwort auf die Lambda FAQ geben (http://www.lambdafaq.org) –

+0

@MauriceNaftalin, danke, ich hätte lambda spec gründlicher lesen sollen. Ich füge eine Notiz darüber hinzu. –

+1

Meine Interpretation der Frage ist das Gegenteil von dem, was Sie hier haben.Ich denke, er möchte Clojure-Funktionen, die Objekte sind, die die Schnittstelle IFn implementieren, an Java-Funktionen übergeben, die ein Objekt erwarten, das ihre einzige Funktionsschnittstelle implementiert. Die Antwort, die ich vermute, ist nein. – bfabry

2

Nein zu tun, es scheint, dass Sie nicht clojure funktioniert, als ob sie gelten auch Java verwenden können Lambda. Clojures IFn entspricht nicht den definierten "Lambda" -Funktionsschnittstellen von Java.