Как записать все файлы без исключения

Обновлено: 21.11.2024

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

Используйте блоки try/catch/finally для восстановления после ошибок или освобождения ресурсов

Используйте блоки try/catch вокруг кода, который потенциально может создать исключение, и ваш код сможет восстановиться после этого исключения. В блоках catch всегда упорядочивайте исключения от наиболее производных к наименее производным. Все исключения происходят от Exception. Более производные исключения не обрабатываются предложением catch, которому предшествует предложение catch для базового класса исключений. Если ваш код не может восстановиться после исключения, не перехватывайте это исключение. Включите методы выше по стеку вызовов для восстановления, если это возможно.

Очистить ресурсы, выделенные с помощью операторов using или блоков finally. Предпочитайте использовать операторы для автоматической очистки ресурсов при возникновении исключений. Используйте блоки finally для очистки ресурсов, которые не реализуют IDisposable. Код в предложении finally почти всегда выполняется, даже если возникают исключения.

Обработка распространенных условий без создания исключений

Для условий, которые могут возникнуть, но могут вызвать исключение, рассмотрите возможность обработки их таким образом, чтобы избежать исключения. Например, если вы попытаетесь закрыть соединение, которое уже закрыто, вы получите InvalidOperationException. Этого можно избежать, используя оператор if для проверки состояния подключения перед попыткой закрыть его.

Если вы не проверите состояние соединения перед закрытием, вы можете поймать исключение InvalidOperationException.

Выбор метода зависит от того, как часто вы ожидаете, что событие будет происходить.

Используйте обработку исключений, если событие происходит не очень часто, то есть если событие действительно исключительное и указывает на ошибку (например, на неожиданный конец файла). При использовании обработки исключений в нормальных условиях выполняется меньше кода.

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

Создавайте классы так, чтобы можно было избежать исключений

Класс может предоставлять методы или свойства, которые позволяют избежать вызова, который вызовет исключение. Например, класс FileStream предоставляет методы, помогающие определить, достигнут ли конец файла. Их можно использовать, чтобы избежать исключения, которое возникает, если вы читаете дальше конца файла. В следующем примере показано, как читать до конца файла, не вызывая исключения.

Еще один способ избежать исключений — возвращать значение null (или значение по умолчанию) для чрезвычайно распространенных ошибок вместо создания исключения. Чрезвычайно распространенный случай ошибки можно считать нормальным потоком управления. Возвращая значение null (или значение по умолчанию) в этих случаях, вы минимизируете влияние на производительность приложения.

Для типов значений следует учитывать, следует ли использовать Nullable или default в качестве индикатора ошибки для вашего конкретного приложения. При использовании Nullable значение по умолчанию становится нулевым вместо Guid.Empty . Иногда добавление Nullable может сделать более понятным, когда значение присутствует или отсутствует. В других случаях добавление Nullable может создать дополнительные случаи для проверки, которые не являются необходимыми, и служит только для создания потенциальных источников ошибок.

Выдавать исключения вместо возврата кода ошибки

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

Вводите новый класс исключений только в том случае, если предопределенный класс неприменим. Например:

Сгенерировать исключение InvalidOperationException, если набор свойств или вызов метода не подходят для текущего состояния объекта.

Сгенерировать исключение ArgumentException или один из предопределенных классов, производных от ArgumentException, если переданы недопустимые параметры.

Заканчивайте имена классов исключений словом Exception

Если необходимо пользовательское исключение, присвойте ему соответствующее имя и унаследуйте его от класса Exception. Например:

Включить три конструктора в пользовательские классы исключений

При создании собственных классов исключений используйте как минимум три общих конструктора: конструктор без параметров, конструктор, принимающий строковое сообщение, и конструктор, принимающий строковое сообщение и внутреннее исключение.

Exception(), который использует значения по умолчанию.

Exception(String), которое принимает строковое сообщение.

Exception(String, Exception), которое принимает строковое сообщение и внутреннее исключение.

Убедитесь, что данные исключения доступны при удаленном выполнении кода

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

Поместите сборку в общую базу приложений, совместно используемую обоими доменами приложений.

Если домены не имеют общей базы приложений, подпишите сборку, содержащую информацию об исключении, строгим именем и разверните сборку в глобальном кэше сборок.

Используйте грамматически правильные сообщения об ошибках

Создавайте четкие предложения и расставляйте знаки препинания в конце. Каждое предложение в строке, назначенной свойству Exception.Message, должно заканчиваться точкой. Например, «Таблица журнала переполнена». будет подходящей строкой сообщения.

Включить локализованное строковое сообщение в каждое исключение

Сообщение об ошибке, которое видит пользователь, получено из свойства Exception.Message созданного исключения, а не из имени класса исключения. Как правило, вы присваиваете значение свойству Exception.Message, передавая строку сообщения в аргумент сообщения конструктора исключений.

Для локализованных приложений вы должны предоставить локализованную строку сообщения для каждого исключения, которое может создать ваше приложение. Вы используете файлы ресурсов для предоставления локализованных сообщений об ошибках. Сведения о локализации приложений и получении локализованных строк см. в следующих статьях:

В настраиваемых исключениях укажите дополнительные свойства по мере необходимости

Предоставьте дополнительные свойства для исключения (в дополнение к пользовательской строке сообщения) только в том случае, если есть программный сценарий, в котором дополнительная информация полезна. Например, исключение FileNotFoundException предоставляет свойство FileName.

Расположите операторы throw так, чтобы трассировка стека была полезной

Трассировка стека начинается с оператора, в котором создается исключение, и заканчивается оператором catch, перехватывающим исключение.

Использовать методы построения исключений

Обычно класс выдает одно и то же исключение из разных мест своей реализации. Чтобы избежать лишнего кода, используйте вспомогательные методы, которые создают исключение и возвращают его. Например:

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

Восстановить состояние, когда методы не завершаются из-за исключений

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

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

Один из способов справиться с этой ситуацией — перехватить все исключения, вызванные транзакцией пополнения, и откатить снятие средств.

Этот пример иллюстрирует использование throw для повторного создания исходного исключения, что может облегчить вызывающим сторонам задачу увидеть настоящую причину проблемы без проверки свойства InnerException. Альтернативой является создание нового исключения и включение исходного исключения в качестве внутреннего исключения:

На этой странице обсуждаются подробности чтения, записи, создания и открытия файлов. Существует широкий спектр методов файлового ввода-вывода на выбор. Чтобы лучше понять API, на следующей диаграмме методы файлового ввода-вывода упорядочены по сложности.

Способы файлового ввода-вывода расположены от менее сложных к более сложным

В крайнем левом углу диаграммы показаны служебные методы readAllBytes , readAllLines и методы записи, предназначенные для простых, распространенных случаев. Справа от них находятся методы, используемые для перебора потока или строк текста, такие как newBufferedReader, newBufferedWriter, затем newInputStream и newOutputStream. Эти методы совместимы с пакетом java.io. Справа от них находятся методы для работы с ByteChannels, SeekableByteChannels и ByteBuffers, такие как метод newByteChannel. Наконец, справа показаны методы, использующие FileChannel для расширенных приложений, которым требуется блокировка файлов или ввод-вывод с отображением памяти.

Примечание. Методы создания нового файла позволяют указать необязательный набор исходных атрибутов для файла. Например, в файловой системе, поддерживающей набор стандартов POSIX (такой как UNIX), вы можете указать владельца файла, владельца группы или права доступа к файлу во время создания файла. На странице «Управление метаданными» объясняются атрибуты файлов, а также способы доступа к ним и их установки.

Эта страница имеет следующие темы:

Параметр OpenOptions

Некоторые методы в этом разделе принимают необязательный параметр OpenOptions. Этот параметр является необязательным, и API сообщает вам, какое поведение по умолчанию для метода, если он не указан.

Поддерживаются следующие перечисления StandardOpenOptions:

  • ЗАПИСЬ — открывает файл для записи.
  • APPEND — добавляет новые данные в конец файла.Этот параметр используется с параметрами WRITE или CREATE.
  • TRUNCATE_EXISTING — усекает файл до нуля байтов. Этот параметр используется с параметром WRITE.
  • CREATE_NEW — создает новый файл и выдает исключение, если файл уже существует.
  • CREATE — открывает файл, если он существует, или создает новый файл, если он не существует.
  • DELETE_ON_CLOSE — удаляет файл при закрытии потока. Этот параметр полезен для временных файлов.
  • SPARSE — указывает на то, что вновь созданный файл будет разреженным. Этот расширенный параметр используется в некоторых файловых системах, таких как NTFS, где большие файлы с «пробелами» данных могут храниться более эффективно, так как эти пустые промежутки не занимают место на диске.
  • СИНХРОНИЗАЦИЯ – синхронизирует файл (содержимое и метаданные) с базовым устройством хранения.
  • DSYNC: синхронизирует содержимое файла с базовым устройством хранения.

Часто используемые методы для небольших файлов

Чтение всех байтов или строк из файла

Если у вас небольшой файл и вы хотите прочитать все его содержимое за один проход, вы можете использовать метод readAllBytes(Path) или readAllLines(Path, Charset). Эти методы берут на себя большую часть работы за вас, например открытие и закрытие потока, но не предназначены для обработки больших файлов. В следующем коде показано, как использовать метод readAllBytes:

Запись всех байтов или строк в файл

Для записи байтов или строк в файл можно использовать один из методов записи.

В следующем фрагменте кода показано, как использовать метод записи.

Буферизованные методы ввода/вывода для текстовых файлов

Пакет java.nio.file поддерживает канальный ввод-вывод, который перемещает данные в буферы, минуя некоторые уровни, которые могут стать узким местом для потокового ввода-вывода.

Чтение файла с использованием буферизованного потокового ввода-вывода

Метод newBufferedReader(Path, Charset) открывает файл для чтения, возвращая BufferedReader, который можно использовать для эффективного чтения текста из файла.

В следующем фрагменте кода показано, как использовать метод newBufferedReader для чтения из файла. Файл закодирован в "US-ASCII".

Запись файла с использованием буферизованного потокового ввода-вывода

Вы можете использовать метод newBufferedWriter(Path, Charset, OpenOption. ) для записи в файл с помощью BufferedWriter .

В следующем фрагменте кода показано, как с помощью этого метода создать файл, закодированный в "US-ASCII":

Методы для небуферизованных потоков и совместимость с API java.io

Чтение файла с помощью потокового ввода-вывода

Чтобы открыть файл для чтения, можно использовать метод newInputStream(Path, OpenOption. ). Этот метод возвращает небуферизованный входной поток для чтения байтов из файла.

Создание и запись файла с помощью потокового ввода-вывода

Вы можете создать файл, добавить в файл или записать в файл с помощью метода newOutputStream(Path, OpenOption. ). Этот метод открывает или создает файл для записи байтов и возвращает небуферизованный выходной поток.

Метод принимает необязательный параметр OpenOption. Если параметры открытия не указаны и файл не существует, создается новый файл. Если файл существует, он усекается. Этот параметр эквивалентен вызову метода с параметрами CREATE и TRUNCATE_EXISTING.

В следующем примере открывается файл журнала. Если файл не существует, он создается. Если файл существует, он открывается для добавления.

Методы для каналов и байтовых буферов

Чтение и запись файлов с помощью канала ввода/вывода

В то время как поток ввода-вывода считывает символ за раз, канальный ввод-вывод считывает буфер за раз. Интерфейс ByteChannel обеспечивает базовые функции чтения и записи. SeekableByteChannel — это ByteChannel, который может поддерживать позицию в канале и изменять эту позицию. SeekableByteChannel также поддерживает усечение файла, связанного с каналом, и запрос размера файла.

Возможность перемещаться в разные точки файла, а затем читать или записывать в это место, делает возможным произвольный доступ к файлу. Дополнительную информацию см. в разделе Файлы с произвольным доступом.

Существует два метода чтения и записи ввода-вывода канала.

Примечание. Методы newByteChannel возвращают экземпляр SeekableByteChannel . С файловой системой по умолчанию вы можете преобразовать этот байтовый канал с возможностью поиска в FileChannel, предоставляя доступ к более продвинутым функциям, таким как отображение области файла непосредственно в памяти для более быстрого доступа, блокировка области файла, чтобы другие процессы не могли получить к ней доступ, или чтение и запись байтов из абсолютной позиции без изменения текущей позиции канала.

Оба метода newByteChannel позволяют указать список опций OpenOption. Поддерживаются те же параметры открытия, что и в методах newOutputStream, в дополнение к еще одному параметру: READ требуется, поскольку SeekableByteChannel поддерживает как чтение, так и запись.

Указание READ открывает канал для чтения.Указание WRITE или APPEND открывает канал для записи. Если ни один из этих параметров не указан, то канал открывается для чтения.

Следующий фрагмент кода считывает файл и выводит его на стандартный вывод:

В следующем примере, написанном для UNIX и других файловых систем POSIX, создается файл журнала с определенным набором прав доступа к файлам. Этот код создает файл журнала или добавляет его к файлу журнала, если он уже существует. Файл журнала создается с разрешениями на чтение/запись для владельца и разрешениями только на чтение для группы.

Способы создания обычных и временных файлов

Создание файлов

Вы можете создать пустой файл с начальным набором атрибутов, используя метод createFile(Path, FileAttribute). Например, если во время создания вы хотите, чтобы файл имел определенный набор прав доступа к файлу, используйте для этого метод createFile. Если вы не укажете никаких атрибутов, файл будет создан с атрибутами по умолчанию. Если файл уже существует, createFile выдает исключение.

В рамках одной атомарной операции метод createFile проверяет существование файла и создает этот файл с указанными атрибутами, что делает процесс более защищенным от вредоносного кода.

Следующий фрагмент кода создает файл с атрибутами по умолчанию:

Разрешения для файлов POSIX содержат пример использования createFile(Path, FileAttribute) для создания файла с предустановленными разрешениями.

Вы также можете создать новый файл с помощью методов newOutputStream, как описано в разделе Создание и запись файла с использованием потокового ввода-вывода. Если вы откроете новый выходной поток и сразу же его закроете, будет создан пустой файл.

Создание временных файлов

Вы можете создать временный файл, используя один из следующих методов createTempFile:

Первый метод позволяет коду указать каталог для временного файла, а второй метод создает новый файл в каталоге временных файлов по умолчанию. Оба метода позволяют указать суффикс для имени файла, а первый метод также позволяет указать префикс. В следующем фрагменте кода приведен пример второго метода:

Как Java-разработчик, вы должны хорошо разбираться в исключениях Java и обработке исключений.

В этом учебном пособии представлены базовые знания, которыми должен обладать каждый программист при работе с программами на языке Java. Для начала давайте разберемся, что такое исключения Java.

Что такое исключения Java

Программа Java может столкнуться с проблемами, которые приводят к внезапному завершению программы во время ее выполнения. Эти проблемы называются исключениями.

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

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

Зачем нам нужна обработка исключений

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

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

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

Иерархия исключений Java

Все исключения в Java должны быть потомками класса Exception, который сам является потомком класса Throwable.

Двумя основными подклассами класса Exception являются RuntimeException и IOException .

Исключение или ошибка

Другим дочерним классом класса Throwable является класс Error. Однако ошибки отличаются от исключений.

Ошибки указывают на проблемы, с которыми JVM может столкнуться во время выполнения. Эти проблемы обычно являются критическими и неустранимыми. Утечки памяти и несовместимость библиотек — распространенные причины ошибок в программах.

StackOverflowError и OutOfMemoryError — два примера ошибок Java.

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

Исключения Java можно разделить на две основные категории: проверяемые и непроверяемые исключения.

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

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

Все классы, расширяющие класс RuntimeException, являются непроверяемыми исключениями. Двумя примерами таких классов являются NullPointerException и ArrayIndexOutOfBoundsException .

Часто используемые методы в классе исключений

Мы рассмотрим несколько часто используемых методов класса Java Exception:

  1. getMessage : возвращает сообщение, содержащее сведения о возникшем исключении.
  2. printStackTrace : возвращает трассировку стека возникшей исключительной ситуации.
  3. toString : возвращает имя класса и сообщение, возвращаемое методом getMessage.

Как обрабатывать исключения

Давайте посмотрим, как мы можем обрабатывать исключения в Java:

попробовать поймать

Мы можем перехватывать исключения и правильно их обрабатывать с помощью блока try-catch в Java.

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

Основной синтаксис блока try-catch следующий:

При таком подходе программа не останавливает выполнение, когда программа генерирует исключение, вместо этого оно корректно обрабатывается.

Мы увидим, как обрабатывать исключения ввода-вывода, выдаваемые классом FileReader в программе Java.

Здесь мы использовали один блок catch для обработки исключения FileNotFoundException, возникающего при создании экземпляра класса FileReader, и исключения IOException, вызываемого методом read() класса FileReader.

Оба этих исключения являются дочерними элементами класса Exception.

Мы также можем использовать несколько операторов catch для перехвата различных типов ошибок, выдаваемых кодом внутри одного оператора try. В предыдущем примере мы можем использовать один блок catch для перехвата FileNotFoundException и другой блок catch для исключения IOException, как показано в следующем фрагменте кода:

Если созданное исключение совпадает с исключением, обработанным первым оператором catch, оно затем обрабатывается логикой внутри первого оператора catch.

Если исключения не совпадают, они передаются второму оператору catch. Если имеется более двух операторов catch, этот процесс продолжается до тех пор, пока исключение не достигнет оператора catch, который перехватывает его тип.

Поскольку FileNotFoundException является подтипом IOException , использование второго оператора catch для перехвата FileNotFoundException не будет работать. Он будет обработан первым оператором catch и никогда не достигнет второго оператора.

наконец-то

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

Затем код внутри оператора finally выполняется независимо от того, возникает ли исключение. Оператор finally всегда должен находиться в конце блока try-catch-finally.

Например, когда мы используем класс FileReader для чтения файла, важно закрыть открытый файл в конце обработки, независимо от того, возникнет исключение или нет. Чтобы убедиться в этом, мы можем поместить код для закрытия файла в оператор finally.

Однако, если вы попытаетесь скомпилировать приведенный выше код, он не будет скомпилирован из-за необработанного исключения IOException . Это связано с тем, что метод close() класса FileReader также может генерировать IOExceptions. Итак, мы должны поместить эту часть в другой блок try следующим образом:

выбрасывает

Обработка ошибок с помощью ключевого слова throws в Java проста. На самом деле при таком подходе вы не обрабатываете исключение в том месте, где оно возникает. Вместо этого мы выбрасываем исключение из текущего метода в метод, вызвавший текущий метод. Затем обработка ошибки становится обязанностью внешнего метода.

Чтобы генерировать исключение из метода, вам просто нужно объявить, что этот метод может генерировать рассматриваемое исключение. Давайте посмотрим, как мы можем обрабатывать исключения IOException, выдаваемые классом FileReader, используя этот подход.

бросить

В отличие от других подходов в этом списке, ключевое слово throw не используется для обработки ошибок. Но поскольку большинство людей путают ключевое слово throw с ключевым словом throws, мы подумали, что лучше обсудить это здесь.

Ключевое слово throw используется для явного вызова исключения. Мы можем сгенерировать только что созданное исключение или исключение, которое было перехвачено внутри метода.

Пользовательские исключения

Помимо использования встроенных исключений Java, вы можете определить свои собственные исключения. Вы можете определить их как проверенные или непроверенные исключения. Чтобы создать новое проверенное исключение, ваше новое исключение должно расширять класс Exception.

Чтобы создать непроверенное исключение, расширьте класс RuntimeException.

В следующем примере кода мы создали пользовательское проверенное исключение:

Теперь мы можем использовать указанное выше исключение внутри логики нашей программы следующим образом:

Если мы проверим длину строки с помощью класса InputChecker, он выдаст исключение InvalidLengthException, если длина строки меньше минимальной длины или больше максимальной длины.

Когда мы запустим приведенный выше фрагмент кода, он вызовет исключение InvalidLengthException, и мы получим следующий вывод:

Заключение

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

Исключение (или исключительное событие) — это проблема, возникающая во время выполнения программы. Когда возникает исключение, нормальный ход программы нарушается, и программа/приложение аварийно завершает работу, что не рекомендуется, поэтому эти исключения необходимо обрабатывать.

Исключение может возникнуть по разным причинам. Ниже приведены некоторые сценарии, в которых возникает исключение.

Пользователь ввел неверные данные.

Файл, который нужно открыть, не найден.

Сетевое соединение было потеряно во время обмена данными или JVM не хватило памяти.

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

На основании этого у нас есть три категории исключений. Вам нужно понять их, чтобы знать, как работает обработка исключений в Java.

Проверенные исключения. Проверенное исключение — это исключение, которое проверяется (уведомляется) компилятором во время компиляции, они также называются исключениями времени компиляции. Эти исключения нельзя просто игнорировать, программист должен позаботиться об этих исключениях (обработать).

Например, если вы используете класс FileReader в своей программе для чтения данных из файла, если файл, указанный в его конструкторе, не существует, возникает FileNotFoundException, и компилятор запрашивает программист для обработки исключения.

Пример

Если вы попытаетесь скомпилировать приведенную выше программу, вы получите следующие исключения.

Вывод

Примечание. Поскольку методы read() и close() класса FileReader вызывают IOException, вы можете заметить, что компилятор уведомляет об обработке IOException вместе с FileNotFoundException.

Непроверенные исключения. Непроверенное исключение — это исключение, возникающее во время выполнения. Их также называют исключениями времени выполнения. К ним относятся программные ошибки, такие как логические ошибки или неправильное использование API. Исключения во время выполнения игнорируются во время компиляции.

Например, если вы объявили в своей программе массив размером 5 и пытаетесь вызвать 6-й элемент массива, возникает исключение ArrayIndexOutOfBoundsException.

Пример

Если вы скомпилируете и запустите приведенную выше программу, вы получите следующее исключение.

Вывод

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

Иерархия исключений

Все классы исключений являются подтипами класса java.lang.Exception. Класс исключений является подклассом класса Throwable. Помимо класса исключений, существует еще один подкласс, называемый Error, который является производным от класса Throwable.

Ошибки — это ненормальные состояния, возникающие в случае серьезных сбоев, которые не обрабатываются программами Java. Ошибки генерируются для указания на ошибки, генерируемые средой выполнения. Пример: JVM не хватает памяти. Обычно программы не могут восстановиться после ошибок.

Класс Exception имеет два основных подкласса: класс IOException и класс RuntimeException.

Ниже приведен список наиболее распространенных проверенных и непроверенных встроенных исключений Java.

Методы исключений

Ниже приведен список важных методов, доступных в классе Throwable.

общедоступная строка getMessage()

Возвращает подробное сообщение о возникшем исключении. Это сообщение инициализируется в конструкторе Throwable.

public Throwable getCause()

Возвращает причину исключения, представленную объектом Throwable.

общедоступная строка toString()

Возвращает имя класса, объединенного с результатом getMessage().

public void printStackTrace()

Выводит результат toString() вместе с трассировкой стека в System.err, поток вывода ошибок.

public StackTraceElement [] getStackTrace()

Возвращает массив, содержащий каждый элемент трассировки стека. Элемент с индексом 0 представляет вершину стека вызовов, а последний элемент массива представляет метод в нижней части стека вызовов.

публичный Throwable fillInStackTrace()

Заполняет трассировку стека этого объекта Throwable текущей трассировкой стека, добавляя к любой предыдущей информации в трассировке стека.

Перехват исключений

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

Синтаксис

Код, подверженный исключениям, помещается в блок try. Когда возникает исключение, оно обрабатывается связанным с ним блоком catch. За каждым блоком try должен сразу же следовать либо блок catch, либо блок finally.

Инструкция catch включает объявление типа исключения, которое вы пытаетесь перехватить. Если в защищенном коде возникает исключение, проверяется блок (или блоки) catch, следующие за попыткой. Если тип возникшего исключения указан в блоке catch, исключение передается в блок catch так же, как аргумент передается в параметр метода.

Пример

Ниже показан массив, объявленный с двумя элементами. Затем код пытается получить доступ к третьему элементу массива, что вызывает исключение.

Это приведет к следующему результату —

Вывод

Несколько блоков захвата

За блоком try может следовать несколько блоков catch. Синтаксис для нескольких блоков catch выглядит следующим образом:

Синтаксис

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

Пример

Вот фрагмент кода, показывающий, как использовать несколько операторов try/catch.

Перехват нескольких типов исключений

Начиная с Java 7, вы можете обрабатывать более одного исключения с помощью одного блока catch, эта функция упрощает код. Вот как бы вы это сделали —

Броски/Ключевые слова Throw

Если метод не обрабатывает проверенное исключение, метод должен объявить его с помощью ключевого слова throws. Ключевое слово throws появляется в конце сигнатуры метода.

Вы можете сгенерировать исключение, только что созданное или только что перехваченное, с помощью ключевого слова throw.

Постарайтесь понять разницу между ключевыми словами throws и throw: throws используется для отсрочки обработки проверенного исключения, а throw используется для явного вызова исключения.< /p>

Следующий метод объявляет, что он генерирует исключение RemoteException —

Пример

Метод может объявить, что он создает более одного исключения, и в этом случае исключения объявляются в списке, разделенном запятыми. Например, следующий метод объявляет, что он генерирует RemoteException и InsufficientFundsException —

Пример

Окончательный блок

Блок finally следует за блоком try или блоком catch. Блок finally всегда выполняется независимо от возникновения исключения.

Использование блока finally позволяет запускать любые операторы очистки, которые вы хотите выполнить, независимо от того, что происходит в защищенном коде.

Блок finally появляется в конце блоков catch и имеет следующий синтаксис —

Синтаксис

Пример

Это даст следующий результат —

Вывод

Обратите внимание на следующее –

Предложение catch не может существовать без оператора try.

Необязательно иметь предложения finally всякий раз, когда присутствует блок try/catch.

Блок try не может присутствовать без предложения catch или finally.

Никакой код не может находиться между блоками try, catch, finally.

Попытка использования ресурсов

Как правило, когда мы используем какие-либо ресурсы, такие как потоки, соединения и т. д., мы должны явно закрывать их с помощью блока finally. В следующей программе мы читаем данные из файла с помощью FileReader и закрываем его с помощью блока finally.

Пример

try-with-resources, также называемая автоматическим управлением ресурсами, представляет собой новый механизм обработки исключений, представленный в Java 7, который автоматически закрывает ресурсы, используемые в блоке try catch.

Чтобы использовать этот оператор, вам просто нужно объявить требуемые ресурсы в скобках, и созданный ресурс будет автоматически закрыт в конце блока. Ниже приведен синтаксис оператора try-with-resources.

Синтаксис

Ниже представлена ​​программа, которая считывает данные из файла с помощью оператора try-with-resources.

Пример

При работе с оператором try-with-resources необходимо помнить о следующих моментах.

Чтобы использовать класс с оператором try-with-resources, он должен реализовать интерфейс AutoCloseable, а его метод close() вызывается автоматически во время выполнения.

Вы можете объявить более одного класса в операторе try-with-resources.

Пока вы объявляете несколько классов в блоке try инструкции try-with-resources, эти классы закрываются в обратном порядке.

За исключением объявления ресурсов в круглых скобках, все аналогично обычному блоку try/catch в блоке try.

Ресурс, объявленный в блоке try, создается непосредственно перед началом блока try.

Ресурс, объявленный в блоке try, неявно объявляется окончательным.

Пользовательские исключения

Вы можете создавать свои собственные исключения в Java. Помните о следующих моментах при написании собственных классов исключений —

Все исключения должны быть дочерними для Throwable.

Если вы хотите написать проверяемое исключение, которое автоматически применяется правилом обработки или объявления, вам необходимо расширить класс Exception.

Если вы хотите написать исключение среды выполнения, вам необходимо расширить класс RuntimeException.

Мы можем определить наш собственный класс исключений, как показано ниже —

Вам просто нужно расширить предопределенный класс Exception, чтобы создать собственное Exception. Они считаются проверенными исключениями. Следующий класс InsufficientFundsException является определяемым пользователем исключением, которое расширяет класс Exception, делая его проверяемым исключением. Класс исключения, как и любой другой класс, содержит полезные поля и методы.

Пример

Чтобы продемонстрировать использование нашего пользовательского исключения, следующий класс CheckingAccount содержит метод remove(), который создает исключение InsufficientFundsException.

Следующая программа BankDemo демонстрирует вызов методов deposit() и remove() CheckingAccount.

Скомпилируйте все три вышеуказанных файла и запустите BankDemo. Это даст следующий результат —

Вывод

Общие исключения

В Java можно определить две категории исключений и ошибок.

Исключения JVM — это исключения/ошибки, которые исключительно или логически выдаются JVM. Примеры: NullPointerException, ArrayIndexOutOfBoundsException, ClassCastException.

Программные исключения. Эти исключения явно создаются приложением или программистами API. Примеры: IllegalArgumentException, IllegalStateException.

Сопоставление кодов ошибок с исключениями

Например, в операционной системе Windows вызов метода, который возвращает код ошибки ERROR_FILE_NOT_FOUND (или 0x02), сопоставляется с FileNotFoundException, а код ошибки ERROR_PATH_NOT_FOUND (или 0x03) сопоставляется с DirectoryNotFoundException.

Однако точные условия, при которых операционная система возвращает определенные коды ошибок, часто недокументированы или плохо документированы. В результате могут возникать непредвиденные исключения. Например, поскольку вы работаете с каталогом, а не с файлом, вы ожидаете, что указание недопустимого пути к каталогу конструктору DirectoryInfo вызовет исключение DirectoryNotFoundException. Однако это также может вызвать исключение FileNotFoundException.

Обработка исключений в операциях ввода-вывода

Из-за этой зависимости от операционной системы идентичные условия исключения (например, ошибка каталога не найдена в нашем примере) могут привести к тому, что метод ввода-вывода выдаст любое одно из всего класса исключений ввода-вывода. Это означает, что при вызове API ввода-вывода ваш код должен быть готов к обработке большинства или всех этих исключений, как показано в следующей таблице:

Обработка исключения ввода-вывода

Являясь базовым классом для исключений в пространстве имен System.IO, IOException также генерируется для любого кода ошибки, который не соответствует предварительно определенному типу исключения. Это означает, что он может быть вызван любой операцией ввода-вывода.

Поскольку IOException является базовым классом для других типов исключений в пространстве имен System.IO, вы должны обрабатывать блок catch после обработки других исключений, связанных с вводом-выводом.

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

В случае IOException вы можете получить дополнительную информацию об ошибке из свойства IOException.HResult. Чтобы преобразовать значение HResult в код ошибки Win32, вы удаляете старшие 16 бит из 32-битного значения.В следующей таблице перечислены коды ошибок, которые могут быть заключены в IOException.

HResult Константа Описание
ERROR_SHARING_VIOLATION 32 Имя файла отсутствует, либо файл или каталог уже используются.
ERROR_FILE_EXISTS 80 Файл уже существует.
ERROR_INVALID_PARAMETER 87 Аргумент, предоставленный метод недействителен.
ERROR_ALREADY_EXISTS 183 Файл или каталог уже существует.

Вы можете обрабатывать их с помощью предложения When в операторе catch, как показано в следующем примере.

Читайте также: