The use case is this:
用例是这样的:
public void testMethod(String para1, String para2, String para3){
if(para1==null){
System.out.println("para1 cannot be null");
}
if(para2)...
}
As the check null code above, we will be repeating ourselvous on writing the same code to check every parameter. But we cannot really factor out a common method, say, checknull(String para), because we need to output the name of the parameter so the users know which one is wrong.
作为上面的检查空代码,我们将重复编写相同的代码以检查每个参数。但我们不能真正分解出一个常见的方法,比如checknull(String para),因为我们需要输出参数的名称,以便用户知道哪一个是错误的。
Maybe there is no way to do this in java I guess. Method parameter names should be gone after compile if I understand it correctly.
也许在java中没有办法做到这一点我想。如果我理解正确,方法参数名称应该在编译后消失。
So, how do you guys usually address this problem?
那么,你们通常如何解决这个问题呢?
10 个解决方案
#1
It's put in the message. No other way to do it. And no, you can't get the variable name.
它被放入了信息中。别无他法。不,你不能得到变量名。
I suggest you consider using Java's assert
feature, which is highly-underused. It can be quite concise too:
我建议你考虑使用Java的断言功能,这是一个高度未充分利用的功能。它也可以非常简洁:
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";
}
You just need to enable assertions in the VM with the -ea
parameter. That's another advantage: you can turn them on or off as a runtime option.
您只需要使用-ea参数在VM中启用断言。这是另一个优点:您可以将它们作为运行时选项打开或关闭。
It should be noted that the above will generate an AssertionError
, which is an Error
(in the Java sense), so won't be caught by a catch (Exception e)
block. So they should be used for conditions that really aren't recoverable or things that should never happen.
应该注意的是,上面将生成一个AssertionError,这是一个错误(在Java意义上),因此不会被catch(异常e)块捕获。所以他们应该被用于真正不可恢复的条件或者永远不会发生的事情。
Generally if a user breaks the contract (by passing in a null
when they shouldn't, for example) then an appropriate RuntimeException
may be better.
通常,如果用户违反合同(例如,当他们不应该传入null时),那么适当的RuntimeException可能会更好。
#2
If you want to check the value of a variable at run time, you can use reflection to check the instantiated objects fields like this:
如果要在运行时检查变量的值,可以使用反射来检查实例化的对象字段,如下所示:
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;
}
}
You can easily go from this implementation to one which uses getter/setter method invocations to check the value of inaccessible fields. If you want something less generic, or you want something which only checks specific fields, you can use c.getField(String) to get just that field, and then call field.get(object) for just that field.
您可以轻松地从此实现转到使用getter / setter方法调用来检查不可访问字段的值。如果你想要一些不那么通用的东西,或者你想要只检查特定字段的东西,可以使用c.getField(String)来获取该字段,然后只为该字段调用field.get(object)。
#3
I believe that Java 7 will have standard annotations requiring that a given parameter cannot be null. Unfortunately I have not seen these annotation for Java 6 or earlier :(
我相信Java 7将具有标准注释,要求给定参数不能为空。不幸的是我还没有看到Java 6或更早版本的这些注释:(
#4
Use the varargs notation in Java 1.5 . Declare your arguments as "Object... objects" and loop thru the collection.
在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"); } } }
public static void printSpaced(Object ... objects){for(Object o:objects){System.out.print(o +“:”); if(o ==“x”){System.out.print(“x found”); }}}
#5
What I do is similar to what you have, except I throw a NullPointerException (per Effective Java, personally, I'd have preferred IllegalArgumentException).
我所做的与你所拥有的类似,除了我抛出一个NullPointerException(根据Effective Java,我个人更喜欢IllegalArgumentException)。
...
if (para1 == null) {
throw new NullPointerException("para1 cannot be null");
}
...
If you want to refactor it out to a method, you could do something along the lines of:
如果你想将它重构为一个方法,你可以做以下几点:
assertNotNull(Object param, String paramName) {...}
#6
Although it may be overkill, I guess it is also worth mentioning that you could check your arguments using a 3rd party design by contract framework. The Java implementations seem to rely on doclet comments or annotations to specify the rules. I've only taken a cursory look at them, so I can't recommend any one in particular.
虽然它可能有点过分,但我想也值得一提的是,您可以通过合同框架使用第三方设计来检查您的论点。 Java实现似乎依赖于doclet注释或注释来指定规则。我只是粗略地看一下它们,所以我不能特别推荐任何一个。
#7
Hmm, even if you could dynamically get the parameter names, I don't see that there would be much benefit. It's not that tough to write:
嗯,即使你可以动态获取参数名称,我也没有看到会有很多好处。写起来并不难:
checkNull("parm1", parm1);
checkNull("parm2", parm2);
checkNull("parm3", parm3);
By the way, I hope this is just example code, and you don't REALLY call your parameters parm1, parm2, and parm3, but something more meaningful like customerName, balanceDue, and accountType.
顺便说一句,我希望这只是示例代码,并且您不会真正调用参数parm1,parm2和parm3,而是更有意义的东西,如customerName,balanceDue和accountType。
And once you say that, it should quickly become apparent that in a real application, the validation requirements for each parameter will likely be different. customerName should not be null, but it probably also should not be an empty string. balanceDue should contain only digits and at most one decimal point and possibly a leading minus sign. Etc. So you can't just loop through all your parameters performing the same validation on each, rather you must do the appropriate validation for each.
一旦你这么说,很快就会发现在实际应用中,每个参数的验证要求可能会有所不同。 customerName不应为null,但它也可能不应为空字符串。 balanceDue应仅包含数字,最多只能包含一个小数点,可能还包含一个前导减号。等等。因此,您不能只遍历所有参数,在每个参数上执行相同的验证,而是必须对每个参数进行相应的验证。
Unless you have dozens of parameters, the code to write a loop would be almost as much trouble as just writing several calls to a common validation function anyway. And if you have dozens of parameters, this is usually a bad thing of itself.
除非你有很多参数,否则编写循环的代码几乎和编写几个调用公共验证函数一样麻烦。如果你有几十个参数,这通常是一件坏事。
#8
I haven't used it, but Paranamer can give you runtime access to parameter names (at the cost of requiring debug info in code and using reflection to get parameter names). This is almost certainly overkill for your problem however.
我没有使用它,但Paranamer可以为您提供对参数名称的运行时访问(代价是在代码中需要调试信息并使用反射来获取参数名称)。然而,这对你的问题来说几乎肯定是过度杀伤力。
Also note that the FindBugs and JSR305 annotations (the latter should make it to Java7, but can be used now with FindBugs and downloaded from the FindBugs site or Maven distribution) can be used in Java5 and above, to provide some level of compile-time checking of parameter nullness. I think that this is nice, and provides at least good documentation (as well as catching some errors), but is definitely not the same as a runtime check (which should catch all such errors, albeit only at runtime), and so as such is not a replacement (though perhaps you could write an AspectJ aspect that validated the parameters to methods with such annotations).
另请注意,FindBugs和JSR305注释(后者应该用于Java7,但现在可以与FindBugs一起使用并从FindBugs站点或Maven发行版下载)可以在Java5及更高版本中使用,以提供一定程度的编译时间检查参数空值。我认为这很好,并提供至少良好的文档(以及捕获一些错误),但绝对不同于运行时检查(它应该捕获所有这些错误,尽管只是在运行时),所以这样不是替代品(尽管你可能会编写一个AspectJ方面来验证带有这种注释的方法的参数)。
#9
Use an annotation on the param and add a dynamic proxy (either Java 4 style of CGLIB) to do the check See link text on how to use CGLIB
在param上使用注释并添加动态代理(CGLIB的Java 4样式)以进行检查请参阅有关如何使用CGLIB的链接文本
#10
Why don't you pass them along as a map? This way you could have a key representing the name of the variable and a value representing the actual String variable.
你为什么不把它们作为地图传递?这样,您可以使用表示变量名称的键和表示实际String变量的值。
#1
It's put in the message. No other way to do it. And no, you can't get the variable name.
它被放入了信息中。别无他法。不,你不能得到变量名。
I suggest you consider using Java's assert
feature, which is highly-underused. It can be quite concise too:
我建议你考虑使用Java的断言功能,这是一个高度未充分利用的功能。它也可以非常简洁:
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";
}
You just need to enable assertions in the VM with the -ea
parameter. That's another advantage: you can turn them on or off as a runtime option.
您只需要使用-ea参数在VM中启用断言。这是另一个优点:您可以将它们作为运行时选项打开或关闭。
It should be noted that the above will generate an AssertionError
, which is an Error
(in the Java sense), so won't be caught by a catch (Exception e)
block. So they should be used for conditions that really aren't recoverable or things that should never happen.
应该注意的是,上面将生成一个AssertionError,这是一个错误(在Java意义上),因此不会被catch(异常e)块捕获。所以他们应该被用于真正不可恢复的条件或者永远不会发生的事情。
Generally if a user breaks the contract (by passing in a null
when they shouldn't, for example) then an appropriate RuntimeException
may be better.
通常,如果用户违反合同(例如,当他们不应该传入null时),那么适当的RuntimeException可能会更好。
#2
If you want to check the value of a variable at run time, you can use reflection to check the instantiated objects fields like this:
如果要在运行时检查变量的值,可以使用反射来检查实例化的对象字段,如下所示:
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;
}
}
You can easily go from this implementation to one which uses getter/setter method invocations to check the value of inaccessible fields. If you want something less generic, or you want something which only checks specific fields, you can use c.getField(String) to get just that field, and then call field.get(object) for just that field.
您可以轻松地从此实现转到使用getter / setter方法调用来检查不可访问字段的值。如果你想要一些不那么通用的东西,或者你想要只检查特定字段的东西,可以使用c.getField(String)来获取该字段,然后只为该字段调用field.get(object)。
#3
I believe that Java 7 will have standard annotations requiring that a given parameter cannot be null. Unfortunately I have not seen these annotation for Java 6 or earlier :(
我相信Java 7将具有标准注释,要求给定参数不能为空。不幸的是我还没有看到Java 6或更早版本的这些注释:(
#4
Use the varargs notation in Java 1.5 . Declare your arguments as "Object... objects" and loop thru the collection.
在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"); } } }
public static void printSpaced(Object ... objects){for(Object o:objects){System.out.print(o +“:”); if(o ==“x”){System.out.print(“x found”); }}}
#5
What I do is similar to what you have, except I throw a NullPointerException (per Effective Java, personally, I'd have preferred IllegalArgumentException).
我所做的与你所拥有的类似,除了我抛出一个NullPointerException(根据Effective Java,我个人更喜欢IllegalArgumentException)。
...
if (para1 == null) {
throw new NullPointerException("para1 cannot be null");
}
...
If you want to refactor it out to a method, you could do something along the lines of:
如果你想将它重构为一个方法,你可以做以下几点:
assertNotNull(Object param, String paramName) {...}
#6
Although it may be overkill, I guess it is also worth mentioning that you could check your arguments using a 3rd party design by contract framework. The Java implementations seem to rely on doclet comments or annotations to specify the rules. I've only taken a cursory look at them, so I can't recommend any one in particular.
虽然它可能有点过分,但我想也值得一提的是,您可以通过合同框架使用第三方设计来检查您的论点。 Java实现似乎依赖于doclet注释或注释来指定规则。我只是粗略地看一下它们,所以我不能特别推荐任何一个。
#7
Hmm, even if you could dynamically get the parameter names, I don't see that there would be much benefit. It's not that tough to write:
嗯,即使你可以动态获取参数名称,我也没有看到会有很多好处。写起来并不难:
checkNull("parm1", parm1);
checkNull("parm2", parm2);
checkNull("parm3", parm3);
By the way, I hope this is just example code, and you don't REALLY call your parameters parm1, parm2, and parm3, but something more meaningful like customerName, balanceDue, and accountType.
顺便说一句,我希望这只是示例代码,并且您不会真正调用参数parm1,parm2和parm3,而是更有意义的东西,如customerName,balanceDue和accountType。
And once you say that, it should quickly become apparent that in a real application, the validation requirements for each parameter will likely be different. customerName should not be null, but it probably also should not be an empty string. balanceDue should contain only digits and at most one decimal point and possibly a leading minus sign. Etc. So you can't just loop through all your parameters performing the same validation on each, rather you must do the appropriate validation for each.
一旦你这么说,很快就会发现在实际应用中,每个参数的验证要求可能会有所不同。 customerName不应为null,但它也可能不应为空字符串。 balanceDue应仅包含数字,最多只能包含一个小数点,可能还包含一个前导减号。等等。因此,您不能只遍历所有参数,在每个参数上执行相同的验证,而是必须对每个参数进行相应的验证。
Unless you have dozens of parameters, the code to write a loop would be almost as much trouble as just writing several calls to a common validation function anyway. And if you have dozens of parameters, this is usually a bad thing of itself.
除非你有很多参数,否则编写循环的代码几乎和编写几个调用公共验证函数一样麻烦。如果你有几十个参数,这通常是一件坏事。
#8
I haven't used it, but Paranamer can give you runtime access to parameter names (at the cost of requiring debug info in code and using reflection to get parameter names). This is almost certainly overkill for your problem however.
我没有使用它,但Paranamer可以为您提供对参数名称的运行时访问(代价是在代码中需要调试信息并使用反射来获取参数名称)。然而,这对你的问题来说几乎肯定是过度杀伤力。
Also note that the FindBugs and JSR305 annotations (the latter should make it to Java7, but can be used now with FindBugs and downloaded from the FindBugs site or Maven distribution) can be used in Java5 and above, to provide some level of compile-time checking of parameter nullness. I think that this is nice, and provides at least good documentation (as well as catching some errors), but is definitely not the same as a runtime check (which should catch all such errors, albeit only at runtime), and so as such is not a replacement (though perhaps you could write an AspectJ aspect that validated the parameters to methods with such annotations).
另请注意,FindBugs和JSR305注释(后者应该用于Java7,但现在可以与FindBugs一起使用并从FindBugs站点或Maven发行版下载)可以在Java5及更高版本中使用,以提供一定程度的编译时间检查参数空值。我认为这很好,并提供至少良好的文档(以及捕获一些错误),但绝对不同于运行时检查(它应该捕获所有这些错误,尽管只是在运行时),所以这样不是替代品(尽管你可能会编写一个AspectJ方面来验证带有这种注释的方法的参数)。
#9
Use an annotation on the param and add a dynamic proxy (either Java 4 style of CGLIB) to do the check See link text on how to use CGLIB
在param上使用注释并添加动态代理(CGLIB的Java 4样式)以进行检查请参阅有关如何使用CGLIB的链接文本
#10
Why don't you pass them along as a map? This way you could have a key representing the name of the variable and a value representing the actual String variable.
你为什么不把它们作为地图传递?这样,您可以使用表示变量名称的键和表示实际String变量的值。