предисловие
Как должны обрабатываться исключения в Java Эта тема кажется простой, не так ли?try...catch
Ну, но зачастую баги чаще появляются в каких-то простых местах, которые мы скорее проигнорируем.
У большинства зрелых команд разработчиков есть набор норм и рекомендаций по обработке исключений.
В этой статье я собрал 9 лучших практик, которые использует моя команда, в надежде, что они помогут вам в обработке исключений.
1. Используйте finally или попробуйте... с... ресурсом, чтобы закрыть ресурсы
Если нам нужно использовать некоторые ресурсы в блоке кода try, такие какInputStream
, нам нужно закрыть ресурс после его использования.
Вот неправильный пример
public void tryResource() {
FileInputStream inputStream = null;
try {
File file = new File("./小黑说Java.txt");
inputStream = new FileInputStream(file);
// 使用inputStream读取文件
// 不要这样做
inputStream.close();
} catch (FileNotFoundException e) {
log.error("文件未找到", e);
} catch (IOException e) {
log.error("文件读取异常", e);
}
}
В приведенном выше коде, пока нет исключений при чтении файла, этот код работает нормально, но пока код в блоке tryclose()
Если в методе возникнет исключение, ресурс не будет закрыт.
Так что в этом случае мы должны поместить код для закрытия ресурса вfinally
в или использоватьtry...with...resource
утверждение.
использовать наконец
Код в блоке finally выполняется независимо от возникновения исключения, что обеспечивает закрытие объекта ресурса.
public void closeResourceInFinally() {
FileInputStream inputStream = null;
try {
File file = new File("./小黑说Java.txt");
inputStream = new FileInputStream(file);
// 使用inputStream读取文件
} catch (FileNotFoundException e) {
log.error("文件未找到", e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.error("资源关闭异常", e);
}
}
}
}
использовать try...with...resource
Если вы используете JDK версии 1.7+, вы также можете использоватьtry...with...resource
утверждение. Если вы используете реализацию класса ресурсовAutoCloseable
интерфейс, вы можете использовать этот метод.
Большинство стандартных API классов ресурсов в Java реализуют этот интерфейс. Открытие ресурса в предложении try автоматически закроет объект ресурса после выполнения блока try или обработки исключения.
public void useTryWithResource() {
File file = new File("./小黑说Java.txt");
try (FileInputStream inputStream = new FileInputStream(file);) {
// 使用inputStream读取文件
} catch (FileNotFoundException e) {
log.error("文件未找到", e);
} catch (IOException e) {
log.error("文件读取异常", e);
}
}
2. Используйте более явные исключения
Если нашему методу нужно генерировать исключение, чем конкретнее тип исключения, тем лучше. Поскольку другие люди, вызывающие ваш код извне, могут не знать о вашей внутренней логике реализации, убедитесь, что вы предоставили им как можно больше информации, чтобы другим было легче понять, как использовать ваш метод, чтобы вызывающий мог Лучшая обработка брошенных исключения.
Например, в вашем методе content throwNumberFormatException
чем броситьIllegalArgumentException
или сразу броситьException
, смысл будет понятнее.
3. Исключение объясняется в аннотации метода
Если ваш метод объявляет, что может быть выдано исключение, это исключение должно быть описано в комментарии к документации метода. Это то же самое, что и цель предыдущей статьи, которая состоит в том, чтобы позволить вызывающему методу получить больше информации заранее, чтобы он мог избежать исключений при вызове вашего метода или сделать его более понятным, если выполняется обработка исключений.
Поэтому мы должны добавить оператор @throws в комментарий к документации метода и указать, при каких обстоятельствах будет выброшено соответствующее исключение.
/**
* 这个方法内部做了什么什么事情...
*
* @param input
* @throws BusinessException 如果出现xxx情况,则会抛出这个异常
*/
public void doSomething(String input) throws BusinessException {
...
}
4. Несите достаточно описательной информации в исключении
Это похоже на цель двух предыдущих подходов. В исключении содержится достаточно описательной информации, поэтому при возникновении исключения можно увидеть более полезную информацию при просмотре информации об исключении в файле журнала.
Поэтому мы должны как можно точнее описать, почему возникло это исключение, и предоставить наиболее важные данные для поиска другими.
Конечно, здесь не может быть слишком экстремально.Вы пишете небольшое эссе, и вы должны использовать краткое описание информации, чтобы коллеги по эксплуатации и обслуживанию могли понять серьезность проблемы и легче проанализировать проблему.
Не нужно предоставлять кучу лишней избыточной информации, постарайтесь быть достаточно точным. Например, когда вы создаете другой объект Long, если вы передаете строку, она выдаетNumberFormatException
.
public static void testLong() {
try {
Long abc = new Long("ABC");
} catch (NumberFormatException e) {
log.error("格式异常", e);
}
}
NumberFormatException
Имя класса уже говорит нам, что существует исключение форматирования чисел, поэтому вmessage
Только входная строка должна быть предоставлена в . Если имя класса исключений, которое вы определяете, не может четко выразить, что такое исключение, напримерBusinessException
, ты должен бытьmessage
Более подробная информация выражена в.
5. Сначала ловите более явные исключения
Как правило, в используемой нами среде IDE, если вы сначала перехватываете менее конкретное исключение, такое как Exception, а затем перехватываете более конкретное исключение, такое как IOException, когда вы выполняете захват исключения, это подскажет нам, что следующий блок catch недоступен. Таким образом, мы должны сначала захватить наиболее конкретный класс исключений, а затем поставить захват менее конкретного класса исключений.
public void catchExceptions() {
try {
doSomething("小黑说Java");
} catch (NumberFormatException e) {
log.error("格式异常", e);
} catch (IllegalArgumentException e) {
log.error("非法参数", e);
}
}
6. Не ловите Throwable
Throwable
это всеException
а такжеError
родительский класс.
Хотя это может бытьcatch
блок, чтобы поймать его, но мы не должны этого делать. потому что если вы используетеThrowable
, то не только все кинутException
захватывать, а также захватывает всеError
.
И когда наша программа бросаетError
указывает на серьезную проблему, с которой невозможно справиться, например, типичныйOutofMemoryError
,StackOverflowError
подожди, эти двоеError
Оба вызваны ситуациями, которые программа не может контролировать и не может обработать. Так что лучше не быть в вашемcatch
пойманThrowable
, если вы не очень увереныtry
Код в блоке выдает условие исключения, которое можно обработать.
public void catchThrowable() {
try {
// 一些业务代码
} catch (Throwable t) {
// 不要这样做
}
}
7. Не игнорируйте исключения
Вероятно, вы уверены, что при разработке исключений не будет, и это правда, что при разработке исключений не возникает, поэтому вы ничего не делаете с исключением в блоке catch.
public void doNotIgnoreExceptions() {
try {
// 一些业务代码
} catch (NumberFormatException e) {
// 认为永远不会执行到这里
}
}
Однако вы не совсем уверены, что кто-то в будущем добавит новый код в ваш блок try, и он может не осознавать, что добавленный им код вызовет генерацию исключения, что вызовет настоящую строку. но об этом никто не знает.
Итак, вы должны по крайней мере напечатать строку журнала в улове, чтобы сообщить своим коллегам по эксплуатации: «Внимание, здесь маловероятное исключение».
public void doNotIgnoreExceptions() {
try {
// 一些业务代码
} catch (NumberFormatException e) {
log.error("警报,这里出现了一个不可能会出现的异常", e);
}
}
8. Не выдавать исключение после печати лога
Это, вероятно, делает большинство людей.Я видел много кода других людей, выводящего строку журнала исключений при обработке исключений, а затем выбрасывающего исключение или преобразующего его вRuntimeException
бросать.
Он даже появился в некоторых фреймворках с открытым исходным кодом.
public void testCatchEx() {
try {
new Long("heihei");
} catch (NumberFormatException e) {
log.error("数字格式异常", e);
throw e;
}
}
Вы можете подумать, что это интуитивно понятно, и в этом нет ничего плохого, просто позвольте человеку, вызывающему ваш метод, справиться с этим. Однако таким образом в журнале будет напечатано несколько сообщений об ошибках для созданного исключения.
Дубликаты журналов не приносят никакой ценной информации.Ссылаясь на описание в пункте 4 выше, информация об исключении должна содержать достаточную информацию, и она должна быть точной. Если вам нужно добавить другую информацию, вы должны обернуть пойманное исключение в свое пользовательское исключение, прежде чем его генерировать.
public void wrapException(String input) throws BusinessException {
try {
// do something
} catch (NumberFormatException e) {
throw new BusinessException("一段对异常的描述信息.", e);
}
}
Следовательно, мы должны перехватывать исключение только тогда, когда мы хотим его обработать, в противном случае мы должны выбросить его и объяснить перед методом, чтобы вызывающая сторона обработала его.
9. Используйте необработанные исключения при упаковке исключений
Обычно во время разработки проекта будет набор настраиваемых исключений, которые используются для инкапсуляции стандартных исключений в API в настраиваемые исключения, которые можно использовать для некоторой унифицированной обработки исключений на внешнем уровне.
Но когда мы инкапсулируем исходное исключение в пользовательское исключение, нам нужно убедиться, что исходное исключениеcause
Сохраните его в пользовательском исключении, иначе вы потеряете информацию о трассировке стека исходного исключения на внешнем уровне, так что вы не сможете проанализировать конкретную причину создания исключения с помощью информации об исключении.
public void wrapException(String input) throws BusinessException {
try {
// do something
} catch (NumberFormatException e) {
// 将e作为构造参数中的cause
throw new MyBusinessException("一段对异常的描述信息.", e);
}
}
Суммировать
Есть много разных вещей, которые мы должны учитывать при генерации или перехвате исключений, большинство из вышеперечисленных предназначены для улучшения читабельности кода и упрощения использования API для других.
Обычно исключение является не только механизмом обработки ошибок, но и выполняет определенную роль носителя информации. Мы должны следовать этим правилам обработки исключений и лучшим практикам и писать хороший код, который более стандартизирован и не позволит другим жаловаться.
Я Сяо Хей, программист, который «выслеживает» Интернет.
Текущая вода не соревнуется за первое, а говорить дорого