#java #control-flow
#java #поток управления
Вопрос:
У меня есть переменная, x
.
Я хочу вызвать метод, m()
только если x
это одно из двух возможных значений.
При вызове m()
я хочу передать ему аргумент, значение которого зависит от значения x
.
Есть ли способ сделать это в Java без проверки значения x
более одного раза и вызова / записи m()
только в одном месте (т. Е. Не в нескольких ветвях if
оператора)?
Одно решение, которое я развлекаю:
switch (x) {
case 1:
y = "foo";
break;
case 2:
y = "bar";
break;
default:
y = null;
break;
}
if (y != null) m(y);
Но я не могу не чувствовать, что это технически проверяет x
дважды, просто скрывая этот факт, добавляя «прокси» для второй проверки.
(Чтобы пояснить, почему ограничения таковы, каковы они есть: при чтении кода мне трудно понять логику, которая сильно разветвляется при высокой степени дублирования между ветвями — это становится игрой «найди разницу», а не просто возможностью видеть, что происходит. Я предпочитаю агрессивно рефакторировать такое дублирование, что является привычкой, которая хорошо помогает мне в Ruby, JS и других языках; Я надеюсь, что смогу научиться делать то же самое для Java и сделать код более понятным для меня и других с первого взгляда.)
Комментарии:
1. Создайте
Map<Integer, String>
, заполните его значениями для1
и2
, а затем используйтеmap.get(x)
— проверки не требуются.2. @ElliottFrisch Является ли карта действительно лучшим решением, чем просто нарушение его логики в двух разных
if
утверждениях? Если это происходит часто, я бы понял, но для небольшого количества этого случая ваше решение действительно интересно?3. Ваш первый пример вообще не будет работать, он будет иметь одинаковый результат как для 1, так и для 2.
4. …Вы абсолютно правы, @MarkoTopolnik.
5. @MadJlzz Это действительно интересно в двух случаях, нет. Это способ сделать то, что просил OP, и я опубликовал его в качестве комментария, потому что у меня действительно не было времени, чтобы раскрыть корень всего зла .
Ответ №1:
Я не уверен в том, что вы хотите сделать, но, возможно, вы можете использовать Map для получения параметра ‘y’ из ‘x’
Map<Integer, String> map = new HashMap<>();
map.put(1, "foo");
map.put(2, "bar");
if (map.containsKey(x)) {
m(map.get(x));
}
Комментарии:
1. Разработчик Ruby во мне любит это.
2. Рад видеть, что вам нравится это 😉 Карты иногда могут быть очень эффективными для решения проблем
3. @Jos Я бы ни в коем случае не назвал это эффективным… Краткий или краткий, конечно, возможно, даже элегантный, но неэффективный.
4. Или
Optional.ofNullable(map.get(x)).ifPresent(y -> m(y));
5. @4castle приятно, или даже лучше, ИМХО, со ссылкой на метод вместо лямбда:
Optional.ofNullable(map.get(x)).ifPresent(this::m);
или, ИМХО, еще лучше со всеми ссылками на методы:Optional.of(x).map(map::get).ifPresent(this::m);
Ответ №2:
Используйте «goto» или эквивалент:
void do_m_if_appropriate() {
// x and y are assumed to be eg. member variables
switch (x) {
case 1:
y = "foo";
break;
case 2:
y = "bar";
break;
default:
return; // this is the "goto equivalent" part
}
m(y);
}
Выше довольно элегантно. При необходимости также тривиально изменить его на return true
or false
в зависимости от того, вызвано ли оно m()
, или просто y
or null
.
Вы также можете выполнять трюки с конструкциями цикла, хотя некоторые могут сказать, что это злоупотребление конструкцией цикла, и вы должны прокомментировать это соответствующим образом:
do { // note: not a real loop, used to skip call to m()
switch (x) {
case 1:
y = "foo";
break;
case 2:
y = "bar";
break;
default:
continue; // "goto equivalent" part
}
m(y);
} while(false);
Комментарии:
1. Оооо, мило. Вы используете окружающую область в качестве инструмента управления потоком, а затем используете продолжение блока, чтобы подразумевать «найдено подходящее значение».
2. Принимая этот ответ на данный момент, поскольку он наименее странный, используя только инструменты, которые существуют на большинстве распространенных языков, при этом удовлетворяя всем требованиям.
Ответ №3:
Вот решение с опциями (мой синтаксис Java может быть немного неправильным). Обратите внимание, что для вас код выглядит примерно так, но с точки зрения реализации он похож на опубликованный вами пример (т. Е. Проверяет, является ли y исключительным значением).
switch (x) {
case 1:
y = Optional<String>.of("foo");
break;
case 2:
y = Optional<String>.of("bar");
break;
default:
y = Optional<String>.empty();
break;
}
y.map((m's class)::m);
result = y.orElse( <value result should take if x was invalid> );
На самом деле может быть лучше изменить m(), чтобы возвращать необязательное значение и просто возвращать пустое значение, если значение y недопустимо, но я предполагаю, что вы хотите выполнить эту проверку на стороне вызывающего абонента.
Ответ №4:
Почему бы и нет
switch (x) {
case 1:
y = "foo";
m(y);
break;
case 2:
y = "bar";
m(y);
break;
}
Комментарии:
1. Как я уже говорил в сообщении: я не хочу вызывать
m()
более одного места, как вы это сделали.2. Мой плохой, я думал, вы имели в виду, что хотите вызвать его только один раз (не обязательно иметь его в одном месте в коде).