2015-03-06 11 views
5

Ich versuche, die generische Typ Informationen aus dem Rückgabetyp eines Lambda-Ausdruck über einige höherrangige Funktionen in Java 8 zu erhalten. Ich habe meinen tatsächlichen Code zu diesem Test vereinfacht Fall. Das Problem ist nicht, was ich erwarte den Code genau zu tun, aber ich erwarte nicht die generische Art (en) R als java.lang.String abgeleitet werden und durch die Funktionsaufrufe durchgeführt.Java 8 - Generieren Rückgabetyp mit Lambdas

import java.util.function.Function; 

public class AdamTest { 

    public final static void main(final String args[]) { 
     final AdamTest adamTest = new AdamTest(); 

     final String s = adamTest.thing2(7).apply(i -> i.toString()); 
     System.out.println(s); 
    } 


    private <R> R fn1(final Function<Integer, R> op) { 
     return op.apply(10); 
    } 

    private <R> Function<Function<Integer, R>, R> thing2(final Integer val) { 
     return fn1(i -> new Function<Function<Integer, R>, R>() { 
       @Override 
       public R apply(Function<Integer, R> op) { 
        return op.apply(val * i); 
       } 
      } 
     ); 
    } 
} 

Im Moment kompiliert dieser Code nicht wegen dieser Zeile final String s = adamTest.thing2(7).apply(i -> i.toString());. Ich denke, dass ich mit meinen Typgrenzen etwas Unverständliches habe, da der Compiler nicht in der Lage ist, den Rückgabetyp von thing2(7).apply abzuleiten und Object statt String, auf den ich gehofft hatte, zu erhalten.

Wie erhalte ich die generische Typ Grenzen richtig, so dass der korrekte Rückgabetyp heißt java.lang.String wird durch den Compiler zu entnehmen?

+0

Können Sie den Fehler hinzufügen, den Sie bekommen? –

+1

Der Compiler "bewertet" den Ausdruck von links nach rechts; Das Problem tritt bei 'adamTest.thing2 (7)' auf. Der Compiler betrachtet die '.apply' nicht, um den Typ herauszufinden, und ohne das ist es nicht möglich. –

+0

Was versuchst du genau zu machen? Das ist völlig unklar. – fge

Antwort

5

Wie bereits gesagt, werden diese Aussagen von links nach rechts ausgewertet.

Um den Compiler zu zwingen, den richtigen Typ zu verwenden, können Sie einfach schreiben als

final String s = adamTest.<String>thing2(7).apply(String::valueOf); 

EDIT: Richtet sich nach den Anmerkungen kann die Lambda-Ausdruck durch ein Verfahren Bezug ersetzt werden (sieht Reiniger).

+0

Sie können den Methodenaufruf auch durch i.toString() durch eine Methodenreferenz ersetzen. – buftlica

+0

@MatkoMedenjak Leider kann das nicht getan werden. Die Klasse 'Integer' definiert zwei Methoden namens' toString': eine statische Methode ['Integer.toString (int)'] (http://docs.oracle.com/javase/8/docs/api/java/lang/ Integer.html # toString-int-) und eine nicht-statische Methode ['Integer.toString()'] (http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html # toString--). Der Compiler kann nicht zwischen ihnen unterscheiden, wenn der Methodenverweis 'Integer :: toString' verwendet wird. – Seelenvirtuose

+0

Danke @Seelenvirtuose das ist die Lösung Ich kam zu mir selbst, aber irgendwie erwartete ich wirklich bessere Schlüsse aus dem Compiler und so fühlte ich, dass ich einen Fehler in meinen Generika gemacht hatte, weshalb ich die Frage stellte. – adamretter

5

Ich glaube nicht, dass es ohne Abgüsse behoben werden kann (vielleicht weiß jemand besser). Eine Alternative ist, Ihre Aussagen in zwei Linien aufgeteilt:

Function<Function<Integer, String>, String> thing2 = adamTest.thing2(7); 
final String s = thing2.apply(i -> i.toString()); 

Beachten Sie auch, dass thing2 vereinfacht werden kann:

private <R> Function<Function<Integer, R>, R> thing2(final Integer val) { 
    return fn1(i -> (op -> op.apply(val * i))); 
} 
+0

Ich würde es in zwei Aussagen teilen, wenn es einen 'auto' Typ in Java gab, aber da es nicht ist, bevorzuge ich die von @Seelenvirtuose vorgeschlagene generische Besetzung. Ich mag die Vereinfachung aber, danke. – adamretter

-2

Sie müssen zu den Einstellungen Ihres Compilers gehen, um Lambda-Ausdrücke zu aktivieren. Hier ist ein Beispiel mit intellij. Es ist unter Datei> Projektstruktur, dann dieses Dropdown. Hoffe, das hilft!

NVM, nicht genug Ruf. Aber ich gab Details.

+0

Genug Ruf, um Bilder zu posten * – Jahhein

+0

Sie können immer Bild in einigen Bild-Hosting-Server und Link freigeben. Andere Benutzer mit höherer Reputation können Ihren Post bearbeiten, um ein Bild direkt in Ihre Antwort aufzunehmen. – Pshemo

+0

Danke, ich warte nur bis ich 10 Ruf habe. Die Anweisungen sind eher geradlinig, denke ich. Ich sehe viele Fragen über Lambda, und das ist normalerweise die Antwort. – Jahhein

Verwandte Themen