Java vararg pass lambda and values

I'm trying to unite lambdas and simple values in varag.

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

ERROR: method Log cannot be applied to given types; REQUIERED String,Object[] found: String,String,int,()->"aaa",()->111 REASON: varargs mismatch; Object is not a functional interface

Is it possible to pass both lambdas and values to vararg?


The problem is in the error message

Object is not a functional interface

You can only create a lambda for a functional interfaces (one with exactly one abstract method) Object is not an interface and it doesn't have any abstract methods so you can't create a lambda of this type. What you can do is

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

This way the compiler knows what sort of lambda you intended to implement.

By comparison you could write the following and this would behave differently in your method.

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

For the compiler there is no way to tell what type of functional interface is used when you delcare them (unlike the first one, since you defined that in the variableType)

So a fix would be casting the supplier. Eg (not tested)

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

Hope this points in the right direction.


The problem is that Object is not a @FunctionalInterface . That being said you can pass a simple anonymous instance like this:

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

This method can be used if you don't want to use unchecked casts which will result in a compiler warning.

If you still want to cast your lambda it can be done this way:

Log( "%s %d %s %d", "bbb", 222, (Supplier<String>) () -> "aaa");
链接地址: http://www.djcxy.com/p/78958.html

上一篇: Scala - 使隐式值类在另一个作用域中可用

下一篇: Java可变参数传递lambda和值