How to correctly determine that an object is a lambda?
JavaLambdaJava 8Java Problem Overview
I see that the class of a lambda is isSynthetic() && !isLocalOrAnonymousClass()
, but I presume that the same may be true for proxy classes.
Of course, I could check that getDeclaredMethods().length == 1
and apply regexp
to the class name.
However I want to know if there is a more elegant and robust option to find out if a given object is a lambda.
Java Solutions
Solution 1 - Java
There is no official way to do this, by design. Lambdas are part of the language; and are integrated into the type system through functional interfaces. There should be no need to distinguish a Runnable
that began life as a lambda, a named class, or an inner class -- they're all Runnables. If you think you have to "deal with lambda" by taking apart the class file, you're almost certainly doing something wrong!
Solution 2 - Java
If you know the lambda extends Serializable
you could check the synthetic writeReplace
method that is generated returns a SerializedLambda
as shown below.
import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.function.Function;
public class IsLambdaExample
{
public static void main( String[] args )
{
System.out.println(
"Is anonymous inner class a lambda: "+isLambda(
new SerialisableFunction<Object,Object>(){ public Object apply( Object o ){ return null; } }
)
);
System.out.println( "Is lambda a lambda: "+isLambda( (SerialisableFunction<Object,Object>)o -> null ) );
System.out.println(
"Is proxy instance a lambda: "+isLambda(
(SerialisableFunction)Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(),
new Class[]{ SerialisableFunction.class },
new InvocationHandler()
{
@Override
public Object invoke( Object proxy, Method method, Object[] args )
{
return null;
}
private SerializedLambda writeReplace()
{
return new SerializedLambda( InvocationHandler.class, "", "", "", 0, "", "", "", "", new Object[]{} );
}
}
)
)
);
}
public static <T extends Function<?,?> & Serializable> Boolean isLambda( T potentialLambda )
{
try{
Class<?> potentialLambdaClass = potentialLambda.getClass();
if( !potentialLambdaClass.isSynthetic() ){
return false;
}
Method writeReplace = potentialLambdaClass.getDeclaredMethod("writeReplace");
writeReplace.setAccessible(true);
Object writeReplaceObject = writeReplace.invoke(potentialLambda);
return writeReplaceObject != null && SerializedLambda.class.isAssignableFrom( writeReplaceObject.getClass() );
}
catch( NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored ){
return false;
}
}
interface SerialisableFunction<T,U> extends Function<T,U>, Serializable {}
}
Solution 3 - Java
public static boolean isLambda(Object obj) {
return obj.getClass().toString().contains("$$Lambda$");
}