Java能否动态获取方法调用的实参变量名,无需手动传入?
实现动态获取方法实参变量名以简化校验调用
现有代码与痛点
当前校验正数属性的代码需要同时传入变量和变量名字符串,示例如下:
配置类方法
public Configuration setProperty(int someSpecificProperty) { MyAppUtil.requirePositive(someSpecificProperty, "someSpecificProperty"); this.someSpecificProperty = someSpecificProperty; return this; }
工具类校验方法
// MyAppUtil static void requirePositive(int property, String propertyName) { if (property <= 0) { throw new IllegalPropertyException(propertyName, PropertyIssue.NON_POSITIVE); } }
异常定义
public class IllegalPropertyException extends RuntimeException { private static final String FORMAT = "%s value is invalid: should be %s"; public IllegalPropertyException(String propertyName, PropertyIssue propertyIssue) { super(String.format(FORMAT, propertyName, propertyIssue.whatItShouldBeInstead())); } @RequiredArgsConstructor public enum PropertyIssue { NULL("not null"), EMPTY("not empty"), NON_POSITIVE("greater than zero"); private final String whatItShouldBeInstead; String whatItShouldBeInstead() { return whatItShouldBeInstead; } } }
期望简化调用,仅传入变量即可:
public Configuration setSpecificProperty(int someSpecificProperty) { MyAppUtil.requirePositive(someSpecificProperty); this.someSpecificProperty = someSpecificProperty; return this; }
可行实现方案
1. 利用Java反射获取参数名称(Java 8+)
Java 8开始支持通过反射获取方法参数名称,但需编译时开启参数名称保留(添加-parameters编译选项)。
修改MyAppUtil的requirePositive方法:
import java.lang.reflect.Method; import java.lang.reflect.Parameter; // MyAppUtil static void requirePositive(int property) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); // 栈索引2对应调用requirePositive的目标方法 StackTraceElement callerElement = stackTrace[2]; try { Class<?> callerClass = Class.forName(callerElement.getClassName()); Method callerMethod = callerClass.getMethod( callerElement.getMethodName(), int.class ); Parameter parameter = callerMethod.getParameters()[0]; String propertyName = parameter.getName(); if (property <= 0) { throw new IllegalPropertyException(propertyName, PropertyIssue.NON_POSITIVE); } } catch (Exception e) { // 反射失败时降级使用默认名称 throw new IllegalPropertyException("unknown property", PropertyIssue.NON_POSITIVE); } }
注意:该方式对重载方法的处理存在限制,若调用方法有多个同类型参数,需额外逻辑区分;且反射存在一定性能开销,不适合高频调用场景。
2. 使用编译时注解处理器
通过自定义注解和注解处理器,在编译阶段生成包含变量名的校验代码,避免运行时反射开销。
步骤1:定义注解
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.SOURCE) public @interface Positive { }
步骤2:实现注解处理器
编写注解处理器,扫描带有@Positive的参数,自动生成包含变量名的校验逻辑(可借助Google Auto等代码生成框架简化开发)。
步骤3:简化调用
public Configuration setSpecificProperty(@Positive int someSpecificProperty) { MyAppUtil.requirePositive(someSpecificProperty); this.someSpecificProperty = someSpecificProperty; return this; }
3. 基于Lombok扩展自定义校验
若项目已使用Lombok,可自定义类似@NonNull的校验注解,结合Lombok的代码生成能力,在setter方法中自动注入带变量名的正数校验逻辑,实现无侵入式简化调用。
总结
- 反射方式实现成本最低,但存在性能和重载方法适配的局限性;
- 编译时注解处理器性能最优,适合生产环境,但实现复杂度较高;
- Lombok扩展方案适配已有Lombok的项目,集成成本低。
内容的提问来源于stack exchange,提问作者Sergey Zolotarev
相关产品推荐
相关产品推荐

