Как мне управлять сложным управлением потоком в Java? - PullRequest
3 голосов
/ 13 апреля 2011

Я некоторое время изучал управление потоками Java и обработку исключений, и у меня есть следующие общепринятые правила:

  1. не использовать обработку исключений для управления потоком
  2. избегайте проверенных исключений, если клиент не ожидает восстановления (что является хорошим способом сказать, что вы заставляете клиента обрабатывать исключение, чтобы он мог также попытаться восстановить его?)

Наряду с общими правилами я стараюсь следовать:

  1. если doSomething () не может «сделать что-то», вызывающий должен быть осведомлен об этом
  2. методы должны быть связаны с выполнением одной вещи

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

if(doA()){
  if(doB()){
    if(doC()){ 
      // only here do I know it's good
    }else{
      // I know C failed
    }
  }else{
    // I know B failed
  }
}else{
  // I know A failed
}

Я получаю 5-6 вложений, если-то глубоко в некоторых частях, и это довольно уродливо. Не говоря уже об управлении кучей логических переменных для отслеживания того, что сработало, а что нет.

Есть совет? Будет ли это место, где приемлемо «goto»?

Ответы [ 4 ]

5 голосов
/ 13 апреля 2011

Вы должны заглянуть в doA(), doB() и doC().Если они вряд ли потерпят неудачу, выведите исключение, если они потерпят неудачу.

try {
  doA();
  doB();
  doC();
} catch (FailureException e) {
  // handle failure
}

Примеров необоснованных сбоев предостаточно, IOException, IllegalParameterException и т. Д.Вероятность сбоя

if (!doA()) {
  // handle A's failure
  return;
}
if (!doB()) {
  // handle B's failure
  return;
}
if (!doC()) {
  // handle C's failure
  return;
}

Примеры разумных сбоев в Java чуть менее подчеркнуты.Некоторые примеры включают read(), возвращающий -1, когда больше нечего читать.Если ваш doA() на самом деле назван ближе к attemptA(), то, возможно, будет возвращен boolean, указывающий на успешность попытки.Подумайте о add(...) и addAll(...) в интерфейсе Collections, они возвращают true, если полученный Collection был изменен.

Традиционный goto не является хорошим выбором в большинстве языков,как и при просмотре кода, практически невозможно узнать, откуда этот код «появился».Отсутствие знаний о состоянии до входа в goto делает невозможным гарантировать согласованную среду до входа в блок goto.Кстати, именно поэтому традиционный goto недоступен в Java, и только ограниченное продолжение goto есть.

Чтобы перейти от плохо вложенной структуры к менее вложенной, используйте несколько методов рефакторинга.:

if(doA()){
  if (doB()) {
    if (doC()) { 
      // only here do I know it's good
    } else {
      // I know C failed
    }
  } else {
    // I know B failed
  }
} else {
  // I know A failed
}
return;

эквивалентно

if (doA()) {
  if (doB()) {
    if (doC()) { 
      // only here do I know it's good
    } else {
      // I know C failed
    }
  } else {
    // I know B failed
  }
  return;
} else {
  // I know A failed
  return;
}

, что эквивалентно

if (!doA()) {
  // I know A failed
  return;
} else {
  if (doB()) {
    if (doC()) { 
      // only here do I know it's good
    } else {
      // I know C failed
    }
  } else {
    // I know B failed
  }
  return;
}

Если код в «Я знаю, что Сбой» включает в себя возврат, товам не нужно беспокоиться о том, что код при условии doA() соответствует действительности приведенному ниже коду;так что вы можете продвинуть нижний блок, вот так:

if (!doA()) {
  // I know A failed
  return;
}
if (doB()) {
  if (doC()) { 
    // only here do I know it's good
  } else {
    // I know C failed
  }
} else {
  // I know B failed
}
return;
1 голос
/ 13 апреля 2011

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

Совершенно разумно использовать исключения для управления потоком - в исключительных условиях. Обычная рекомендация - избегать их использования для обычного управления потоком.

0 голосов
/ 13 апреля 2011

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

0 голосов
/ 13 апреля 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...