java 如何正确判断一个对象是lambda?

sc4hvdpw  于 2023-01-24  发布在  Java
关注(0)|答案(4)|浏览(266)

我看到lambda的类是isSynthetic() && !isLocalOrAnonymousClass(),但我假设代理类也是如此。
当然,我可以检查getDeclaredMethods().length == 1并将regexp应用于类名。
然而,我想知道是否有一个更优雅和健壮的选项来确定给定的对象是否是lambda。

qlfbtfca

qlfbtfca1#

没有官方的方法可以通过设计来做到这一点。lambda是语言的一部分;并且通过函数接口集成到类型系统中。应该没有必要区分Runnable最初是作为lambda、命名类还是内部类出现的--它们都是Runnables。如果您认为必须通过分解类文件来“处理lambda”,那么您几乎肯定做错了什么!

abithluo

abithluo2#

如果您知道lambda扩展Serializable,则可以检查生成的合成writeReplace方法是否返回SerializedLambda,如下所示。

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 {}
}
i86rm4rw

i86rm4rw3#

检查Runnable-或任何其他函数接口-是否已经被Lambda实现的一个简单方法是检查类是否是合成的,而接口的函数不是:

Class clz = suspectedObject.getClass();
var isLambda = clz.isSynthetic() && !clz.getDeclaredMethod("run").isSynthetic();

注意,这也会检测函数引用(this::run)--我不认为有办法区分这种形式和匿名lambda。
我想使用这个方法以一种更好的方式记录对象的类型-我的框架有时记录所提供的接口实现的名称,以让用户知道他们的代码的哪一部分有问题,而lambda的toString()几乎是无用的。我并不是说我已经想出了一种有用的方式来表示“您应该查看这个特定的lambda,而不是您的类中的其他几十个lambda中的任何一个。

pkwftd7m

pkwftd7m4#

public static boolean isLambda(Object obj) {
    return obj.getClass().toString().contains("$$Lambda$");
}

相关问题