Я работал над приложением для Android, которое try/catch
часто используется, чтобы предотвратить его сбой даже в тех местах, где в этом нет необходимости. Например,
Ссылка на представление в xml layout
with id = toolbar
выглядит следующим образом:
// see new example below, this one is just confusing
// it seems like I am asking about empty try/catch
try {
View view = findViewById(R.id.toolbar);
}
catch(Exception e) {
}
Этот подход используется во всем приложении. Трассировка стека не печатается, и очень сложно найти, что пошло не так. Приложение внезапно закрывается без вывода трассировки стека.
Я попросил старшего объяснить мне это, и он сказал:
Это сделано для предотвращения сбоев в производстве.
Я полностью с этим не согласен . Для меня это не способ предотвратить сбои приложений. Это показывает, что разработчик не знает, что делает, и сомневается.
Используется ли такой подход в промышленности для предотвращения сбоев корпоративных приложений?
Если try/catch
это действительно так, то можно ли подключить обработчик исключений к потоку пользовательского интерфейса или другим потокам и уловить все там? Если возможно, это будет лучший подход.
Да, пусто try/catch
- это плохо, и даже если мы печатаем трассировку стека или регистрируем исключение на сервере, try/catch
случайная упаковка блоков кода во всем приложении не имеет для меня смысла, например, когда каждая функция заключена в try/catch
.
ОБНОВИТЬ
Поскольку этому вопросу уделяется много внимания, и некоторые люди неверно истолковали его (возможно, потому, что я не сформулировал его четко), я собираюсь перефразировать его.
Вот что здесь делают разработчики
Написана и протестирована функция , это может быть небольшая функция, которая просто инициализирует представления, или сложная, после тестирования она оборачивается вокруг
try/catch
блока. Даже для функции, которая никогда не вызовет исключения.Эта практика используется во всем приложении. Иногда печатается трассировка стека, а иногда просто
debug log
выводится случайное сообщение об ошибке. Это сообщение об ошибке отличается от разработчика к разработчику.При таком подходе приложение не аварийно завершает работу, но поведение приложения становится неопределенным. Иногда даже трудно понять, что пошло не так.
Настоящий вопрос, который я задавал: Применяется ли в отрасли практика предотвращения сбоев корпоративных приложений? и я не спрашиваю о пустом try / catch . Это похоже на то, что пользователи любят приложения, которые не дают сбоев, чем приложения, которые ведут себя неожиданно? Потому что на самом деле это сводится к тому, чтобы либо вывести его из строя, либо предоставить пользователю пустой экран, либо поведение, о котором пользователь не знает.
Я размещаю здесь несколько фрагментов настоящего кода
private void makeRequestForForgetPassword() { try { HashMap<String, Object> params = new HashMap<>(); String email= CurrentUserData.msisdn; params.put("email", "blabla"); params.put("new_password", password); NetworkProcess networkProcessForgetStep = new NetworkProcess( serviceCallListenerForgotPasswordStep, ForgotPassword.this); networkProcessForgetStep.serviceProcessing(params, Constants.API_FORGOT_PASSWORD); } catch (Exception e) { e.printStackTrace(); } } private void languagePopUpDialog(View view) { try { PopupWindow popupwindow_obj = popupDisplay(); popupwindow_obj.showAsDropDown(view, -50, 0); } catch (Exception e) { e.printStackTrace(); } } void reloadActivity() { try { onCreateProcess(); } catch (Exception e) { } }
Это не дубликат лучших практик обработки исключений Android , OP пытается перехватить исключение для другой цели, чем этот вопрос.
источник
catch(Exception e){}
- этот комментарий имел смысл до редактирования вопросаON ERROR RESUME NEXT
Ответы:
Конечно, всегда есть исключения из правил, но если вам нужно практическое правило - тогда вы правы; пустые блоки catch - это «абсолютно» плохая практика.
Давайте рассмотрим подробнее, начав с вашего конкретного примера:
try { View view = findViewById(R.id.toolbar); } catch(Exception e) { }
Итак, ссылка на что-то создается; а когда это не удается ... это не имеет значения; потому что эта ссылка вообще не используется! Приведенный выше код - это абсолютно бесполезный линейный шум . Или человек, который написал этот код, изначально предполагает, что второй подобный вызов волшебным образом больше не вызовет исключения?
Возможно, это должно было выглядеть так:
try { View view = findViewById(R.id.toolbar); ... and now do something with that view variable ... } catch(Exception e) { }
Но опять же, чем это помогает ?! Существуют исключения, чтобы сообщать или распространять ошибочные ситуации в коде. Игнорирование ошибок редко бывает хорошей идеей. Фактически, исключение можно обрабатывать следующим образом:
Короче говоря: минимальное , что вы делаете с исключением, - это регистрировать / отслеживать их; так что, когда вы позже приступите к отладке какой-либо проблемы, вы поймете: «Хорошо, в этот момент произошло исключение».
И, как указывали другие: вы также избегаете перехвата для исключения в целом (ну, в зависимости от уровня: могут быть веские причины иметь некоторый перехват для исключения и даже некоторые виды ошибок на самом высоком уровне, чтобы убедиться, что ничего не теряется; никогда ).
Наконец, процитируем Уорда Каннингема:
Вы знаете, что работаете с чистым кодом, когда каждая прочитанная вами процедура оказывается примерно такой, как вы ожидали. Вы можете назвать это красивым кодом, если он также делает вид, будто язык был создан для решения проблемы.
Позвольте этому погрузиться и медитируйте над этим. Чистый код вас не удивляет. Пример, который вы нам показываете, удивляет всех .
Обновление , касающееся обновления, о котором спрашивает ОП
try { do something } catch(Exception e) { print stacktrace }
Тот же ответ: делать это «повсюду» - тоже плохая практика. Потому что этот код также удивляет читателя.
Выше:
Итак, используя try / catch как «образец», как вы показываете; как сказано: все еще не очень хорошая идея. И да, это предотвращает сбои; но приводит ко всем видам "неопределенного" поведения. Вы знаете, когда вы просто перехватываете исключение вместо того, чтобы правильно с ним справляться; вы открываете банку с червями; потому что вы можете столкнуться с мириадами последующих ошибок, которые позже не поймете. Потому что вы использовали событие «первопричина» раньше; где-то распечатал; и этого куда-то теперь нет.
источник
Из документации Android :
Назовем это как -
Форматирование / разбиение на абзацы слегка изменено по сравнению с источником для этого ответа.
PS Не бойтесь исключений !! Они друзья!!!
источник
Object a; try { a = thing(); } catch (Exception e) {...} try { a.action(); } catch (Exception e) {...}
))Exception
перехват универсального кода может быть полезен как часть системы «журнал до сбоя», хотя в этом случае он должен быть выполнен заново.Я бы поставил это как комментарий к другому ответу, но у меня пока нет репутации для этого.
Вы правы, говоря, что это плохая практика, на самом деле то, что вы опубликовали, показывает различные виды плохой практики в отношении исключений.
Я попытаюсь объяснить все это на этом примере.
try { User user = loadUserFromWeb(); if(user.getCountry().equals("us")) { enableExtraFields(); } fillFields(user); } catch (Exception e) { }
Это может привести к сбою по нескольким причинам, с которыми следует обращаться по-разному.
Решения
(1) Во-первых, молчаливый провал - это нехорошо. В случае сбоя приложение не будет работать. Вместо этого должна быть попытка решить проблему или отобразить предупреждение, например, «Не удалось загрузить данные пользователя, возможно, вы не подключены к Интернету?». Если приложение не выполняет то, что должно, для пользователя это больше разочаровывает, чем если бы оно просто закрылось.
(4) Если Пользователь является неполным, например, страна не известна и возвращает null. Метод equals создаст исключение NullPointerException. Если этот NPE просто брошен и пойман, как указано выше, метод fillFields (пользовательский) не будет вызываться, даже если он все еще может выполняться без проблем. Вы можете предотвратить это, включив нулевые проверки, изменив порядок выполнения или настроив область действия try / catch. (Или вы можете сохранить код, например: "us" .equals (user.getCountry ()), но я должен был предоставить пример). Конечно, любое другое исключение также предотвратит выполнение fillFields (), но если пользователя нет, вы, вероятно, все равно не захотите, чтобы он выполнялся.
(1, 2, 3) Загрузка из Интернета часто вызывает множество исключений, от исключения IOException до исключения HttpMessageNotReadable и даже просто возврата. Возможно, пользователь не подключен к Интернету, возможно, произошли изменения на внутреннем сервере или он не работает, но вы не знаете, потому что вы перехватываете (Исключение) - вместо этого вы должны перехватить определенные исключения. Вы даже можете поймать несколько таких
try{ User user = loadUserFromWeb(); //throws NoInternetException, ServerNotAvailableException or returns null if user does not exist if(user == null) { throw new UserDoesNotExistException(); //there might be better options to solve this, but it highlights how exceptions can be used. } fillFields(user); if("us".equals(user.getCountry()) { enableExtraFields(); } } catch(NoInternetException e){ displayWarning("Your internet conneciton is down :("); } catch(ServerNotAvailableException e){ displayWarning("Seems like our server is having trouble, try again later."); } catch(UserDoesNotExistException e){ startCreateUserActivity(); }
Надеюсь, это объясняет.
По крайней мере, в качестве быстрого исправления вы могли бы отправить событие на свой сервер с исключением. Например, через firebase или crashlytics. Таким образом, вы можете по крайней мере увидеть такие вещи, как (эй, основное действие не загружается для 80% наших пользователей из-за проблемы вроде (4).
источник
Это определенно плохая практика программирования.
Из текущего сценария, если есть сотни
try
catch
, вы даже не узнаете, где возникает исключение, без отладки приложения, что является кошмаром, если ваше приложение находится в производственной среде.Но вы можете включить регистратор, чтобы знать, когда возникает исключение (и почему). Это не изменит ваш обычный рабочий процесс.
... try { View view = findViewById(R.id.toolbar); }catch(Exception e){ logger.log(Level.SEVERE, "an exception was thrown", e); } ...
источник
Это плохая практика. В других ответах говорилось об этом, но я думаю, что важно отступить и понять, почему у нас вообще есть исключения.
Каждая функция имеет постусловие - набор вещей, которые должны выполняться после выполнения этой функции. Например, функция, которая читает из файла, имеет условие post, что данные в файле будут считаны с диска и возвращены. Таким образом, возникает исключение, когда функция не может удовлетворить одно из своих постусловий.
Игнорируя исключение из функции (или даже эффективно игнорируя его, просто регистрируя исключение), вы говорите, что вас устраивает то, что эта функция фактически не выполняет всю работу, которую она согласилась сделать. Это кажется маловероятным - если функция работает некорректно, нет никакой гарантии, что все последующее будет работать вообще. И если остальная часть вашего кода работает нормально, независимо от того, работает ли конкретная функция до конца, тогда возникает вопрос, почему у вас вообще есть эта функция.
[Теперь есть определенные случаи, когда пустые
catch
es допустимы. Например, ведение журнала - это то, что вы можете оправдать заключением в пустой улов. Ваше приложение, вероятно, будет нормально работать, даже если некоторые записи журнала не могут быть записаны. Но это особые случаи, над которыми вам придется очень много работать, чтобы найти их в обычном приложении.]Дело в том, что это плохая практика, потому что она фактически не поддерживает работу вашего приложения (предполагаемое оправдание этого стиля). Возможно технически ОС его не убила. Но маловероятно, что приложение по-прежнему работает должным образом после простого игнорирования исключения. А в худшем случае это могло действительно причинить вред (например, повредить файлы пользователя и т. Д.).
источник
Это плохо по нескольким причинам:
findViewById
вызывает исключение? Исправьте это (и скажите мне, потому что я этого никогда не видел) вместо того, чтобы ловить.Exception
когда вы можете поймать определенный тип исключения.Если приложение переходит в плохое состояние, гораздо лучше для него аварийное завершение работы, чем для того, чтобы оно продолжало работать в непригодном для использования состоянии. Когда кто-то видит NPE, не следует просто вставлять нулевой чек и уходить. Лучший подход - выяснить, почему что-то имеет значение NULL, и либо остановить его от значения NULL, либо (если значение NULL оказывается допустимым и ожидаемым состоянием) проверить наличие NULL. Но вы должны понять, почему проблема возникает в первую очередь.
источник
Я разрабатываю приложения для Android в течение последних 4-5 лет и никогда не использовал try catch для инициализации представления.
Если это панель инструментов, как это
например: - Чтобы получить TextView из представления (фрагмент / диалог / любое настраиваемое представление)
TextView textview = (TextView) view.findViewById (R.id.viewId);
вместо этого
Объект просмотра имеет минимальный охват по сравнению с его реальным типом представления.
Примечание: - Возможно, произошел сбой из-за загрузки представления. Но добавление try catch - плохая практика.
источник
View
которые могут быть уже полезными (например,setVisibility()
), без точного указания того, какой именно класс используется. (например, в случае макета, который может время от времениДа, try / catch используется для предотвращения сбоя приложения, но вам, конечно, не нужен try / catch для получения представления из XML, как показано в вашем вопросе.
try / catch обычно используется при выполнении любого HTTP-запроса, при синтаксическом разборе любой строки на URL-адрес, создании URL-соединений и т. д., а также при печати трассировки стека. Не печатать его не имеет особого смысла в окружении try / catch.
источник
Как было сказано ранее, общие исключения не следует улавливать, или, по крайней мере, только в нескольких центральных местах (обычно расположенных в коде фреймворка / инфраструктуры, а не в коде приложения). При обнаружении общих исключений и их регистрации приложение должно быть затем закрыто или, по крайней мере, пользователь должен быть проинформирован о том, что приложение потенциально находится в нестабильном состоянии и может произойти повреждение данных (если пользователь решит продолжить выполнение). Потому что это то, что может произойти, если вы перехватите все виды исключений (нехватки памяти, чтобы назвать одно) и оставите приложение в неопределенном состоянии.
ИМХО, хуже проглотить исключения и рискнуть целостностью данных, потерей данных или просто оставить приложение в неопределенном состоянии, чем позволить приложению вылететь из строя, а пользователь знает, что что-то пошло не так, и может попробовать снова. Это также приведет к лучшему сообщению о проблемах (больше в корне проблемы), возможно, к меньшему количеству различных симптомов, чем если бы ваши пользователи начали сообщать о всех проблемах, происходящих из неопределенного состояния приложения.
После того, как будет создана централизованная обработка исключений / ведение журнала / отчетность и контролируемое завершение работы, начните переписывать обработку исключений, чтобы улавливать локальные исключения как можно более конкретно. Постарайтесь сделать блок try {} как можно короче.
источник
Позвольте мне добавить свою точку зрения как парень, работающий в индустрии корпоративной мобильной разработки более десяти лет. Во-первых, несколько общих советов по исключениям, большинство из которых включены в ответы выше:
Теперь, когда вы разрабатываете приложение не для себя, а для компании или корпорации, часто возникают дополнительные требования по этой теме:
Итак, краткий ответ заключается в том, что код, который вы нашли, не является примером хорошей практики, поскольку его сложно и дорого поддерживать без улучшения качества приложения.
источник
Другая точка зрения: как человек, ежедневно создающий корпоративное программное обеспечение, если в приложении есть неустранимая ошибка, я хочу , чтобы оно вылетало. Сбой желателен. Если происходит сбой, он регистрируется. Если он дает сбой более нескольких раз за короткий промежуток времени, я получаю электронное письмо о том, что приложение дает сбой, и могу проверить, что наше приложение и все используемые нами веб-службы все еще работают.
Итак, вопрос:
Является
try{ someMethod(); }catch(Exception e){}
хорошая практика? Нет! Вот несколько моментов:
САМАЯ важная вещь: это плохой клиентский опыт. Как мне узнать, что происходит что-то плохое? Мои клиенты пытаются использовать мое приложение, но ничего не работает. Они не могут проверить свой банковский счет, оплачивать счета, что бы ни делало мое приложение. Мое приложение совершенно бесполезно, но, по крайней мере, оно не вылетало! (Часть меня считает, что этот «старший» разработчик получает баллы за низкое количество сбоев, поэтому они играют в систему.)
Когда я занимаюсь разработкой и пишу плохой код, если я просто перехватываю и проглатываю все исключения на верхнем уровне, у меня нет регистрации. У меня ничего нет в консоли, и мое приложение выдает ошибку без предупреждения. Насколько я могу судить, все работает нормально. Итак, я фиксирую код ... Оказывается, мой объект DAO все время был нулевым, а платежи клиентов никогда не обновлялись в БД. Ой! Но мое приложение не вылетело, так что это плюс.
Играя в адвоката дьявола, скажем, я нормально ловил и проглатывал каждое исключение. Это очень легко написать обработчик исключений в Android. Если вам действительно нужно перехватывать каждое исключение, вы можете сделать это в одном месте, а не перетирать
try/catch
всю кодовую базу.Некоторые разработчики, с которыми я работал в прошлом, считали, что сбой - это плохо.
Я должен заверить их, что мы хотим, чтобы наше приложение вылетало. Нет, нестабильное приложение - это не нормально, но сбой означает, что мы сделали что-то не так и нам нужно это исправить. Чем быстрее он выйдет из строя, чем раньше мы его обнаружим, тем легче его исправить. Единственный другой вариант, о котором я могу думать, - это позволить пользователю продолжить прерванный сеанс, что я приравниваю к раздражению моей пользовательской базы.
источник
Это плохая практика,
catch(Exception e){}
потому что вы по сути игнорируете ошибку. Вероятно, вы захотите сделать что-то вроде:try { //run code that could crash here } catch (Exception e) { System.out.println(e.getMessage()); }
источник
Мы в значительной степени используем вашу логику. Используйте
try-catch
для предотвращения сбоев рабочих приложений.Исключения НИКОГДА не следует игнорировать. Это плохая практика кодирования. Ребятам, обслуживающим код, будет очень сложно локализовать часть кода, которая вызвала исключение, если они не зарегистрированы.
Мы используем
Crashlytics
для регистрации исключений. Код не выйдет из строя (но некоторые функции будут нарушены). Но вы получаете журнал исключений на панели инструментовFabric/Crashlytics
. Вы можете посмотреть эти журналы и исправить исключения.try { codeThatCouldRaiseError(); } catch (Exception e) { e.printStackTrace(); Crashlytics.logException(e); }
источник
Хотя я согласен с другими ответами, есть одно обстоятельство, с которым я неоднократно сталкивался, когда этот мотив является незначительным. Предположим, кто-то написал небольшой код для класса следующим образом:
private int foo=0; . . . public int getFoo() throws SomeException { return foo; }
В этом случае метод getFoo () не может дать сбой - всегда будет возвращено допустимое значение частного поля foo. Однако кто-то - вероятно, из педантичных соображений - решил, что этот метод следует объявить как потенциально генерирующий исключение. Если вы затем попытаетесь вызвать этот метод в контексте - например, обработчике событий - который не позволяет генерировать исключение, вы в основном вынуждены использовать эту конструкцию (даже в этом случае я согласен, что нужно хотя бы регистрировать исключение только на всякий случай) . Всякий раз, когда мне приходится это делать, я всегда по крайней мере добавляю большой жирный комментарий «ЭТО НЕ МОЖЕТ ПРОИЗОЙТИ» рядом с предложением «catch».
источник