You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 14:33:15