Выход после фатального исключения в основной функции или ниже в иерархии вызовов

Если у меня есть программа, которая вызывает метод, который должен завершаться, если выдается конкретное исключение, должен ли я спроектировать ее таким образом, чтобы исключение передавалось обратно в main, чтобы оно могло безопасно вернуться, или я должен обрабатывать исключение в функции и вызывать System.exit(-1)?

Вот пример того, что я имею в виду, обрабатывая его в функции:

public class MyClass{
     public static void main (String[] args){
        myFunction(args);
     }
     public static void myFunction(String[] args){
          try{
              if(args.length == 0) 
                   throw Exception("Invalid Input");
          }catch(Exception e){
              System.out.println(e);
              System.exit(-1);
          }
     }
 }

Вот пример того, что я имею в виду, говоря об этом:

public class MyClass{
     public static void main (String[] args){
        try{
             myFunction(args);
        }catch(Exception e){ 
             System.out.println(e);
        }
     }
     public static void myFunction(String[] args) throws Exception{
         if(args.length == 0)
              throw Exception("Invalid Input");
     }
 }

Какой способ следует использовать в этой ситуации?


person user1939991    schedule 31.07.2018    source источник
comment
Программа завершится, если вы просто позволите исключению быть перехваченным из main(). Зачем вам перехватывать исключение, если оно фатальное? Кроме того, catch(Exception e){ System.exit(-1); } обычно никогда не бывает хорошей идеей.   -  person Mick Mnemonic    schedule 01.08.2018
comment
Это исключение, которое выдается из-за недопустимого ввода, что не является фатальным для программы, но требует, чтобы я вышел из программы.   -  person user1939991    schedule 01.08.2018
comment
Хорошо, тогда было бы лучше, если бы вы действительно поделились соответствующим кодом.   -  person Mick Mnemonic    schedule 01.08.2018
comment
@MickMnemonic Фактический код длинный, поэтому я изменил пример, чтобы он представлял мою ситуацию. Причина, по которой я выхожу, заключается в том, что программа не может продолжаться, если в примере введены неправильные данные.   -  person user1939991    schedule 01.08.2018
comment
Должен сказать... Это один из самых умных и наводящих на размышления вопросов, которые я когда-либо видел.   -  person Taslim Oseni    schedule 01.08.2018
comment
Прочтите Почему вопрос о «лучшей практике» — это плохо? прежде чем пытаться задавать больше вопросов, основанных на мнениях, которые вызывают спорную дискуссию, потому что у них нет единого согласованного ответа.   -  person    schedule 01.08.2018
comment
Прежде всего основано на мнении. Многие хорошие вопросы в той или иной степени формируют мнение, основанное на экспертном опыте, но ответы на этот вопрос, как правило, почти полностью основаны на мнениях, а не на фактах, ссылках или конкретных опыт. Пожалуйста, прочтите Каких типов вопросов мне следует избегать?, прежде чем задавать дополнительные вопросы.   -  person    schedule 01.08.2018
comment
Как показывает мой ответ, этот вопрос по сути не основан на мнении и имеет ответ, обоснованный техническими соображениями.   -  person Raedwald    schedule 01.08.2018


Ответы (4)


Очень мало причин звонить System.exit. Может быть, если бы возникло какое-то катастрофическое состояние, когда вы захотели бы немедленно остановить JVM, трудно представить, что бы это было. Поэтому я бы сказал, никогда не вызывайте System.exit без каких-либо очень конкретных требований.

Настройте блок try-catch в методе main, перехватите Throwable и зарегистрируйте его. Это сводит к минимуму обработку исключений в других местах программы и поощряет отказоустойчивый способ программирования, чтобы исключения не поглощались и не терялись.

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

Если вы обеспокоены тем, что может быть выдана какая-то ошибка, которую нельзя зарегистрировать (возможно, нам не хватает памяти и мы не можем войти в систему, не вызывая другой ошибки нехватки памяти), добавьте ведение журнала в вызывающую сторону в дополнение к Java. программа делает свою собственную регистрацию, в качестве меры предосторожности.

person Nathan Hughes    schedule 01.08.2018
comment
Итак, поскольку мне нужно выйти здесь, вы бы порекомендовали передать его обратно в main, чтобы зарегистрировать ошибку и безопасно вернуться? - person user1939991; 01.08.2018
comment
@ user1939991: в целом да. Чего вы хотите избежать, так это поймать какое-то исключение слишком близко к источнику, где сейчас программа находится в плохом состоянии, и продолжение оттуда вызовет только больше ошибок. Вы используете исключение, чтобы переместить управление в безопасное место. - person Nathan Hughes; 01.08.2018

Это довольно сложный вопрос для меня, сейчас я просто делюсь некоторыми мыслями.

Есть два основных фактора, о которых вам нужно заботиться:

  1. Это фатально? Вы можете предотвратить уничтожение/закрытие программы?
  2. Можете ли вы сделать что-то с исключением? Запишите полезную информацию? Восстановить его какими-то методами?

No.1

Если это фатально, то вам лучше попытаться убедиться, что программа exit изящно перехватит ее на нужном уровне, возможно, прямо там, где генерируется исключение или выше (что больше зависит от № 2);

No.2

Если вы хотите отслеживать некоторую полезную информацию для отладки или даже для восстановления, если это возможно.

Затем, поймаете ли вы его и обработаете ли его, зависит от вашего проекта/системы.

В качестве примера возьмем обычный случай:

Если вам нужно отслеживать информацию на вызывающем уровне, вы должны поймать исключение на нижнем уровне и сгенерировать исключение, чтобы оно было у вызывающего/более высокого уровня:

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

Другим словом

Пожалуйста, НЕ пытайтесь ввести exception в логику вашего проекта/системы, exception следует рассматривать как исключения, обрабатывающие непредвиденные проблемы.

Извините, что добавляю это, надеюсь, это может быть полезно.

person Hearen    schedule 01.08.2018

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

Во-первых, рассмотрим связанный с этим вопрос "когда вы должны создавать исключение"? правильный ответ на это: "Если и только если альтернативой будет неспособность установить условие публикации или поддерживать инвариант». Это напоминает нам о том, что нужно думать с точки зрения условий публикации метода. Вы предоставляете пример метода разбора аргументов командной строки. Это должно иметь пост-условие «аргументы командной строки действительны». Таким образом, в случае недопустимости аргументов командной строки это правило говорит нам, что метод должен генерировать исключение и не должен завершаться.

Во-вторых, подумайте, зачем вообще нужны исключения. Есть языки программирования без них (в частности, Си). Альтернативой является использование кодов состояния. Одним из преимуществ исключений является то, что они отделяют обнаружение проблем (где вы выдаете исключение) от принятия решения о том, что делать в случае возникновения проблемы (где вы перехватываете исключения). Они предоставляют средства для «продвижения политики вверх», к методам вызова более высокого уровня. Итак, в случае возникновения проблемы (например, недопустимых аргументов командной строки в вашем примере) должна ли программа завершиться? Это вопрос политики, и поэтому он относится к методу более высокого уровня, а не к методу низкого уровня. И тот же аргумент применим ко всем уровням программы: ни один метод не может быть оправдан как завершение программы, реализация самой радикальной возможной политики, потому что вместо этого он может продвигать политику вверх, вызывая исключение. Единственный метод, который не может продвигать политику вверх, — это метод main, потому что у него нет вызывающего объекта, к которому можно было бы продвигать вверх. Это говорит о том, что только основной метод должен вызывать завершение программы. Обратите внимание, что JVM работает таким образом: даже ошибки виртуальной машины, которые вообще не могут быть обработаны и должны привести к завершению программы, приводят к выдаче VirtualMachineError, а не к прямому завершению программы.

person Raedwald    schedule 01.08.2018

Из этот пост:

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

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

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

В этом сообщении также есть полезная информация.

person 0xCursor    schedule 01.08.2018