2016-10-17 1 views
5

Je suis en train d'unir lambdas et des valeurs simples dans varag.Java vararg passer lambda et les valeurs

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 

ERREUR: le protocole ne peut pas être appliqué à des types donnés; REQUIERED Chaîne, Object [] trouvé: String, String, int,() -> "aaa",() -> 111 RAISON: varargs mismatch; L'objet n'est pas une interface fonctionnelle

Est-il possible de transmettre à la fois lambdas et valeurs à vararg?

+0

, (Object)() -> 111); ' –

+1

@ Timothy Truckle Cette solution donnera toujours une erreur de compilation. – n247s

+0

J'ai essayé (Object), mais ça n'aide pas. La coulée (fournisseur) a résolu le problème. – Dmitry

Répondre

4

Le problème est dans le message d'erreur

Object is not a functional interface

Vous ne pouvez créer un lambda pour une interface fonctionnelle (une avec exactement une méthode abstraite) objet n'est pas une interface et il n'a pas toutes les méthodes abstraites donc vous ne pouvez pas créer un lambda de ce type. Ce que vous pouvez faire est

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

De cette façon, le compilateur sait quel type de lambda vous souhaitez implémenter. En comparaison, vous pourriez écrire ce qui suit et cela se comporterait différemment dans votre méthode.

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

Le problème est que Object est pas un @FunctionalInterface. Cela étant dit, vous pouvez passer une instance anonyme simple, comme celui-ci:

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

Cette méthode peut être utilisée si vous ne souhaitez pas utiliser non vérifiées moulages qui se traduira par un avertissement du compilateur.

Si vous voulez toujours jeter votre lambda peut se faire de cette façon:

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

Ma réponse est une alternative à la vôtre. –

+0

@Whomever downvoted: soin d'expliquer? –

+0

Quel est le problème avec ça? Les Lambdas sont des sucres syntaxiques pour les classes internes anonymes annotées avec '@ FunctionalInterface'. –

0

Pour le compilateur il n'y a aucun moyen de dire quel type d'interface fonctionnelle est utilisée lorsque vous les delcare (contrairement à la première un, puisque vous avez défini cela dans le variableType)

Donc, une solution serait de mouler le fournisseur. Par exemple. (non testé)

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

Espérons que cela pointe dans la bonne direction. Varargs doit avoir le même type, essayez ceci: `Log ("% s% d% s% d ", (Objet)" bbb ", (Objet) 222, (Object)() ->" aaa "