Java: использование RuntimeException для сбегания от Посетителя

1128] Хотя на этот вопрос уже был дан ответ, я хотел бы расширить существующие ответы.

Как уже упоминал Странник, фигурные скобки здесь означают тело лямбды. Kotlin поддерживает размещение обратных вызовов вне регулярных скобок .

Это:

button.setOnClickListener {clickListener()}

Равно равно:

button.setOnClickListener({clickListener()})

, что равно:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        clickListener();
    }
});

Или (только Java 8) :

button.setOnClickListener(view -> clickListener());

TL; DR: содержимое аргументов функции определяется с помощью (), а лямбда-тела определяются с помощью {} (так же, как с обычными функциями, классами, интерфейсами , так далее.).

Теперь, во-первых, обратный вызов метода onClick принимает аргумент view. Если вы используете автономную функцию, у нее должен быть следующий аргумент:

fun clickListener(view: View) { TODO("Place your listener code here") }

Это основано на именовании - если вы реализуете OnClickListener, просто передайте this в качестве аргумента. У вас уже есть слушатель и функция, поэтому вам не нужно явно определять, что передать. Однако, если вы реализуете OnClickListener, обязательно проверьте идентификатор перед выполнением действия, если у вас есть несколько представлений, использующих его в качестве прослушивателя.

Если вы используете методы, следующее зависит от того, как.

Использование функций var или val

Если ваш обратный вызов определен как:

val listener = {view: View -> 
       TODO()               
    }

Вы можете передать его как аргумент:

button.setOnClickListener(listener)

[1126 ] OnClickListeners

Если у вас есть var onClickListener: OnClickListener, применяются те же функции, что и с функциями var / val.

Использование функции

Если у вас есть fun clickListener, вам придется добавить лямбду, чтобы передать его. Это, как и в случае с Java, использовать ::. Однако вам не нужно явно объявлять область действия, как в Java. Это означает, что любой из них будет работать:

button.setOnClickListener(::clickListener);
button.setOnClickListener(this::clickListener);
// alternatively with a different target, if it's somewhere else. 

Дальнейшее чтение

10
задан Chris Conway 15 December 2008 в 23:04
поделиться

7 ответов

Я думаю, что это - разумный подход по нескольким причинам:

  • Вы используете третью сторону и не можете добавить контролируемую исключительную ситуацию
  • Проверка возвращаемых значений везде в большой группе посетителей, когда это только необходимо в некоторых, является ненужной нагрузкой

Кроме того, существуют те, которые утверждали, что неконтролируемые исключения не все настолько плохо. Ваше использование напоминает мне о OperationCanceledException Eclipse, который используется для выдувания из продолжительных фоновых задач.

Это не прекрасно, но, если хорошо зарегистрировано, это кажется хорошо мне.

4
ответ дан 4 December 2019 в 02:27
поделиться

Существует ли причина, Вы только возвращаете значение? Такой как ПУСТОЙ УКАЗАТЕЛЬ, если Вы действительно хотите ничего не возвратить? Это было бы намного более простым, и не рискнет выдавать исключение на этапе выполнения непроверенное.

0
ответ дан 4 December 2019 в 02:27
поделиться

При выдаче исключения на этапе выполнения, поскольку управляющая логика является определенно плохой идеей. Причина Вы чувствуете себя грязными, состоит в том, что Вы обходите систему типов, т.е. тип возврата Ваших методов является ложью.

У Вас есть несколько опций, которые являются значительно более чистыми.

1. Функтор исключений

Хорошая техника для использования, когда Вы ограничиваетесь в исключениях, которые можно выдать, если Вы не можете бросить контролируемую исключительную ситуацию, возвращает объект, который бросит контролируемую исключительную ситуацию. java.util.concurrent. Вызываемый экземпляр этого функтора, например.

Посмотрите здесь для подробного объяснения этой техники.

Например, вместо этого:

public Something visit(Node n) {
  if (n.someting())
     return new Something();
  else
     throw new Error("Remember to catch me!");
}

Сделайте это:

public Callable<Something> visit(final Node n) {
  return new Callable<Something>() {
    public Something call() throws Exception {
      if (n.something())
         return new Something();
      else
         throw new Exception("Unforgettable!");
    }
  };
}

2. Дизъюнктное объединение (иначе любой Bifunctor)

Эта техника позволяет Вам возвратить одни из двух различных типов из того же метода. Это немного похоже Tuple<A, B> техника, что большинство людей знакомо с для того, чтобы возвратить больше чем одно значение из метода. Однако вместо того, чтобы возвращать значения обоих типов A и B, это включает возвращение единственного значения или типа A или B.

Например, учитывая Сбой перечисления, который мог перечислить применимые коды ошибок, пример становится...

public Either<Fail, Something> visit(final Node n) {
  if (n.something())
    return Either.<Fail, Something>right(new Something());
  else
    return Either.<Fail, Something>left(Fail.DONE);
}

Совершение звонка является теперь намного более чистым, потому что Вы не должны пробовать/ловить:

Either<Fail, Something> x = node.dispatch(visitor);
for (Something s : x.rightProjection()) {
  // Do something with Something
}
for (Fail f : x.leftProjection()) {
  // Handle failure
}

Любой класс не очень трудно записать, но полнофункциональная реализация обеспечивается библиотекой Functional Java.

3. Монада опции

Немного как безопасный с точки зрения типов пустой указатель, это - хорошая техника для использования, когда Вы не хотите возвращать значение для некоторых исходных данных, но Вам не нужны исключения или коды ошибок. Обычно люди возвратят то, что назвало "значение сигнальной метки", но Опция является значительно более чистой.

Вы теперь имеете...

public Option<Something> visit(final Node n) {
  if (n.something())
    return Option.some(new Something());
  else
    return Option.<Something>none();
}    

Вызов является хорошим и чистым:

Option<Something> s = node.dispatch(visitor));
if (s.isSome()) {
  Something x = s.some();
  // Do something with x.
}
else {
  // Handle None.
}

И то, что это - монада, позволяет Вам цепочечные вызовы, не обрабатывая специальное предложение, которое Ни один не оценивает:

public Option<Something> visit(final Node n) {
  return dispatch(getIfPart(n).orElse(dispatch(getElsePart(n)));
}    

Класс Опции еще легче записать, чем Также, но снова, полнофункциональная реализация обеспечивается библиотекой Functional Java.

Посмотрите здесь для детального обсуждения Опции и Также.

4
ответ дан 4 December 2019 в 02:27
поделиться

Я вижу следующие опции для Вас:

  1. Идите вперед и определите это RuntimeException подкласс. Проверьте на серьезные проблемы путем ловли исключения в наиболее общем вызове к dispatch и создание отчетов, что то, если это получает это далеко.
  2. Имейте возврат кода обработки узла специальный объект, если он думает, ища, должен закончиться резко. Это все еще вынуждает Вас проверить возвращаемые значения вместо того, чтобы ловить исключения, но Вам мог бы понравиться вид кода лучше тот путь.
  3. Если обход дерева должен быть остановлен некоторым внешним фактором, сделайте все это в подпотоке и установите синхронизируемое поле в том объекте, чтобы сказать потоку останавливаться преждевременно.
0
ответ дан 4 December 2019 в 02:27
поделиться

Почему Вы возвращаете значение от своего посетителя? Соответствующий метод посетителя называют классы, которые посещают. Вся сделанная работа инкапсулируется в самом классе посетителя, это ничего не должно возвращать и обрабатывать свои собственные ошибки. Единственное обязательство, требуемое класса вызова, состоит в том, чтобы назвать соответствующий visitXXX метод, ничто больше. (Это предполагает, что Вы используете перегруженные методы в качестве в Вашем примере в противоположность переопределению того же посещения () метод для каждого типа).

Посещаемый класс не должен быть изменен посетителем или иметь, чтобы иметь любое знание того, что это делает, кроме него позволяет посещению происходить. Возвращение значения или выдача исключения нарушили бы это.

Шаблон "посетитель"

0
ответ дан 4 December 2019 в 02:27
поделиться

Необходимо ли использовать Посетителя от XTC? Это - довольно тривиальный интерфейс, и Вы могли реализовать свое собственное, которое может бросить проверенный ReturnException, который Вы не забыли бы ловить при необходимости.

0
ответ дан 4 December 2019 в 02:27
поделиться

Я не пользовался библиотекой XTC, которую Вы упоминаете. Как это предоставляет дополнительную часть шаблона "посетитель" - accept(visitor) метод на узлах? Даже если это - основанный на отражении диспетчер, должно все еще быть что-то, что обрабатывает рекурсию вниз синтаксическое дерево?

Если этот структурный итеративный код с готовностью доступен, и Вы уже не используете возвращаемое значение от Вашего visitXxx(node) методы, мог Вы использовать простое перечислимое возвращаемое значение или даже булев флаг, говоря accept(visitor) не рекурсивно вызывать в дочерние узлы?

Если:

  • accept(visitor) явно не реализован узлами (существует некоторое продолжение отражения поля или средства доступа, или узлы просто реализуют получающий ребенка интерфейс для некоторой стандартной логики потока управления, или по любой другой причине...), и

  • Вы не хотите смешивать со структурной частью итерации библиотеки, или это не доступно, или это не стоит усилия...

затем как последнее прибежище я предполагаю, что исключениями могла бы быть Ваша единственная опция, все еще пользуясь ванильной библиотекой XTC.

Интересная проблема, хотя, и я могу понять, почему основанный на исключении поток управления заставляет Вас чувствовать себя грязными...

0
ответ дан 4 December 2019 в 02:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: