Мне нужно убедиться, что атрибут объекта не равен null, и добавьте значение по умолчанию, если оно равно null. Есть ли простой способ сделать это, или мне нужно сделать это вручную, проверив каждый атрибут его получателями и сеттерами?
Возможно ли в Java проверить, являются ли поля объектов пустыми, а затем добавить значение по умолчанию ко всем этим атрибутам?
Ответ 1
Вы можете использовать отражение для итерации по полю объекта и установки их. Вам, очевидно, потребуется какое-то сопоставление между типами или даже именами полей и требуемыми значениями по умолчанию, но это можно сделать довольно легко в цикле. Например:
for (Field f : obj.getClass().getFields()) {
f.setAccessible(true);
if (f.get(obj) == null) {
f.set(obj, getDefaultValueForType(f.getType()));
}
}
[Обновление]
С современной 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;
}
Тогда значения по умолчанию для TestPojo
можно установить, просто запустив test.setDetaults()
Ответ 2
Вам нужно вручную фильтровать входные данные для конструкторов и сеттеров. Ну... вы могли бы использовать отражение, но я бы не советовал. Часть работы конструкторов и сеттеров заключается в проверке ввода. Это может включать такие вещи, как:
public void setPrice(double price) {
if (price < 0.0d) {
throw new IllegalArgumentException("price cannot be negative " + price);
}
this.price = price;
}
и
public void setName(String name) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
}
Вы можете использовать функции-обертки для фактической проверки и исключения исключений.
Ответ 3
Возможно, проверьте 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;
...
}
Для ознакомления см. Начало работы с JSR 303 (Bean Validation) - часть 1 и часть 2 или раздел "Начало работы" справочного руководства, которое является частью дистрибутива Hibernate Validator.
Ответ 4
Неотражающее решение для Java 8 без использования ряда if's должно было бы передавать все поля и проверять на отсутствие:
return Stream.of(id, name).allMatch(Objects::isNull);
Это остается довольно легко поддерживать, избегая отражения. Это вернет true для нулевых атрибутов.
Ответ 5
Вы можете создать функцию, которая возвращает логическое значение и проверяет каждый атрибут. Вы можете вызвать эту функцию, чтобы выполнить эту работу для вас.
В качестве альтернативы вы можете инициализировать объект со значениями по умолчанию. Таким образом вам не нужно делать какие-либо проверки.
Ответ 6
У меня недостаточно контекста, чтобы дать вам правильный ответ, но я посоветую вам сделать код неизменным максимально возможным. Используйте поля public final
. Больше getters
или setters
: каждое поле должно быть определено constructor
. Ваш код короче, читабельнее и не позволяет писать код с побочными эффектами.
Это не мешает вам передавать пустые аргументы вашему конструктору, хотя... Вы все равно можете проверить каждый аргумент, как это было предложено с помощью @cletus, но я предлагаю вам вместо NullPointerException
добавить IllegalArgumentException
, что doesn не давайте нового намека на то, что вы сделали.
В любом случае, это то, что я делаю, насколько могу, и это улучшило мой код (читаемость, стабильность) в большой степени. Все в моей команде делают это, и мы очень этому довольны. Мы узнали, что когда мы пытаемся написать код erlang
, где все неизменно.
Надеюсь, что это поможет.
Ответ 7
Я пробовал это, и он работает без каких-либо проблем, чтобы проверить, пусто ли поле. Я частично ответил на ваш вопрос, поскольку я лично не пытался добавлять значения по умолчанию в атрибуты
if(field.getText()!= null && !field.getText().isEmpty())
Надеюсь, что это поможет
Ответ 8
Это не проверка на 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)
{
}
}
}