用例是这样的:
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中我无法做到这一点。如果我理解正确,方法参数名称应该在编译后消失。
那么,你们通常如何解决这个问题呢?
答案 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变量的值。