2016-10-17 10 views
5

Ich versuche, Lambdas und einfache Werte in Varag zu vereinen.Java vararg pass Lambda und Werte

public static void Log(String format, Object ... args) { 
    final Object[] fmt = new Object[ args.length ]; 
     for(int i = 0; i < args.length; i++) 
      fmt[i] = args[i] instanceof Supplier ? 
        ((Supplier) args[i]).get() : 
        args[i]; 
    final String s = String.format(format, fmt); 
    System.err.println(s); 
} 

final Supplier 
    s =() -> "aaa", 
    d =() -> 111; 
Log("%s %d %s %d", "bbb", 222, s, d); // OK, OUTPUT: bbb 222 aaa 111 
Log("%s %d %s %d", "bbb", 222,() -> "aaa",() -> 111); // COMPILE FAIL 

Fehler: Methode Protokoll kann nicht auf bestimmte Typen angewendet werden; REQUIERED String, Object [] gefunden: String, String, int,() -> "aaa",() -> 111 GRUND: varargs mismatch; Objekt ist keine funktionale Schnittstelle

Ist es möglich, beide Lambdas und Werte an Vararg zu übergeben?

+0

varargs müssen denselben Typ haben, also versuchen Sie Folgendes: 'Log ("% s% d% s% d ", (Objekt)" bbb ", (Objekt) 222, (Objekt)() ->" aaa " , (Object)() -> 111); ' –

+1

@ Timothy Truckle Diese Lösung wird immer noch einen Compilerfehler geben. – n247s

+0

Ich habe versucht (Objekt), aber es hilft nicht. (Zulieferer) Casting löste das Problem. – Dmitry

Antwort

4

Das Problem ist in der Fehlermeldung

Object is not a functional interface

Sie nur eine Lambda für eine funktionale Schnittstellen (eines mit genau einer abstrakten Methode) erstellen kann Objekt nicht eine Schnittstelle ist, und es hat keine abstrakten Methoden Sie können also kein Lambda dieses Typs erstellen. Was Sie tun können, ist

Log("%s %d %s %d", "bbb", 222, (Supplier)() -> "aaa", (Supplier)() -> 111); 

Auf diese Weise weiß der Compiler, welche Art von Lambda Sie implementieren wollten.

Zum Vergleich könnten Sie Folgendes schreiben und dies würde sich in Ihrer Methode anders verhalten.

Log("%s %d %s %d", "bbb", 222, (Callable)() -> "aaa", (Callable)() -> 111); 
0

Das Problem ist, dass Object kein @FunctionalInterface ist. Dass gesagt wird Ihnen eine einfache anonyme Instanz wie dies passieren kann:

Log("%s %d %s %d", "bbb", 222, new Supplier<String>() { 
      @Override 
      public String get() { 
       return "aaa"; 
      } 
     }); 

Dieses Verfahren verwendet werden können, wenn Sie nicht markiert Abgüsse verwenden möchten nicht, die in einem Compiler Warnung.

Wenn Sie noch Ihr Lambda werfen kann es auf diese Art und Weise erfolgen:

Log("%s %d %s %d", "bbb", 222, (Supplier<String>)() -> "aaa"); 
+1

Meine Antwort ist eine Alternative zu Ihrer. –

+0

@Whomever downvoted: vorsichtig erklären? –

+0

Was ist das Problem damit? Lambdas sind syntaktische Zucker für anonyme innere Klassen, die mit '@ FunctionalInterface' versehen sind. –

0

Für den Compiler gibt es keine Möglichkeit zu sagen, welche Art von Funktionsschnittstelle verwendet wird, wenn man sie delcare (im Gegensatz zu dem ersten eine, da Sie das in der Variable definiertType)

So eine Lösung würde den Lieferanten werfen. Z.B. (nicht getestet)

Log("%s %d %s %d", "bbb", 222, ((Supplier<String>)() -> "aaa"), ((Suplier<Integer>)() -> 111)); 

Hoffe, das zeigt in die richtige Richtung.