This is a bit hacky and probably slow, but you can easily override toString()
for a lambda using a Proxy
. For non-toString()
calls, simply call method.invoke(lambda, args)
. Then for toString()
, return your desired string representation. Here's a simple static utility method that can add toString()
to any lambda or interface:
private static <T> T addToStringBehavior(
final T t, final Function<T, String> toString) {
final Class<?> aClass = t.getClass();
return (T) Proxy.newProxyInstance(
aClass.getClassLoader(),
aClass.getInterfaces(),
(proxy, method, args) -> {
if (method != null && "toString".equals(method.getName())
&& (args == null || args.length == 0)) {
return toString.apply(t);
}
return method.invoke(t, args);
});
}
You can use it like so:
public static void main(final String[] args) {
final Supplier<String> lambda = () -> "test";
System.out.println(lambda);
final Supplier<String> lambdaWithToString =
addToStringBehavior(lambda, (l) -> l.get());
System.out.println(lambdaWithToString);
System.out.println(lambdaWithToString.get().equals(lambda.get()));
}
The above calls will output the following:
Main$$Lambda$14/0x0000000800066840@65c7a252
test
true
Warning: it's likely that proxying a lambda like this will be much slower than using the lambda directly, so this may not be appropriate to use in production environments where performance is a concern. But for debugging purposes (or in tests which was where I needed it), this solution works great and basically removes the need for duplicate/boilerplate code when you need a lambda to override/implement toString()
.