#java #if-statement #optimization
#java #if-оператор #оптимизация
Вопрос:
В моем проекте есть логика, похожая на следующий код, и будет много типов, но это слишком запутанно для написания, я хочу спросить, есть ли какой-либо более элегантный способ.
int a = 3,b = 5;
int type = 2;
if (type == 1) {
if (a > 1) {
System.out.println("a > 1");
} else if (b > 3) {
System.out.println("b > 3");
}
}
if (type == 2) {
if (b > 3) {
System.out.println("b > 3");
} else if (a > 1) {
System.out.println("a > 1");
}
}
Комментарии:
1. Оператор switch сделал бы его немного лучше.
2. Может быть, оператор переключения? В этом коде трудно выделить шаблон, который особенно поддается рефакторингу, чтобы сделать его «элегантным». Имейте в виду, что «элегантность» и «оптимизация» часто являются противоположными целями.
3. существуют ли только 2 переменные
a
иb
?4. @Bohemian ♦ В реальном проекте в операторе if есть три условия, a и b приведены только для иллюстрации
5. Не видя фактического кода (а не чего-то похожего на фактический код), трудно дать совет по рефакторингу. Это было бы похоже на то, как врач осматривает мою сестру, чтобы убедиться, что я здоров.
Ответ №1:
Используйте Map<Integer, BiConsumer<Integer, Integer>
.
Map<Integer, BiConsumer<Integer, Integer> map = new HashMap<>();
map.put(1, (a, b) -> {
if (a > 1) {
System.out.println("a > 1");
} else if (b > 3) {
System.out.println("b > 3");
}
});
map.put(2, (a, b) -> {
if (b > 3) {
System.out.println("b > 3");
} else if (a > 1) {
System.out.println("a > 1");
}
});
Затем использовать:
Optional.ofNullable(map.get(type)).ifPresent(c -> c.accept(a, b));
Комментарии:
1. И это лучше, чем код OP, потому что …?
2. @Holger потому что карта может быть определена, заполнена и протестирована в другом месте с точки использования. Популяция может быть даже через весенние бобы, причем каждая пара условие / лямбда является своим собственным бобом. Речь идет о развязке. Используя эту абстракцию, вы можете изменять способ, когда и где заполняется карта, создавать собственные карты для каждой среды, поддерживать и обновлять код, а также масштабировать его. Если вы запекаете его в виде жесткого кода, вы не сможете реально выполнить ни одну из этих вещей.
3. Поскольку эта мотивация не была указана в вопросе, не должна ли она быть в вашем ответе, а не в комментарии?
Ответ №2:
Итак, у вас есть куча условий со связанными сообщениями, и вы хотите проверить их в другом порядке в зависимости от типа?
Если это так, вы могли бы объявить
interface Checker {
String check();
}
а затем выполните:
Checker ca = () -> a > 1 ? "a > 1" : null;
Checker cb = () -> b > 3 ? "b > 3" : null;
Checker[][] checkers = {
null,
{ca, cb},
{cb, ca},
};
for (var checker : checkers[type]) {
var message = checker.check();
if (message != null) {
return message;
}
}
return null;
Это определяет каждое условие только один раз, независимо от того, сколько существует типов.
(вы также можете использовать выражение switch, а не массив)
Ответ №3:
Вы могли бы попробовать использовать оператор switch, это сделало бы его более элегантным. Что-то вроде:
int a = 3, b = 5;
int type = 2;
switch (type)
{
case 1:
if (a>1) System.out.println("a > 1");
else if (b > 3) System.out.println("b > 3");
break;
case 2:
if(b > 3) System.out.println("b > 3");
else if(a > 1) System.out.println("a > 1");
break;
}
Я надеюсь, что это было несколько полезно, удачи!
Комментарии:
1. Упс, я думаю, вы правы. В последние несколько дней я экспериментировал с операторами C switch, поэтому я немного перепутал. Редактирование, спасибо за комментарий.
Ответ №4:
Если проверка и действие повторяются, вы можете избежать некоторого повторения с помощью чего-то подобного. Самое плохое в этом — это работа с побочными эффектами…
private boolean checkA(int a) {
if (a > 1) {
System.out.println("a > 1");
return true;
}
return false;
}
private boolean checkB(int b) {
if (b > 3) {
System.out.println("b > 3");
return true;
}
return false;
}
...
switch (type)
{
case 1: if (!checkA(a)) {
checkB(b);
}
break;
case 2: if (!checkB(b)) {
checkA(a);
}
break;
}
Редактировать
еще один неприятный способ, которым этим можно «злоупотреблять», — это
boolean dummy;
switch (type)
{
case 1: dummy = checkA(a) || checkB(b);
break;
case 2: dummy = checkB(b) || checkA(a);
break;
}
Ответ №5:
Начните с использования классов для ваших разных типов. Это упростит добавление дополнительных типов с различным поведением. Затем вы можете рассмотреть вопрос об упрощении классов по отдельности. Вы также сможете протестировать их отдельно с помощью модульных тестов.
Ваш пример становится…
new Type2(3, 5).process();
Если у вас есть следующие классы
public interface Processor {
void process();
}
public class Type1 implements Processor {
private int a;
private int b;
public Type1(int a, int b) {
this.a = a;
this.b = b;
}
@Override
public void process() {
if (a > 1) {
System.out.println("a > 1");
} else if (b > 3) {
System.out.println("b > 3");
}
}
}
public class Type2 implements Processor {
private int a;
private int b;
public Type2(int a, int b) {
this.a = a;
this.b = b;
}
@Override
public void process() {
if (b > 3) {
System.out.println("b > 3");
} else if (a > 1) {
System.out.println("a > 1");
}
}
}