2014-05-13 32 views
5

我不想有一个正常的lambda实现一个方法,并重新定义它的toString作为一个附加值。我希望lambda表达式只实现toString方法。 我知道我不是很好表达,但我相信你会理解我这个例子。如何在Java 8中将lambda表达式定义为toString?

public class LambdaToStringTest { 

    public interface ToStringInterface { 
     public abstract String toString(); 
    } 

    public static void main(String[] args) { 
     print("TRACE: %s", (ToStringInterface)()->someComputation()); // <<-- ERROR: The target type of this expression must be a functional interface 
    } 

    private static void print(String format, Object... args) { 
     System.out.println(String.format(format, args)); 
    } 

} 

它编译如果我改变方法的名称,但它不覆盖toString,所以打印方法将不会打印什么预期。

这是试图定义一个日志子系统,它仅在需要时(当它真的要打印时)评估lambda,但与非lambda参数兼容。我知道其他方式来实现它,但我想知道为什么我不能这样做,如果有解决方法或我做错了什么,

+0

我不是问这个:http://stackoverflow.com/questions/16544583/can-i-override-tostring-方法的功能接口在jdk8-using-lambdas我只想实现toString。 – aalku

回答

5

简短的回答,你不能。 @FunctionalInterface s不能用于“覆盖”来自Object的方法。

但是,您可以使用虚拟扩展方法实现Formattable。注意:下面的代码是未经测试:

@FunctionalInterface 
public interface ToStringInterface 
    extends Formattable 
{ 
    String asString(); 

    @Override 
    default void formatTo(Formatter formatter, int flags, int width, int precision) 
    { 
     formatter.format("%s", this); 
     // Or maybe even better: 
     formatter.out().append(this.asString()); 
    } 
} 

我提出这个解决方案,因为你正在使用String.format()这使得采用此接口的。

或者你可以定义你自己的接口。或者甚至为这个接口写一个包装,它在.asString()中调用.toString()。选择很多。

+0

我不认为你应该在一个被lambda实现的接口中使用this.toString,因为它会打印无用的信息。 – aalku

+1

嗯,这是你的选择,我不能说更多;)或者也许lambdas只是不适合你想要做的。无论如何,你有我的解决方案。 – fge

+1

看起来你很困惑自己。在最后一行,它应该是'this.asString()'而不是'this.toString()',因为这就是你的答案的全部要点,lambda将实现'asString'而不是'toString'。 – Holger

2

正如fge所指出的,接口不能从Object类(toString,equals,hashCode)声明方法。

我认为Holger在向你指明供应商方面是正确的,我认为给出你创建一个懒惰的日志评估器的目的,你应该把铸件放在你的打印方法中。为了帮助您的打印调用的语法,你可以创建本质上为您执行抹上实用方法:

private static void print(String format, Object... args) { 
    for (int i = 0; i < args.length; i++) { 
     if (args[i] instanceof Supplier) { 
      args[i] = ((Supplier<?>)args[i]).get(); 
     } 
    } 
    System.out.println(String.format(format, args)); 
} 

private static <T> Supplier<T> supply(Supplier<T> supplier) { 
    return supplier; 
} 

private static class Example { 

    private static String someString() { 
     return "hello"; 
    } 

    private static Boolean someBoolean() { 
     return true; 
    } 
} 

public static void main(String[] args) { 

    print("TRACE: %s; %s; %s", 
     supply(Example::someString), 
     supply(Example::someBoolean), 
     "extra"); 
} 
+0

施法者方法'supply'是一个好主意,但我可能想从实现Supplier的对象中打印toString,所以我最好使用自定义接口。 – aalku

1

函需要很快知道自己的类型,这意味着你有一吨的铸件ToStringInterface,如果你试图保持太接近你的原始想法。您可以调用静态方法来代替演员表。

static Object asString(Supplier<String> string){ 
    return new Object(){ 
     public String toString(){ 
      return string.get(); 
     } 
    }; 
}    

public static void main(String[] args) { 
    print("TRACE: %s", asString(()->someComputation())); 
} 

老实说,虽然,霍尔格的评论是我会做什么 -

void print(String pattern, Supplier<?>... args); 
相关问题