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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2146129/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 04:06:46  来源:igfitidea点击:

Is it possible in Java to check if objects fields are null and then add default value to all those attributes?

javanull

提问by newbie

I need to make sure that no object attribute is null and add default value in case if it is null. Is there any easy way to do this, or do I have to do it manually by checking every attribute by its getters and setters?

我需要确保没有对象属性为空并添加默认值以防它为空。有什么简单的方法可以做到这一点,还是我必须通过 getter 和 setter 检查每个属性来手动完成?

采纳答案by Guss

You can use reflection to iterate over the object's field, and set them. You'd obviously need some sort of mapping between types or even field names and required default values but this can be done quite easily in a loop. For example:

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

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

[Update]

[更新]

With modern Java, you can use annotations to set the default values for fields on a per class basis. A complete implementation might look like this:

使用现代 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;
}

Then default values for a TestPojocan be set just by running test.setDetaults()

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

回答by cletus

You need to manually filter input to constructors and setters. Well... you could use reflection but I wouldn't advise it. Part of the job of constructors and setters is to validate input. That can include things like:

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

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

and

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

You could use wrapper functions for the actual check and throwing the exception.

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

回答by Lucas T

You can create a function that returns a boolean value and checks every attribute. You can call that function to do the job for you.

您可以创建一个返回布尔值并检查每个属性的函数。您可以调用该函数来为您完成这项工作。

Alternatively, you can initialize the object with default values. That way there is no need for you to do any checking.

或者,您可以使用默认值初始化对象。这样您就无需进行任何检查。

回答by Pascal Thivent

Maybe check Hibernate Validator 4.0, the Reference Implementation of the JSR 303: Bean Validation.

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

This is an example of an annotated class:

这是带注释的类的示例:

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;

        ...
}

For an introduction, see Getting started with JSR 303 (Bean Validation) – part 1and part 2or the "Getting started" section of the reference guide which is part of the Hibernate Validator distribution.

有关介绍,请参阅JSR 303 入门(Bean 验证)– 第 1 部分第 2 部分或参考指南的“入门”部分,这是 Hibernate Validator 发行版的一部分。

回答by Jean-Philippe Caruana

I don't have enough context to give you a correct answer, but I'll suggest you to make you code immutableas much as possible. Use public finalfields. No more gettersor setters: every field has to be defined by the constructor. Your code is shorter, more readable and prevents you from writing code with side effects.

我没有足够的上下文来给你一个正确的答案,但我建议你尽可能让你的代码不可变。使用public final字段。没有更多getterssetters:每个字段都必须由constructor. 您的代码更短、更易读,并防止您编写带有副作用的代码。

It doesn't prevent you from passing null arguments to your constructor though... You can still check every argument as suggested by @cletus, but I'll suggest you to throw IllegalArgumentExceptioninstead of NullPointerExceptionthat doesn't give no new hint about what you've done.

尽管如此,它并不会阻止您将空参数传递给您的构造函数......您仍然可以按照@cletus 的建议检查每个参数,但我建议您抛出IllegalArgumentException而不是NullPointerException它不会给出任何关于您的新提示已经做了。

Anyway, that's what I do as much as I can and it improved my code (readability, stability) to a great extend. Everyone in my team does so and we are very happy with that. We learned that when we try to write some erlangcode where everything is immutable.

无论如何,这就是我尽可能多地做的事情,它在很大程度上改进了我的代码(可读性、稳定性)。我团队中的每个人都这样做,我们对此感到非常高兴。我们了解到,当我们尝试编写一些erlang代码时,一切都是不可变的。

Hope this helps.

希望这可以帮助。

回答by Mickey

I tried this and it works without any issues to validate if the field is empty. I have answered your question partially as I haven't personally tried to add default values to attributes

我试过这个,它可以正常工作,没有任何问题来验证该字段是否为空。我已经部分回答了您的问题,因为我没有亲自尝试向属性添加默认值

if(field.getText()!= null && !field.getText().isEmpty())

Hope it helps

希望能帮助到你

回答by Mickey

This is not to check for null, instead this will be helpful in converting an existing object to an empty object(fresh object). I dont know whether this is relevant or not, but I had such a requirement.

这不是检查 null,而是有助于将现有对象转换为空对象(新对象)。我不知道这是否相关,但我有这样的要求。

@SuppressWarnings({ "unchecked" })
static void emptyObject(Object obj) 
{
    Class c1 = obj.getClass();
    Field[] fields = c1.getDeclaredFields();

    for(Field field : fields)
    {
        try
        {
            if(field.getType().getCanonicalName() == "boolean")
            {
                field.set(obj, false);
            }
            else if(field.getType().getCanonicalName() == "char")
            {
                field.set(obj, '\u0000');
            }
            else if((field.getType().isPrimitive()))
            {
                field.set(obj, 0);
            }
            else
            {
                field.set(obj, null);
            }
        }
        catch(Exception ex)
        {

        }
    }
}

回答by Amar Magar

Non-reflective solution for Java 8, without using a series of if's, would be to stream all fields and check for nullness:

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

return Stream.of(id, name).allMatch(Objects::isNull);

This remains quite easy to maintain while avoiding the reflection hammer. This will return true for null attributes.

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