Хабрахабр

[Из песочницы] Почему следует избегать использования исключений в управлении вашим потоком в Java

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

Этого следует избегать по двум причинам: Один из наиболее распространённых неудачных подходов — это использование исключений для контроля потока выполнения.

  1. Это снижает производительность и быстродействие вашего кода
  2. Это делает ваш код менее читаемым

Давайте начнём с рассмотрения примера. Здесь исключение используется для управления потоком выполнения:

public static int findAge(String name) catch (NameNotFoundException e) { return 0; } } private static String findUser(String name) { if(name==null) { throw new NameNotFoundException(); } return name; }

Если пользователь предоставит не нулевое значение имени, то метод findAge вернёт длину этого имени, но если имя пользователя будет null, то тогда метод findUser выбросит исключение NameNotFoundException и в этом случае метод findAge вернёт 0.

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

public static int findAgeNoEx(String name) { String ageAsString = findUserNoEx(name); return ageAsString.length(); } private static String findUserNoEx(String name) { if(name==null) { return ""; } return name; }

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

public class ControlFlowWithExceptionOrNot { public static class NameNotFoundException extends RuntimeException { private static final long serialVersionUID = 3L; } private static final int TRIAL = 10000000; public static void main(String[] args) throws InterruptedException { long start = System.currentTimeMillis(); for (int i = 0; i < TRIAL; i++) { findAgeNoEx(null); } System.out.println("Duration :" + (System.currentTimeMillis() - start)); long start2 = System.currentTimeMillis(); for (int i = 0; i < TRIAL; i++) { findAge(null); } System.out.println("Duration :" + (System.currentTimeMillis() - start2)); }; public static int findAge(String name) { try { String ageAsString = findUser(name); return ageAsString.length(); } catch (NameNotFoundException e) { return 0; } } private static String findUser(String name) { if (name == null) { throw new NameNotFoundException(); } return name; } public static int findAgeNoEx(String name) { String ageAsString = findUserNoEx(name); return ageAsString.length(); } private static String findUserNoEx(String name) { if (name == null) { return ""; } return name; }
}

Вывод:

Duration :16
Duration :6212

Как видно, использование исключения обошлось нам в тысячи миллисекунд на моём Intel Core i7-3630QM.

В то же время, метод с исключением несколько запутанный: не до конца ясно что именно возвращает метод findUser. Если мы сравним два наших findAge метода с точки зрения читабельности, то метод без исключения абсолютно понятен: во-первых мы может быть абсолютно уверены, что метод findUser возвращает строку; а во-вторых независимо от того, какая именно строка будет возвращена, мы получим её длину. По этой причине парадигма функционального программирования не приветствует использование исключений. Он может вернуть строку, а может и выбросить исключение и из сигнатуры метода этого не видно.

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

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

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть