В большинстве современных языков высокого уровня предусмотрен механизм исключений.
В машинном коде процессоров x86 и многих других существует механизм, также называемый исключениями. Через него осуществляется много полезных вещей, таких как виртуальная память, отображаемые на память файлы, эмуляция не поддерживаемых аппаратно инструкций (использовалось на VAX, где решено было сократить систему команд процессора и эмулировать редко используемые команды, использовалось на x86 без FPU, используется в NTVDM), отладочные функции и т.д. Если среда и язык не поддерживают такие механизмы, то реализация кода, используещего ту же функциональность, была бы в значительно длинее.
В отличие от процессорных исключений, в языковых исключениях управление передается "наверх" до внешнего блока, который "поймает" исключение (в ЛИСПе более богатая модель, но в большинстве языков этого нет). При этом контекст, в котором произошла ошибка, будет уничтожен. Что уже делает этот механизм непригодным для реализации ряда "вкусностей". Есть и другие проблемы. Например, отловить момент, когда не хватает памяти, по таким исключениям невозможно -- в средах с виртуальной памятью выделение памяти всегда завершается успешно, а ошибка возникает при попытке обращения к ней.
Может быть, я просто не видел области применения, где исключения действительно делали жизнь проще, но где же польза от исключений?