是否有可能在Java中检查对象字段是否为空,然后将默认值添加到所有这些属性?

new*_*bie 27 java null

我需要确保没有object属性为null并且如果它为null则添加默认值.有没有简单的方法可以做到这一点,还是我必须通过其getter和setter检查每个属性来手动完成?

Gus*_*uss 39

您可以使用反射迭代对象的字段,并设置它们.您显然需要在类型甚至字段名称和所需的默认值之间进行某种映射,但这可以在循环中非常容易地完成.例如:

for (Field f : obj.getClass().getFields()) {
  f.setAccessible(true);
  if (f.get(obj) == null) {
     f.set(obj, getDefaultValueForType(f.getType()));
  }
}
Run Code Online (Sandbox Code Playgroud)

[更新]

使用现代Java,您可以使用注释为每个类设置字段的默认值.完整的实现可能如下所示:

// DefaultString.java:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultString {
    String value();
}

// DefaultInteger.java:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultInteger {
    int value();
}

// DefaultPojo.java:
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

public class DefaultPojo {

    public void setDefaults() {
        for (Field f : getClass().getFields()) {
            f.setAccessible(true);
            try {
                if (f.get(this) == null) {
                    f.set(this, getDefaultValueFromAnnotation(f.getAnnotations()));
                }
            } catch (IllegalAccessException e) { // shouldn't happen because I used setAccessible
            }
        }
    }

    private Object getDefaultValueFromAnnotation(Annotation[] annotations) {
        for (Annotation a : annotations) {
            if (a instanceof DefaultString)
                return ((DefaultString)a).value();
            if (a instanceof DefaultInteger)
                return ((DefaultInteger)a).value();
        }
        return null;
    }

}

// Test Pojo
public class TestPojo extends DefaultPojo {
    @DefaultString("Hello world!")
    public String stringValue;
    @DefaultInteger(42);
    public int integerValue;
}
Run Code Online (Sandbox Code Playgroud)

然后TestPojo可以通过运行来设置a的默认值test.setDetaults()

  • 我建议使用getDeclaredFields而不是getFields - 为我工作,因为declaredFields包含私有字段. (6认同)

cle*_*tus 11

您需要手动过滤输入到构造函数和setter.嗯......你可以使用反射,但我不会建议.构造函数和setter的部分工作是验证输入.这可能包括以下内容:

public void setPrice(double price) {
  if (price < 0.0d) {
    throw new IllegalArgumentException("price cannot be negative " + price);
  }
  this.price = price;
}
Run Code Online (Sandbox Code Playgroud)

public void setName(String name) {
  if (name == null) {
    throw new NullPointerException("name cannot be null");
  }
  this.name = name;
}
Run Code Online (Sandbox Code Playgroud)

您可以使用包装函数进行实际检查并抛出异常.

  • 在"null"参数的情况下,我不会抛出一个`NullPointerException:它没有给出任何提示.我会在每种情况下都抛出`IllegalArgumentException`并让JVM在它进入enconters时抛出`NullPointerException`.我不会使用反思. (5认同)

Pas*_*ent 7

也许检查Hibernate Validator 4.0,JSR 303的参考实现:Bean验证.

这是带注释的类的示例:

public class Address {

    @NotNull 
    private String line1;
    private String line2;
    private String zip;
    private String state;

    @Length(max = 20)
    @NotNull
    private String country;

    @Range(min = -2, max = 50, message = "Floor out of range")
    public int floor;

        ...
}
Run Code Online (Sandbox Code Playgroud)

有关介绍,请参阅JSR 303入门(Bean验证) - 第1部分第2部分或参考指南的"入门"部分,它是Hibernate Validator发行版的一部分.


Ama*_*gar 6

不使用一系列if的Java 8非反射解决方案将是流所有字段并检查是否为空:

return Stream.of(id, name).allMatch(Objects::isNull);
Run Code Online (Sandbox Code Playgroud)

这在避免反射锤的同时仍然非常容易维护。对于空属性,将返回true。