如何在运行时获取变量名?

时间:2009-06-30 13:00:11

标签: java

用例是这样的:

public void testMethod(String para1, String para2, String para3){


 if(para1==null){
         System.out.println("para1 cannot be null");

   }
 if(para2)...
}

作为上面的检查空代码,我们将重复编写相同的代码来检查每个参数。但是我们不能真正分解出一个常见的方法,比如checknull(String para),因为我们需要输出参数的名称,以便用户知道哪一个是错误的。

也许在java中我无法做到这一点。如果我理解正确,方法参数名称应该在编译后消失。

那么,你们通常如何解决这个问题呢?

10 个答案:

答案 0 :(得分:4)

它已放入消息中。别无他法。不,你不能得到变量名。

我建议您考虑使用Java的assert功能,该功能未得到充分利用。它也可以非常简洁:

public void testMethod(String para1, String para2, String para3) {
  assert para1 != null : "para1 is null";
  assert para2 != null : "para2 is null";
  assert para3 != null : "para3 is null";
}

您只需要使用-ea参数在VM中启用断言。这是另一个优点:您可以将它们作为运行时选项打开或关闭。

应该注意的是,上面将生成AssertionError,这是Error(在Java意义上),因此不会被catch (Exception e)块捕获。所以他们应该被用于真正无法恢复的条件或者永远不会发生的事情。

通常,如果用户违反合同(例如,当他们不应该传递null时),则适当的RuntimeException可能更好。

答案 1 :(得分:2)

如果要在运行时检查变量的值,可以使用反射来检查实例化的对象字段,如下所示:

package sandbox;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class ReflectionClassChecker {

    public static boolean checkAllPublic(Object someObject){
        System.out.println("Checking someObject " + someObject.toString());
        boolean hasNulls = false;

        Class<?> c = someObject.getClass();

        Field[] fields = c.getFields();

        for(Field field: fields){
            System.out.println("Checking field " + field.getName() + ".");
            if(isFieldPublic(field)){
                System.out.println("Field " + field.getName() + " is public, checking it for null.");
                Object value = getField(field, someObject) ; 
                if(value == null){
                    System.out.println("Field " + field.getName() + " is null.");
                    hasNulls = true;
                } else {
                    System.out.println("Field " + field + " has value " + value );
                }
            }
        }

        return hasNulls;
    }

    private static boolean isFieldPublic(Field field){
        int modifiers = field.getModifiers();
        boolean isPublic = Modifier.isPublic(modifiers);        
        return isPublic;
    }

    private static Object getField(Field field, Object someObject){
        Object value = null;
        try{
            value = field.get(someObject);
        } catch (IllegalAccessException ignore){
            System.out.println(ignore);
        }       
        return value;
    }
}

您可以轻松地从此实现转到使用getter / setter方法调用来检查不可访问字段的值。如果你想要一些不那么通用的东西,或者你想要只检查特定字段的东西,可以使用c.getField(String)来获取该字段,然后只为该字段调用field.get(object)。

答案 2 :(得分:1)

我相信Java 7将具有标准注释,要求给定参数不能为空。不幸的是,我还没有看到Java 6或更早版本的这些注释:(

答案 3 :(得分:1)

在Java 1.5中使用varargs表示法。将您的参数声明为“Object ... objects”并循环通过集合。

public static void printSpaced(Object ... objects) {    for(Object o:objects){         System.out.print(o +“:”);                 if(o ==“x”){                         System.out.print(“x found”);                 }         } }

答案 4 :(得分:0)

我所做的与您所拥有的类似,除了我抛出NullPointerException(根据有效Java,我个人更喜欢IllegalArgumentException)。

...
if (para1 == null) {
    throw new NullPointerException("para1 cannot be null");
}
...

如果你想将它重构为一个方法,你可以按照以下方式做点什么:

assertNotNull(Object param, String paramName) {...}

答案 5 :(得分:0)

虽然它可能有点过分,但我想也值得一提的是你可以使用第三方design by contract框架检查你的论点。 Java实现似乎依赖于doclet注释或注释来指定规则。我只是粗略地看一下它们,所以我不能特别推荐任何一个。

答案 6 :(得分:0)

嗯,即使你可以动态获取参数名称,我也看不出会有多大好处。写起来并不难:

checkNull("parm1", parm1);
checkNull("parm2", parm2);
checkNull("parm3", parm3);

顺便说一句,我希望这只是示例代码,并且您不会真正调用参数parm1,parm2和parm3,而是更有意义的东西,如customerName,balanceDue和accountType。

一旦你这么说,很快就会发现在实际应用中,每个参数的验证要求可能会有所不同。 customerName不应为null,但它也可能不应为空字符串。 balanceDue应仅包含数字,最多只能包含一个小数点,可能还包含一个前导减号。等等。所以你不能只循环遍历所有参数,在每个参数上执行相同的验证,而是必须对每个参数进行适当的验证。

除非你有几十个参数,否则写一个循环的代码几乎和编写几个调用公共验证函数一样麻烦。如果你有几十个参数,这通常是一件坏事。

答案 7 :(得分:0)

我没有使用它,但是Paranamer可以为您提供对参数名称的运行时访问(代价是在代码中需要调试信息并使用反射来获取参数名称)。然而,这对你的问题几乎肯定是过度杀伤。

另请注意,FindBugs和JSR305注释(后者应该使其成为Java7,但现在可以与FindBugs一起使用并从FindBugs站点或Maven发行版下载)可以在Java5及更高版本中使用,以提供某种程度的编译时检查参数nullness。我认为这很好,并提供至少良好的文档(以及捕获一些错误),但绝对不同于运行时检查(它应该捕获所有这些错误,尽管只是在运行时),所以这样不是替代品(尽管你可以编写一个AspectJ方面来验证带有这种注释的方法的参数)。

答案 8 :(得分:0)

在param上使用注释并添加动态代理(Java 4样式的CGLIB)以进行检查请参阅link text有关如何使用CGLIB的信息

答案 9 :(得分:-1)

为什么不将它们作为地图传递?这样,您可以使用表示变量名称的键和表示实际String变量的值。