Java参数化Method Reference实现静态方法映射批量填充方案问询
解决方案
方案1:反射实现你想要的通用addToMap方法
可以通过LambdaMetafactory将反射获取的静态方法绑定为对应的函数式接口实例,相比每次调用Method.invoke性能损耗极低,实现代码如下:
import java.lang.invoke.*; import java.lang.reflect.Method; import java.util.Map; import java.util.function.Function; import java.util.function.Predicate; public class SymbolRegistry { private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); // 方法名常量,避免拼写错误 private static final String BOOL_METHOD_NAME = "boolMethod"; private static final String CONVERT_METHOD_NAME = "stringToSymbol"; public static Map<Predicate<String>, Function<String, Symbol>> addToMap( Map<Predicate<String>, Function<String, Symbol>> map, Class<? extends Symbol> symbolType ) throws Throwable { // 获取boolMethod静态方法:入参String,返回boolean Method boolMethod = symbolType.getMethod(BOOL_METHOD_NAME, String.class); MethodHandle boolHandle = LOOKUP.unreflect(boolMethod); Predicate<String> predicate = (Predicate<String>) LambdaMetafactory.metafactory( LOOKUP, "test", MethodType.methodType(Predicate.class), MethodType.methodType(boolean.class, Object.class), boolHandle, MethodType.methodType(boolean.class, String.class) ).getTarget().invokeExact(); // 获取stringToSymbol静态方法:入参String,返回Symbol Method convertMethod = symbolType.getMethod(CONVERT_METHOD_NAME, String.class); MethodHandle convertHandle = LOOKUP.unreflect(convertMethod); Function<String, Symbol> function = (Function<String, Symbol>) LambdaMetafactory.metafactory( LOOKUP, "apply", MethodType.methodType(Function.class), MethodType.methodType(Object.class, Object.class), convertHandle, MethodType.methodType(Symbol.class, String.class) ).getTarget().invokeExact(); map.put(predicate, function); return map; } }
注意:该方案依赖方法名固定,若子类方法名修改、参数/返回值不匹配,会在运行期抛出异常,编译期无法检查。
方案2:更推荐的无反射实现(类型安全、性能最优)
完全规避反射风险,只需要给每个子类提前暴露对应的函数式接口实例即可:
- 首先定义通用的处理器载体
public record SymbolHandler(Predicate<String> matcher, Function<String, Symbol> converter) {}
- 每个Symbol子类添加静态常量,比如SymbolA:
public class SymbolA extends Symbol { public static final SymbolHandler HANDLER = new SymbolHandler(SymbolA::boolMethod, SymbolA::stringToSymbol); // 原有逻辑不变 }
- 通用注册方法简化为:
public static Map<Predicate<String>, Function<String, Symbol>> addToMap( Map<Predicate<String>, Function<String, Symbol>> map, SymbolHandler handler ) { map.put(handler.matcher(), handler.converter()); return map; }
注册时直接传入子类的HANDLER常量即可:
addToMap(temp, SymbolA.HANDLER); addToMap(temp, SymbolB.HANDLER); // ...
该方案所有逻辑在编译期就能检查,不存在运行期反射异常,性能和你最初的手写put完全一致。
路由逻辑优化建议
你当前用HashMap存储条目遍历的逻辑有一个问题:HashMap的遍历顺序不固定,如果存在多个Predicate匹配同一个输入字符串的场景,返回结果会不稳定。
更合理的实现是用List<SymbolHandler>存储所有处理器,按优先级排序后遍历,找到第一个匹配的处理器就执行转换,逻辑更可控。
内容的提问来源于stack exchange,提问作者Timothy Egenton
相关产品推荐
相关产品推荐

