- PVSM.RU - https://www.pvsm.ru -
Некоторое время назад мой коллега опубликовал статью [1] про обработку ошибок в Java/Kotlin. И мне стало интересно, а какие вообще в программировании существуют способы передачи ошибок. Если вам тоже интересно, то под катом результат изысканий. Скорее всего, какие-то экзотические методы пропущены, но тут одна надежда на комментарии, которые на Хабре порою бывают интереснее и полезнее самой статьи. :)
За всю историю языков программирования было придумано не так уж много способов передать ошибку. Если совсем абстрагироваться, то их всего три: непосредственный возврат из функции, передача управления и выставление состояния. Всё остальное — это, в той или иной степени, смешение данных подходов. Ниже я постарался собрать и описать основных представителей этих трёх видов.
Disclaimer: для краткости и упрощения восприятия для любого изолированного выполняющегося кода, порождающего ошибку, я буду использовать слово «функция», а для любой не примитивной (integer, string, boolean, etc…) сущности — «структура».
С непосредственным возвратом всё просто. Хотя это, наверное, самый часто используемый способ, но и тут есть множество вариантов. Объединяет их всех способ обработки — сравнение возвращаемого значения с предопределёнными значениями.
C/C++
Функция strchr() возвращает указатель на первое вхождение символа ch в строку, на которую указывает str. Если символ ch не найден, возвращается NULL.
Довольно часто подходы 1 и 2 используют совместно с выставлением состояния.
function countElements(param) {
if (!isArray(param)) {
return -10;
} else if(!isInitialized(param)){
return -20
} else {
return count(array);
}
}
sealed class UserProfileResult {
data class Success(val userProfile: UserProfileDTO) : UserProfileResult()
data class Error(val message: String, val cause: Exception? = null) : UserProfileResult()
}
val avatarUrl = when (val result = client.requestUserProfile(userId)) {
is UserProfileResult.Success -> result.userProfile.avatarUrl
is UserProfileResult.Error -> "http://domain.com/defaultAvatar.png"
}
Также можно вспомнить Either из мира функционального программирования. Хотя тут можно и поспорить.
function doSomething(): array {
...
if($somethingWrong === true) {
return ["result" => null, "error" => "Alarm!!!"];
} else {
return ["result" => $result, "error" => null];
}
...
}
f, err := Sqrt(-1)
if err != nil {
fmt.Println(err)
}
Самый старый и хардкорный вариант, не потерявший своей актуальности и поныне. Заключается он в том, что функция ничего не возвращает, а в случае ошибки записывает её значение (в любом виде) в отдельную сущность, будь то регистр процессора, глобальная переменная или приватное поле класса. Для обработки такого рода ошибок требуется самостоятельно извлечь значение из нужного места и проверить его.
# ls /unknown/path 2>/dev/null
# echo $?
1
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
$result = $mysqli->query("SET a=1");
if ($mysqli->errno) {
printf("Код ошибки: %dn", $mysqli->errno);
}
Response response = client.newCall("https://www.google.com").execute();
Integer errorCode = response.getCode();
И вот мы подошли к самой модной парадигме. Исключения, колбэки, глобальные обработчики ошибок — всё вот это вот. Объединяет их всех то, что в случае возникновения ошибки управление передаётся заранее предопределённому обработчику, а не коду, вызвавшему функцию.
function myErrorHandler($errno, $errstr, $errfile, $errline) {
echo "<b>Custom error:</b> [$errno] $errstr<br>";
echo " Error on line $errline in $errfile<br>";
}
set_error_handler("myErrorHandler");
var observer = Rx.Observer.create(
x => console.log(`onNext: ${x}`),
e => console.log(`onError: ${e}`),
() => console.log('onCompleted'));
Вроде бы ничего не забыл.
И забавный факт. Наверное, самый оригинальный способ возврата ошибки, сочетающий в себе одновременно исключения, выставление состояния и возврат нескольких значений, мне встречался в Informix SPL (пишу по памяти):
CREATE PROCEDURE some_proc(...)
RETURNING int, int, int, int;
…
ON EXCEPTION SET SQLERR, ISAMERR
RETURN 0, SQLERR, ISAMERR, USRERR;
END EXCEPTION;
LET USRERR = 1;
-- do Something That May Raise Exception
LET USRERR = 2;
-- do Something Other That May Raise Exception
…
RETURN result, 0, 0, 0;
END PROCEDURE
Автор: Громов Андрей
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/334068
Ссылки в тексте:
[1] статью: https://habr.com/ru/company/funcorp/blog/471766/
[2] Источник: https://habr.com/ru/post/472506/?utm_source=habrahabr&utm_medium=rss&utm_campaign=472506
Нажмите здесь для печати.