#java #if-statement #conditional-statements
#java #if-оператор #условные операторы
Вопрос:
У меня есть такая логика:
public void method(Boo result, Foo foo, Bar bar) {
if(foo != null) {
if(foo.getId() != null){
result.setId(foo.getId());
} else {
result.setId(bar.getId());
}
if(foo.getName() != null){
boo.setName(foo.getName());
} else {
result.setName(bar.getName());
}
// and many similar attributes
} else {
result.setId(bar.getId());
result.setName(bar.getName());
// and many similar attributes
}
}
Я нахожу этот способ уродливым, есть ли какой-нибудь способ улучшить его дизайн. Я знаю, что лучше использовать mapstruct, но в этом проекте я не могу.
Комментарии:
1. Использование троичного оператора превратило бы каждое if / else в одну строку. Однако, является ли это менее уродливым / более читаемым / лучшим для ваших целей, это совершенно другой вопрос.
2. @JustAnotherDeveloper У меня длинные атрибуты, если я использую тернарный оператор, это тоже может быть некрасиво
3. Если вы можете изменить объекты, возвращающие все эти поля с нулевым значением, вы могли бы использовать
Optional
. Однако это не очень поможет, если вы только обернете вещи локально здесь, в вашемmethod
.4. Если вы используете kotlin , вы можете использовать безопасные вызовы с операторами elvis , и проверки могут быть упрощены до одной строки.
5. @Marc Пожалуйста, прочтите руководство по проверке кода для пользователей Stack Overflow и обратите внимание, что текущий код не будет принят в Code Review за то, что он гипотетический.
Ответ №1:
Я бы поменял тесты. Это немного чище, но все равно будет выглядеть неаккуратно.
public void method(Boo result, Foo foo, Bar bar) {
setResult(result, bar);
if (foo != null) { setResult(result, foo); }
}
private void setResult(Boo result, Bar bar) {
result.setId(bar.getId());
...
}
private void setResult(Boo result, Foo foo) {
if (foo.getId != null) { result.setId(foo.getId()); }
...
}
Комментарии:
1. Я согласен с последним предложением , но это все равно будет выглядеть неаккуратно 🙂
Ответ №2:
С общим классом / интерфейсом:
Если Foo
и Bar
расширить общий базовый класс / интерфейс, вы могли бы создать универсальный метод для применения логики к любому атрибуту.
Например, допустим, что они реализуют этот интерфейс:
public interface IBaseInterface {
Long getId();
String getName();
}
Тогда мы могли бы создать этот универсальный метод:
public static <T> T getAttribute(IBaseInterface foo, IBaseInterface bar, Function<IBaseInterface, T> function) {
if(foo != null) {
T attribute = function.apply(foo);
if(attribute != null) {
return attribute;
}
}
return function.apply(bar);
}
И используйте его следующим образом:
result.setId(getAttribute(foo, bar, IBaseInterface::getId));
result.setName(getAttribute(foo, bar, IBaseInterface::getName));
Без общего класса / интерфейса:
Если они не расширяют общий базовый класс / интерфейс, вы все равно можете использовать этот метод, но вам придется передать методу другой параметр:
public static <T> T getAttribute(Foo foo, Bar bar, Function<Foo, T> functionFoo, Function<Bar, T> functionBar) {
if(foo != null) {
T attribute = functionFoo.apply(foo);
if(attribute != null) {
return attribute;
}
}
return functionBar.apply(bar);
}
И используйте его следующим образом:
result.setId(getAttribute(foo, bar, Foo::getId, Bar::getId));
result.setName(getAttribute(foo, bar, Foo::getName, Bar::getName));
Комментарии:
1. Оба ответа очень хороши, спасибо за ваш ответ, я немного подожду, если нет лучшего решения, я приму один из них
Ответ №3:
Я избегаю использования if else ObjectUtils::firstNonNull
как показано ниже:
public void method(Boo result, Foo foo, Bar bar) {
if(foo != null) {
result.setId(ObjectUtils.firstNonNull(foo.getId(), bar.getId()));
result.setId(ObjectUtils.firstNonNull(foo.getName(), bar.getName()));
// and many similar attributes
} else {
result.setId(bar.getId());
result.setName(bar.getName());
// and many similar attributes
}
}
Я открыт для других предложений!
Ответ №4:
Имея foo
в Optional
качестве, вы могли бы упростить свой код следующим образом:
Optional<Foo> optionalFoo = Optional.ofNullable(foo);
result.setId(optionalFoo.map(Foo::getId).orElseGet(bar::getId));
result.setName(optionalFoo.map(Foo::getName).orElseGet(bar::getName));
// ...
Ответ №5:
if
операторам не нужны фигурные скобки {}
, когда после этого есть один оператор. Думайте об этом как {...}
об одном операторе, заключающем в себе множество других.
Также Java на самом деле не заботится о пробелах и отступах, поэтому вы можете поместить несколько операторов в одну строку.
С этими знаниями вы можете сделать код красивее, например, так:
public void method(Boo result, Foo foo, Bar bar) {
if (foo != null) {
if (foo.getId() != null) result.setId(foo.getId());
else result.setId(bar.getId());
if (foo.getName() != null) boo.setName(foo.getName());
else result.setName(bar.getName());
} else {
result.setId(bar.getId());
result.setName(bar.getName());
}
}
или, по крайней мере, удалите {}
:
public void method(Boo result, Foo foo, Bar bar) {
if (foo != null) {
if (foo.getId() != null)
result.setId(foo.getId());
else
result.setId(bar.getId());
if (foo.getName() != null)
boo.setName(foo.getName());
else
esult.setName(bar.getName());
} else {
result.setId(bar.getId());
result.setName(bar.getName());
}
}
Комментарии:
1. Проблема не в длинном или коротком
Ответ №6:
Если объекты сопоставления имеют одинаковые свойства, и если у вас есть spring beans в зависимости от вашего проекта, BeanUtils.copyProperties (источник, назначение);