Try с catch: try…catch — JavaScript | MDN

C++ | Вложенные try-catch

Последнее обновление: 17.03.2023

Одни конструкции try-catch могут содержать другие. Если исключение возникает во вложенной конструкции try-catch, то программа сначала ищет во вложенной конструкции
блок catch, который обрабатывает нужный тип исключения. Если во вложенной конструкции try-catch такой блок catch не найден, то программа начинает искать аналогичный блок catch во внешей
конструкии try-catch. Посмотрим на примере.


#include <iostream>

double divide(int a, int b)
{
    if(!b)  // если b == 0
    {
        throw "Division by zero";
    }
	return a / b;
}
int main()
{
    try
    {
        try
        {
            int a{10}, b{};
            double result {divide(a, b)};
            std::cout << result << std::endl;
        }
        catch (const char* error)
        {
            std::cout << "Inner execption: " << error << std::endl;
        }
        std::cout << "Inner try-catch finished" << std::endl;
    }
    catch (const char* error)
    {
        std::cout << "External execption: " << error << std::endl;
    }
    std::cout << "External try-catch finished" << std::endl;
}

Здесь функция divide() вызывается во внутренней конструкции try-catch. Оператор throw генерирует исключение, объект которого представляет строковый литерал — тип const char*.
Во вложенной конструкции try-catch есть такой блок catch, который обрабатывает исключения типа const chat*. И выполнения этого блока catch программа продолжает свой
обычный ход работы, а блок catch во внешей конструкции try-catch НЕ выполняется. В итоге будет следующий консольный вывод:


Inner execption: Division by zero
Inner try-catch finished
External try-catch finished

Теперь возьмем другую ситуацию — во вложенной конструкции try-catch нет нужного блока catch:


#include <iostream>

double divide(int a, int b)
{
    if(!b)  // если b == 0
    {
        throw "Division by zero";
    }
	return a / b;
}
int main()
{
    try
    {
        try
        {
            int a{10}, b{};
            double result {divide(a, b)};
            std::cout << result << std::endl;
        }
        catch (unsigned error)
        {
            std::cout << "Inner execption: " << error << std::endl;
        }
        std::cout << "Inner try-catch finished" << std::endl;	// эта строка не выполняется
    }
    catch (const char* error)
    {
        std::cout << "External execption: " << error << std::endl;
    }
    std::cout << "External try-catch finished" << std::endl;
}

Фактически это тот же самый пример, только теперь блок catch во вложенной конструкции обрабатывает исключения типа unsigned. В итоге, когда будет сгенерировано исключение,
вложенная конструкция не сможет найти нужный блок catch для обработки исключения типа const char*. Поэтому выполнение выполнение программы переходит в блок
catch внешней конструкции try-catch, который обрабатывает исключения типа const char*. Поэтому консольный вывод будет другим


External execption: Division by zero
External try-catch finished

НазадСодержаниеВперед

try…catch — JavaScript — Дока

Кратко

Скопировано

Конструкция try...catch позволяет выполнить произвольный код, но если в нем произошла ошибка, то программа не остановит своё выполнение, а перейдёт в блок catch, где ошибку можно обработать.

Как понять

Скопировано

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

В JavaScript ситуация ещё сложнее. Если во время работы скрипта возникла ошибка и она не была обработана, то выполнение останавливается, и программа больше не работает.

Конструкция try...catch делает программы стабильнее — в случае ошибки мы можем продолжить выполнение. Мы можем написать любой синтаксически верный код и, если он выполнится без ошибок, то отлично. Если же что-то пойдёт не так, то выполнится код, написанный в catch.

Представьте, что вы тренируетесь отбивать мяч в бейсбол. У вас есть партнёр, который будет ловить мяч, в случае вашей ошибки, если отбить мяч не удастся. В большинстве попыток у вас все будет получаться хорошо, но если же случится промах, то второй игрок поймает мяч и вернёт его на место, чтобы можно было попробовать снова.

С пойманной в catch ошибкой можно поступить как угодно: отправить данные в специальный логгер, обработать данные из неё и даже выбросить новую ошибку, которая может быть поймана в другом месте и т.д.

Как пишется

Скопировано

Базовый случай

Скопировано

Чтобы использовать try...catch, необходимо в блоке try написать код, который нужно исполнить, а в блоке catch написать, что делать в случае ошибки.

try {  someFunction()  anotherFunction()} catch (err) {  console.log('Поймали ошибку! Вот она: ', err.message)}
          try {
  someFunction()
  anotherFunction()
} catch (err) {
  console.log('Поймали ошибку! Вот она: ', err.message)
}

Если в блоке try не произошло ошибок, то код в блоке catch не выполнится.

Важно помнить, что код в try должен быть синтаксически верным. Если написать невалидный код (например, не закрыть фигурные скобки), то скрипт не запустится, потому что JavaScript не поймёт код. Ошибки, которые обработает блок catch, будут ошибками во время выполнения программы.

В случае ошибки выполнение в блоке try прерывается и сразу же переходит в блок catch . После него скрипт продолжит своё выполнение, как и прежде.

try {  const six = 6 // 1. Создаём константу  console.log(six) // 2. Выведет 6  six = 7 // Ошибка! Присваиваем новое значение в const  // с этого места управление переходит в catch  const nine = 9 // не выполнится  console.log(six + nine) // и это тоже не исполнится} catch (err) {  console.log('Поймали ошибку!') // 3. Обработали ошибку}console.log('Что ж, можно и продолжать') // 4. Будет выполняться дальше
          try {
  const six = 6 // 1. Создаём константу
  console.log(six) // 2. Выведет 6
  six = 7 // Ошибка! Присваиваем новое значение в const
  // с этого места управление переходит в catch
  const nine = 9 // не выполнится
  console. log(six + nine) // и это тоже не исполнится
} catch (err) {
  console.log('Поймали ошибку!') // 3. Обработали ошибку
}
console.log('Что ж, можно и продолжать') // 4. Будет выполняться дальше

finally

Скопировано

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

try {  // подключаемся к вебсокету, но в конце нужно обязательно отключиться  webSocket.connect('ws://....')  callMayThrowError()} catch (err) {  ...}// Пробуем отключаться после try...catchwebSocket.disconnect('ws://....')
          try {
  // подключаемся к вебсокету, но в конце нужно обязательно отключиться
  webSocket.connect('ws://....')
  callMayThrowError()
} catch (err) {
  ...
}
// Пробуем отключаться после try...catch
webSocket.disconnect('ws://....')

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

function doSomeWithError(e) {  throw new Error('new error')}try {  // подключаемся к вебсокету, но в конце нужно обязательно отключиться  webSocket.connect('ws://....')  callMayThrowError()} catch (err) {  // Здесь тоже может возникнуть ошибка  doSomeWithError(err)}// В случае ошибки эта строчка уже не выполнитсяwebSocket.disconnect('ws://....')
          function doSomeWithError(e) {
  throw new Error('new error')
}
try {
  // подключаемся к вебсокету, но в конце нужно обязательно отключиться
  webSocket.connect('ws://....')
  callMayThrowError()
} catch (err) {
  // Здесь тоже может возникнуть ошибка
  doSomeWithError(err)
}
// В случае ошибки эта строчка уже не выполнится
webSocket.disconnect('ws://....')

Как же тогда гарантированно освободить ресурсы при любом исходе выполнения?

В конструкцию try.. .catch можно добавить блок finally, который выполнится после блоков try и catch. Неважно какой код выполнился в предыдущих блоках, после их завершения (даже если из catch была выброшена новая ошибка) исполнится код в блоке finally.

try {  webSocket.connect('ws://....')  callMayThrowError()} catch (err) {  // Здесь тоже может возникнуть ошибка  doSomeWithError(err)} finally {  // Выполнится всегда  webSocket.disconnect('ws://....')}
          try {
  webSocket.connect('ws://....')
  callMayThrowError()
} catch (err) {
  // Здесь тоже может возникнуть ошибка
  doSomeWithError(err)
} finally {
  // Выполнится всегда
  webSocket.disconnect('ws://....')
}

Наличие блока finally необязательно. finally можно использовать и без блока catch.

try {  // Отправить данные на сервер, здесь нам неважна обработка ошибки  sendData()} finally {  // Закрыть соединение при любом результате  closeConnection()}
          try {
  // Отправить данные на сервер, здесь нам неважна обработка ошибки
  sendData()
} finally {
  // Закрыть соединение при любом результате
  closeConnection()
}

Ошибки в catch

Скопировано

Может возникнуть ситуация, когда скрипт обработки ошибки тоже может сломаться. При этом могут возникнуть случаи, когда мы хотим намеренно выбросить новую ошибку из catch, или пробросить текущую, чтобы её обработать в другом месте.

Хорошей практикой считается обрабатывать в модуле только те ошибки, которые связаны непосредственно с ним, а все остальные пробрасывать дальше.

// parse-module.js// Есть свой тип ошибкиclass ParsingError extends Error {  ...}function parse(data) {  try {    parseData(data)  } catch (err) {    if (err.name !== 'ParsingError') {      // Другой тип ошибок пробрасываем дальше      throw err    }    logError(err)}}
          // parse-module.js
// Есть свой тип ошибки
class ParsingError extends Error {
  ...
}
function parse(data) {
  try {
    parseData(data)
  } catch (err) {
    if (err.name !== 'ParsingError') {
      // Другой тип ошибок пробрасываем дальше
      throw err
    }
    logError(err)
}
}

Таким образом, можно разделить ответственность, а обработкой проброшенной ошибки займётся внешний catch.

import parse from 'parse-module'try {  parse(data)} catch (e) {  console.log('Неизвестная ошибка парсинга:', e)}
          import parse from 'parse-module'
try {
  parse(data)
} catch (e) {
  console.log('Неизвестная ошибка парсинга:', e)
}

Ошибки в асинхронном коде

Скопировано

Конструкция try...catch работает только синхронно. Таким образом, с помощью try...catch нельзя обработать ошибку, которая возникла в асинхронном коде.

try {  // Код выполнится корректно, т.к. отсюда вернулся промис  Promise.reject('err')} catch (e) {  // Ошибка не будет поймана  console.log('Ошибка', e)}try {  // Здесь также код выполнится корректно, потому что установил таймаут без ошибок  setTimeout(() => {    throw Error('ошибка')  }, 1000)} catch (e) {  // Ошибка из таймаута также сюда не попадёт  console. log('Ошибка', e)}
          try {
  // Код выполнится корректно, т.к. отсюда вернулся промис
  Promise.reject('err')
} catch (e) {
  // Ошибка не будет поймана
  console.log('Ошибка', e)
}
try {
  // Здесь также код выполнится корректно, потому что установил таймаут без ошибок
  setTimeout(() => {
    throw Error('ошибка')
  }, 1000)
} catch (e) {
  // Ошибка из таймаута также сюда не попадёт
  console.log('Ошибка', e)
}

Однако, если записать асинхронный код в синхронном стиле с помощью async/await, то в этом случае обработку ошибок можно осуществлять с помощью try...catch.

async function handlePromise() {  try {    // Промис вернется с ошибкой    await Promise.reject('err')  } catch (e) {    // Теперь ошибка будет поймана    console.log('Ошибка', e) // err  }}handlePromise()
          async function handlePromise() {
  try {
    // Промис вернется с ошибкой
    await Promise. reject('err')
  } catch (e) {
    // Теперь ошибка будет поймана
    console.log('Ошибка', e) // err
  }
}
handlePromise()

Чтобы поймать ошибку из setTimeout(), блоки try...catch должны находиться внутри функции.

На практике

Скопировано

Егор Огарков советует

Скопировано

Любой асинхронный код можно переписать в синхронном стиле через async/await, чтобы использовать единый стиль обработки ошибок, используя try...catch. Например, перепишем установку таймаута из примера выше:

function wait(ms) {  return new Promise((resolve) => setTimeout(resolve, ms))}async function timeout(fn, ms) {  try {    // Ждем таймаут    await wait(ms)    // И выполняем функцию    fn()  } catch (err) {    // Ловим ошибку    console. log('Ошибка', err)  }}
          function wait(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms))
}
async function timeout(fn, ms) {
  try {
    // Ждем таймаут
    await wait(ms)
    // И выполняем функцию
    fn()
  } catch (err) {
    // Ловим ошибку
    console.log('Ошибка', err)
  }
}

Теперь можно вызывать функцию как прежде, ошибка будет поймана.

timeout(() => {  throw Error('ошибка')}, 1000)
          timeout(() => {
  throw Error('ошибка')
}, 1000)

Документация JDK 20 — Главная

  1. Главная
  2. Ява
  3. Java SE
  4. 20

Обзор

  • Прочтите меня
  • Примечания к выпуску
  • Что нового
  • Руководство по миграции
  • Загрузить JDK
  • Руководство по установке
  • Формат строки версии

Инструменты

  • Технические характеристики инструментов JDK
  • Руководство пользователя JShell
  • Руководство по JavaDoc
  • Руководство пользователя средства упаковки

Язык и библиотеки

  • Обновления языка
  • Основные библиотеки
  • HTTP-клиент JDK
  • Учебники по Java
  • Модульный JDK
  • Руководство программиста API бортового регистратора
  • Руководство по интернационализации

Технические характеристики

  • Документация API
  • Язык и ВМ
  • Имена стандартных алгоритмов безопасности Java
  • банок
  • Собственный интерфейс Java (JNI)
  • Инструментальный интерфейс JVM (JVM TI)
  • Сериализация
  • Проводной протокол отладки Java (JDWP)
  • Спецификация комментариев к документации для стандартного доклета
  • Прочие характеристики

Безопасность

  • Руководство по безопасному кодированию
  • Руководство по безопасности

Виртуальная машина HotSpot

  • Руководство по виртуальной машине Java
  • Настройка сборки мусора

Управление и устранение неполадок

  • Руководство по устранению неполадок
  • Руководство по мониторингу и управлению
  • Руководство по JMX

Client Technologies

  • Руководство по специальным возможностям Java

Исключения | Документация Kotlin

Классы исключений

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

Чтобы создать объект исключения, используйте выражение throw :

fun main() {
// начало выборки
выбросить исключение(«Привет!»)
//конец выборки
}

Чтобы перехватить исключение, используйте выражение try catch :

try {
// какой-то код
} поймать (e: SomeException) {
// обработчик
} окончательно {
// необязательный блок finally
}

Блоков catch может быть ноль или более, а блок finally может быть опущен. Однако требуется хотя бы один блок catch или finally .

Try — это выражение

try — это выражение, что означает, что оно может иметь возвращаемое значение:

значение a: Внутр.? = try { input.toInt() } catch (e: NumberFormatException) { null }

Возвращаемое значение выражения try является либо последним выражением в блоке try , либо последним выражением в блоке catch (или блоки). Содержимое блока finally не влияет на результат выражения.

Проверенные исключения

В Kotlin нет проверенных исключений. Для этого есть много причин, но мы приведем простой пример, иллюстрирующий, почему это так.

Ниже приведен пример интерфейса из JDK, реализованного классом StringBuilder :

Appendable append(CharSequence csq) выдает IOException;

Эта подпись говорит о том, что каждый раз, когда я добавляю строку к чему-то ( StringBuilder , какому-то журналу, консоли и т. д.), я должен перехватывать IOExceptions . Почему? Поскольку реализация может выполнять операции ввода-вывода ( Writer также реализует Appendable ). В результате повсюду появляется такой код:

try {
log.append(сообщение)
} поймать (IOException e) {
// Должен быть безопасным
}

И это нехорошо. Просто взгляните на Effective Java, 3rd Edition, Item 77: Не игнорируйте исключения .

Брюс Экель говорит о проверенных исключениях следующее:

И вот некоторые дополнительные мысли по этому поводу:

  • Проверенные исключения Java были ошибкой (Род Вальдхофф)

  • Проблема с проверенными исключениями (Андерс Хейлсберг)

Если вы хотите предупредить вызывающих абонентов о возможных исключениях при вызове кода Kotlin из Java, Swift или Objective-C, вы можете использовать аннотацию @Throws . Узнайте больше об использовании этой аннотации для Java, Swift и Objective-C.

Тип Nothing

throw — это выражение в Kotlin, поэтому вы можете использовать его, например, как часть выражения Элвиса:

val s = person.name ?: throw IllegalArgumentException(«Name required»)

Выражение throw имеет тип Nothing . Этот тип не имеет значений и используется для обозначения местоположений кода, которые никогда не могут быть достигнуты.