В компютърното програмиране, управлението на изключения или системното администриране на изключения в операционната система (на английски: еxception handling) за софтуера и програмирането процес за справяне с възникващите по време на изпълнение изключения – грешки или неочаквани графични изпълнения на програмата (аномалии) или необикновени условия, изискващи специална обработка, често променящи нормалното протичане на изпълнението на програмата "Exception handling in prolog is done with the catch function.", Exception Handling. Управлението на изключенията се осигурява от специализирани конструктори в езиците за програмиране или механизми на хардуера.
Като цяло, изключение се улавя (обработва) като се запазва текущото състояние на изпълнението на предварително зададено място и се превключва към изпълнение на специфична подпрограма, известна като манипулатор на изключения. Ако изключения са продължаващи, манипулаторът може по-късно да възобнови изпълнението на първоначалното местоположение, с помощта на запазената информация. Например, изключение за стойност с плаваща запетая разделена на нула, по подразбиране, ще позволи на програмата да бъде възобновена, докато недостатъчното състояние на паметта не може да бъде разрешено толкова лесно.
Алтернативни подходи за справяне с изключения в софтуера са проверките за грешки, които поддържат нормалното изпълнение на програмата и по-късно проверяват за отчетени непредвидени случаи, с помощта на специални стойности на връщане или някои спомагателни глобални променливи като errno в C, флагове с плаваща запетая, или валидация на входящите данни за превантивно филтриране на случаите, пораждащи изключения.
Някои програмисти пишат софтуер с функции, докладващи грешки, които събират детайли и могат да бъдат полезни при разрешаването на проблем като покажат тези детайли на екрана или ги съхранят във файл.
Примери Nota bene: примерите са от германското програмиране. Паскал ObjektA := TObjectA.Create; try try BerechneEinkommen(Name); except on E:Exception do begin // Exception wurde abgefangen und wird um einen aussagekräftigen Hinweis ergänzt E.Message := 'Fehler beim Berechnen des Einkommens von ' + Name + #13#10 + E.Message; // ursprüngliche Meldung anhängen raise; // veränderte Exception erneut auslösen end; end; finally FreeAndNil(ObjektA); // dies wird auf jeden Fall ausgeführt end;
C++ try { function1(); function2(); ... } catch (const invalid_argument &e) { cerr << "Falsches Argument: " << e.what() << endl; } catch (const range_error &e) { cerr << "Ungültiger Bereich: " << e.what() << endl; } catch (...) { cerr << "Sonstige Exception" << endl; } C# MessageServiceClient client = new MessageServiceClient("httpEndpoint"); Message message = ... // Message erstellen try { client.AddMessage(message); } catch (FaultException fe) { Console.WriteLine(fe.Message); client.Abort(); } catch (CommunicationException ce) { Console.WriteLine(ce.Message); client.Abort(); } catch (TimeoutException) { client.Abort(); }
Управление на изключения в хардуера Механизмите за управление на изключения в хардуера се обработват от процесора. Едно от функциите му е да открива грешки и да пренасочва потока на програмата към управлението им. Състоянието преди възникването на изключението се запазва в стека.
Управление на изключения в хардуера: IEEE 754 стандарт Управлението на изключения в аритметичния хардуерен стандарт с плаваща запетая IEEE 754 главно се отнася до изключителни условия и дефинира изключението като „събитие, което се случва, когато една операция върху някои конкретни операнди няма изход, подходящ за всяко логическо приложение. Тази операция може да сигнализира едно или повече изключения, като извика управлението по подразбиране или, ако е изрично поискано, алтернативно, дефинирано от езика управление на изключението.“
По подразбиране, IEEE 754 изключенията са възобновими и се обработват чрез заместване на предварително определена стойност за различните изключения, например изключения при безкрайност или делене на нула, предоставяне на флагове за състояние или проверка за настъпване на изключение (виж езика за програмиране C99 за типични примери за управление на IEEE 754 изключения).
Управление на изключения в софтуера Обработката на софтуерни изключения и подкрепата, предоставена от софтуерните инструменти, се различават в известна степен от това, което се разбира под изключения на хардуера, но въпреки това имат подобни концепции. В механизмите за управление на изключения в езиците за програмиране, терминът изключение обикновено се използва за означаване на структура от данни, която съхранява информация за изключителен случай. Един механизъм за прехвърляне на контрол, или предизвикване на изключение, е известен като throw. Ако името на изключението е еквивалентно на това в throw, изпълнението се прехвърля в „catch“.
Предизвикването на изключение е практичен начин за сигнализиране, за това, че програмата не може да се изпълни нормално – например, когато входните данни са невалидни (стойността е извън зададените интервали) или когато ресурс, на който програмата разчита не е достъпен (като липсващ файл, грешка на твърдия диск, или грешка в паметта). В системи, в които няма изключения, програмите ще трябва да върнат специален код за грешка. Това понякога се усложнява от семантични проблеми, при които се изисква допълнителен код, за разграничаване на нормално върнатите стойности от грешните.
Според сравняваща статия през 2006 г. от Joseph R. Kiniry, програмните езици се различават значително в тяхната представа за това, какво е изключение. Според Kiniry, съвременните езици могат да бъдат грубо разделени на две групи: Тези езици, в които изключенията „са създадени, като структури, които контролират входния поток от данни“; според тази статия Ada, C++, Java, Modula-3, ML, OCaml, Python, и Ruby спадат към тази категория Тези езици, в които изключенията „са създадени, за да контролират нетипични, непредсказуеми или грешни ситуации“; според тази статия това включва: C#, Common Lisp, Eiffel, и Modula-2
Kiniry също отбелязва „Език създаден само частично оказва влияние върху управлението на изключения, следователно, и върху начина, по който той се справя с частична или цялостна грешка по време на изпълнение на системата. Другото основно влияние са примерите за използване, обикновено в основните библиотеки и примерите на код в техническите книги, статии, онлайн дискусионни форуми и в стандартите на организацията на код.“.
Съвременните приложения са изправени пред много предизвикателства при проектиране, когато се обмислят стратегиите за обработка на изключенията. Особено в новите приложения на ниво начинания, изключенията често присъстват в процеса. Част от разработването на солидна стратегия за управление на изключения е разпознаване, кога един процес не работи, както и момента в който не може да бъде икономически спасен от софтуерната част от процеса.
Управлението на изключения често не е изпълнено коректно в софтуера, особено, ако има многобройни изключения; анализирането на потока на данни на 5 милиона реда от Java код, показва над 1300 дефекта при улавяне на изключения.
История Управлението на изключения е разработено в Lisp през 1960-те и 1970-те години. Първоначално се появява в LISP 1.5 (1962), къде изключенията се улавят с помощта на ключовата дума ERRSET, която връща стойност NIL в случай на грешка, вместо да прекрати програмата или да включи дебъгера. Предизвикването на изключения е въведено в MacLisp през 60-те години с ключовата дума ERR. Това бързо започва да се използва не само за предизвикване на изключения, но и за контрол на входящия поток и е определено с две нови ключови думи, CATCH и THROW (MacLisp, юни 1972 г.), запазвайки ERRSET и ERR за управление на изключения. Почистващото поведение, което сега се нарича finally е представено първоначално в програмния език NIL (като нова имплементация на LISP) от средата до края на 1970-те като UNWIND-PROTECT. След това е прието и в Common Lisp. По същото време се използва dynamic-wind в Scheme, като метод за справяне с изключенията при затваряне. Първите книги на тема структурирано управление на изключения са Goodenough (1975) и Goodenough (1975). През 80-те управлението на изключения се приема широко от редица езици за програмиране.
Първоначално управлението на софтуерни изключения включва както възобновими изключения (семантика на възобновяване), като повечето хардуерни изключения, така и невъзобновими изключения (семантика на прекратяване). Възобновяването обаче е сметнато за неефективно в практиката през 1970-те и 1980-те години (виж дискусията за C++ стандартизация, цитирана по-долу), и вече не се употреба често, макар че се поддържа от езици за програмиране, като Common Lisp и Dylan.
Семантика на прекратяване Механизмите за обработка на изключения в съвременните езици обикновено са невъзобновими („семантика на прекратяване“), за разлика от хардуерните изключения, при които има възможност за възобновяване. Това се базира на опит от използване и на двете, тъй като има теоретични и практически аргументи в полза и на двете решения; те са широко обсъждани по време на дискусиите за C++ стандартизация през 1989 – 1991 г., което довежда до окончателно решение за семантика на прекратяване. По повод мотивите за такъв дизайн за C++ механизма, Строуструп отбелязва:
На срещата за обсъждане на C++ стандартизацията в Пало Алто през ноември 1991 г., чухме брилянтно кратко изложение на мотивите в полза на семантиката на прекратяване, подкрепени както с личен опит, така и с данни от Джим Мичъл (от Sun, някога от Xerox PARC). Джим бе използвал управление на изключения в половин дузина езици в продължение на период от 20 години и е ранен привърженик на семантиката на възобновяване, като един от основните дизайнери и изпълнители на Cedar/Mesa системата на Xerox. Неговото послание беше:
„Прекратяването се предпочита през възобновяването; това не е въпрос на мнение, а въпрос на години опит. Възобновяване е съблазнително, но не е валидно.“
Той подкрепи това твърдение с данни от няколко операционни системи. Ключовият пример беше Cedar/Mesa: Тя е написана от хора, които обичат и използват възобновяване, но след десет години използване, има само една останала употреба на възобновяване в системата състояща се от половин милион реда – и това е контекстовото запитване. Тъй като не е имало реална необходимост от възобновяването за такова контекстово запитване, те го отстраняват и е установяват значително увеличение на скоростта в тази част на системата. Във всеки случай, в който е използвано възобновяване, през тези десет години, в бъдещето се превръща в проблем, който е заменен от по-подходящ дизайн. На практика, всяка употреба на възобновяване е представена като неспазване на отделните нива на абстракция.
Критика Контрастен поглед върху безопасността на управление на изключения е даден от Ч.А.Р. Хоаре през 1980 г., описващ езика за програмиране Ada като имащи „... множество функции и условни конвенции, много от тях ненужни и някои от тях, като управление на изключения, дори опасни. [...] да не се допуска този език в сегашното си състояние да се използва в приложения, където надеждността е от решаващо значение [...]. следващата заблудена ракета в резултат на грешка на езика за програмиране може да не е на проучвателна космическа ракета на безвредно пътуване до Венера: Тя може да бъде ядрена бойна глава, експлодираща над един от нашите собствени градове.“.
Позовавайки се на множество предишни изследвания от други (1999 – 2004 г.) и на собствените си резултати, Ваймар и Некула пишат, че значителен проблем с изключения е, че те „създаде скрити пътеки за контрол на потоци, които са трудни за разбиране от програмистите“.
Поддръжка на изключенията в езиците за програмиране Вижте също: Синтаксис за обработване на изключения и Специфични за Майкрософт механизми за обработване на изключения