Исключения и работа с файлами
5.87M
Category: programmingprogramming

2.4

1. Исключения и работа с файлами

Рожков Константин Олегович
Инженер-программист в «Диасофт»

2.

Ошибки в программах
Давайте рассмотрим код ниже:
Как вы думаете, что может случиться во время ввода пользователем
значения в консоли?
2

3.

Ошибки в программе
Например, при вводе пользователем значения можно
написать не число, а строку (например “abrakadabra”). Во
время работы программы такая ошибка ввода приведет к
немедленному ее завершению.
3

4.

Читаем выброшенное исключение
Exception in thread "main" java.util.InputMismatchException:
Это сообщение об ошибке указывает на то, что в программе
возникло исключение типа InputMismatchException. Это
означает, что ввод, считываемый сканером, не соответствует
ожидаемому типу данных.
4

5.

Читаем выброшенное исключение
at java.base/java.util.Scanner.throwFor(Scanner.java:939)
Эта часть сообщения указывает на то, что исключение
было сгенерировано в методе throwFor класса Scanner в
файле Scanner.java на строке 939. Этот метод используется
для генерации исключений в классе Scanner.
5

6.

Читаем выброшенное исключение
at java.base/java.util.Scanner.next(Scanner.java:1594):
Следующая строка указывает на метод next класса Scanner в
файле Scanner.java на строке 1594. Метод next используется
для чтения следующей строки из ввода.
6

7.

Читаем выброшенное исключение
at java.base/java.util.Scanner.nextInt(Scanner.java:2258):
Здесь указан вызов метода nextInt класса Scanner в
файле Scanner.java на строке 2258.
Метод nextInt предназначен для чтения следующего
целого числа из ввода.
7

8.

Читаем выброшенное исключение
at java.base/java.util.Scanner.nextInt(Scanner.java:2212):
Это также вызов метода nextInt класса Scanner, но в этот
раз в файле Scanner.java на строке 2212. Это также
относится к чтению целого числа из ввода.
8

9.

Читаем выброшенное исключение
At lesson8_ExceptionsFiles.ExceptDemo.main(ExceptDemo.java:10):
Последняя строка указывает на то, что исключение было
сгенерировано
в
методе
main
класса
ExceptDemo
в
файле ExceptDemo.java на строке 10. Именно здесь происходит чтение
целого числа, которое не соответствует ожидаемому формату.
9

10.

Вывод из чтения исключения
Исключение java.util.InputMismatchException возникает, когда следующая
строка не соответствует ожидаемому шаблону ввода. В нашем случае
есть проблема с чтением int с помощью Scanner.nextInt() в вашем
файле ExceptDemo.java на строке 10.
Каждая строка в сообщении об ошибке исключения представляет собой
метод в стеке вызовов (stack trace).
10

11.

Вывод из чтения исключения
Стек вызовов показывает последовательность методов, которые были
вызваны в момент возникновения исключения.
Каждая строка указывает на конкретный метод в коде, где исключение
было сгенерировано, и обычно включает имя класса, имя метода и
номер строки кода.
На практике часто стоит обращать внимание на первую строчку, чтобы
понять, какое исключение выброшено и на последнюю – где как раз есть
ссылка на наш код: ExceptDemo.java:10
Кликнув на ссылку мы сразу перейдем к месту, где она возникла
11

12.

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

13.

Терминология
В языке Java ошибки в программах называются исключительными
ситуациями или исключениями (Exception).
Действие, которое означает появление исключения или создание
исключительной ситуации при работе программы, в Java принято
называть выбросом исключения (throws Exception).
А способы обработки исключительной ситуации — называют
перехватом исключения (catch Exception)
13

14.

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

15.

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

16.

Иерархия исключений
Throwable
Error
RuntimeException
Exception
IOException
SQLException
16

17.

Иерархия исключений
Базовый класс всех исключений в Java —
это класс Throwable, фактически от него
наследуются все ошибочные ситуации.
17

18.

Иерархия исключений — Error
Ошибки работы виртуальной машины Java и ее окружения.
Error
VirtualMachineError
UnknownError
OutOfMemoryError
ThreadDeath
StackOverflowError
VirtualMachineError является суперклассом всех ошибок, выбрасываемых JVM,
связанных с работой самой виртуальной машины. Эти ошибки обычно вызваны
внутренними сбоями в JVM, которые являются фатальными и не могут быть
обработаны приложением.
ThreadDeath - это специальная ошибка, которая может быть брошена в потоке
для прерывания его выполнения. Когда ThreadDeath бросается в поток, это
приводит к тому, что поток тихо завершает свою работу без выполнения
блоков finally или других завершающих действий. Обычно ThreadDeath не
должен перехватываться и обрабатываться, так как его цель - просто завершить
18
поток.

19.

Иерархия исключений — VirtualMachineError
Ошибки работы виртуальной машины Java и ее окружения.
VirtualMachineError
UnknownError
OutOfMemoryError
StackOverflowError
UnknownError - выбрасывается, когда происходит неизвестное, но серьезное
исключение в Java Virtual Machine
OutOfMemoryError - это ошибка, которая возникает, когда виртуальная машина
Java не может выделить достаточно памяти для создания нового объекта, и это
может произойти, например, при исчерпании памяти кучи.
StackOverflowError - это ошибка, которая возникает, когда стек вызовов методов
переполняется из-за слишком глубокой рекурсии или из-за выделения слишком
большого объема локальной памяти для методов.
19

20.

Иерархия исключений — Exception
Exception
RuntimeException
SQLException
IOException
EOFException
ArithmeticException
ClassCastException
FileNotFoundException
NullPointerException
SocketException
NoSuchElementException
Непроверяемые
Ошибки, связанные с работой приложения.
Проверяемые
20

21.

Иерархия исключений
RuntimeException
ClassCastException
ArithmeticException
NoSuchElementException
NullPointerException
RuntimeException в Java является подклассом Exception, который представляет
непроверяемые исключения, которые могут возникнуть во время выполнения
программы. Как непроверяемое исключение, RuntimeException и его подклассы не
требуют явного обработчика или объявления в блоке throws.
Непроверяемые
факторов
исключения
как
правило
возникают
вследствие
внешних
21

22.

Иерархия исключений — Exception
RuntimeException
ClassCastException
NoSuchElementException
ArithmeticException
NullPointerException
ClassCastException - это исключение в Java, которое возникает при попытке
приведения объекта к типу, который он фактически не является. Например, если
вы пытаетесь привести объект к типу, который не является его
родительским классом или интерфейсом.
NoSuchElementException - это исключение в Java, которое указывает на то, что в
в списке запрашиваемый элемент не существует.
NullPointerException - это исключение в Java, которое указывает на попытку
доступа к члену объекта или вызову метода у переменной, которая равна null
ArithmeticException - это исключение в Java, которое возникает при выполнении
арифметических операций, таких как деление на ноль или переполнение для
определенного типа данных
22

23.

Все вместе
Throwable
Error
ThreadDeath
VirtualMachineError
UnknownError
Exception
SQLException
RuntimeException
ArithmeticException
IOException
ClassCastException
EOFException
NullPointerException
SocketException
OutOfMemoryError
StackOverflowError
FileNotFoundException
NoSuchElementException
23

24.

Checked/unchecked исключения?
Исключения делятся на два типа:
Checked (проверяемые) — исключения, которые обязательно нужно
обработать или указать в описании метода, что в нем может возникнуть
такого типа ошибка, если это не сделать, то компилятор не скомпилирует код
и вернет ошибку компиляции. Это все исключения, наследуемые от Throwable
и Exception.
Unchecked (непроверяемые) — исключения, которые не обязательно
обрабатывать, но они могут возникнуть во время выполнения программы. Это
все исключения, наследуемые от Error и RuntimeException.
24

25.

Почему нельзя просто сделать все
проверяемыми?
Гибкость кода: Непроверяемые исключения не требуют явного объявления
или обработки, что делает код более лаконичным и позволяет более гибко
управлять исключениями в некоторых случаях.
Меньше кода: В случае непроверяемых исключений не нужно использовать
блоки try-catch или объявлять их в сигнатуре метода, что сокращает объем
кода.
Исключения времени выполнения: Некоторые исключения, такие
как NullPointerException, обычно возникают из-за ошибок программирования и
не могут быть предугаданы на этапе компиляции.
Непроверяемые исключения зависят от внешних факторов, которые
трудно предугадать.
Однако, использование слишком многих непроверяемых исключений может
сделать код менее надежным и усложнить его отладку. Поэтому важно разумно
подходить к выбору между проверяемыми и непроверяемыми исключениями в
25
зависимости от конкретной ситуации.

26.

Способы обработки исключений
1. Непроверяемые можно просто не обрабатывать
2. Использовать операторы try/catch/finally
3. Объявить в сигнатуре метода* throws
4. Выбросить ошибку в коде throw new Exception
26

27.

Не обрабатывать непроверяемые
исключения
Рассмотрим пример. Ниже программа производит деление на ноль:
При делении на ноль возникнет ошибка ArithmeticException — этот класс
исключения наследуется от RuntimeException и является unchecked (компилятор
не будет проверять во время процесса компиляции, обрабатывается это
исключение или нет).
27

28.

2. Использовать операторы try/catch/finally
В Java есть три ключевых слова для обработки исключений:
try — используется для отметки начала блока кода, который потенциально
может привести к исключению и ошибке;
catch — используется для отметки начала блока кода, предназначенного для
перехвата и обработки исключений;
finally — используется для отметки начала блока кода, который является
дополнительным.
Блоки catch можно располагать друг за другом.
Блок finally помещается после последнего блока catch. finally является
необязательным, но если в программе требуется выполнить какой-то код, в
независимости от того, появилось исключение или нет, надо использовать блок
finally.
Обычно в этом блоке происходит закрытие и освобождение ресурсов (файла,
сетевого соединения и т.д.).
28

29.

2. Использовать операторы try/catch/finally
Рассмотрим программу ввода двух чисел и будем перехватывать исключение
деления на ноль. Мы обернули «опасный код» операторами try/catch.
В блок try поместили весь код, который может вызвать ошибку, а в блок
catch — действие, которое хотим выполнить при возникновении ошибки.
29

30.

2. Использовать операторы try/catch/finally
В нашем примере используется класс Scanner, который может работать не
только с консолью, но и с файлами и другими ресурсами, требующими
принудительного закрытия.
Поэтому независимо от того, возникнет ошибка или нет, нужно всегда
выполнять блок кода finally, чтобы закрыть соединение.
30

31.

Использовать операторы try/catch/finally
Если мы используем в блоке try/catch какой-либо внешний ресурс (читаем файл,
используем scanner), важно после использования закрыть канал доступа к этому
ресурсу и освободить его, например, вызвав метод close().
Если ресурсы не закрывать, это может привести к утечкам памяти или к тому,
что ресурсы будут заблокированы для других процессов, что в конечном итоге
может вызвать ошибки в работе программы.
Утечка памяти может проявиться в форме непредсказуемого поведения
программы, например, программы могут начать работать медленнее из-за
неэффективного использования памяти или в конечном итоге могут привести к
исчерпанию памяти и аварийному завершению работы программы.
31

32.

Использовать операторы try/catch/finally
Можно располагать несколько операторов catch друг после друга.
Изменим предыдущий пример и будем считывать из консоли строковые
значения. При этом у нас может возникнуть исключение NoSuchElementException
32

33.

Использовать операторы try/catch/finally
Если мы знаем, что действия в блоке catch будут одинаковы при разных
исключениях, то можем их объединить в один блок с помощью оператора “|”.
В данном случае, будет сложнее определить, что пользователь сделал не так.

34.

Использовать операторы try/catch/finally
Но можно, например, вывести в консоль информацию об ошибке.

35.

Использовать операторы try/catch/finally
Если мы хотим ловить все исключения, наследуемые от одного общего
класса (как было в примере выше — RuntimeException), можем указать
только его в качестве аргумента для перехвата исключения.
35

36.

Использовать операторы try/catch/finally
Если при описании исключений указать класс-родитель раньше, то блок
с исключением,
следующий после него, не будет вызван никогда (блок с
.
ArithmeticException не будет вызван):
Но обратное расположение допустимо и часто используется, с начала в
коде описывается класс-наследник, а за ним более общий (класс родитель)
36

37.

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

38.

Объявить в сигнатуре метода throws
Через запятую можно перечислить исключения, которые могут возникнуть в
методе:
Можно также объединить родительским исключением:
Исключения, объявленные с использованием оператора throws, будут
выброшены в консоль и выведены на экран.
38

39.

Разница между try-catch и throws
Можно провести параллель с дорожными
знаками.
throws – как предупреждающий знак для
других разработчиков о том, что данный метод
может выбросить исключение, которое нужно
будет обработать (или так же предупредить об
исключении в своем методе)
try-catch – это как объездная дорога, в случае
обнаружения неполадки на основной.
39

40.

Объявить в сигнатуре метода throws
Пример объявления проверяемого исключения для метода преобразования
даты, введенной пользователем:
40

41.

Объявить в сигнатуре метода throws
Пример объявления проверяемого исключения для метода преобразования
даты, введенной пользователем:
Мы можем в методе main «установить предупреждающий знак» как в этом
примере или «проложить запасной путь» как в прошлом.
41

42.

Выбросить ошибку в коде throw new Exception
В случае, если нам требуется прекратить работу программы (например,
пользователь ввел некорректные данные), мы можем сами инициировать
создание и выброс исключения.
Для выброса исключения нужно в методе объявить оператор throw и создать
исключение, например: throw new Exception ("Сообщение"):
42

43.

Создать свой тип исключения
Чтобы создать свое исключение, нужно унаследовать свой класс от классаисключения. Для создания своего проверяемого исключения можно
наследоваться от классов Throwalbe или Exception, а для создания
unchecked exception — от класса RuntimeException.
К теме наследования мы еще вернемся на следующих занятиях.
43

44.

Создать свой тип исключения
Теперь попробуем выбросить свое исключение:
44

45.

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

46.

Итоги
Теперь мы знаем иерархию исключений
Умеем читать stacktrace, чтобы выявить ошибку
Выбрасывать
исключения
в
коде,
ловить
ошибки,
обходить их в коде
Проверяемые/непроверяемые исключения
Как создать свой тип исключений
46

47.

Работа с файлами
Класс File, определённый в пакете java.io, управляет информацией о
файлах и каталогах. Файлы и каталоги отличаются друг от друга в
операционной системе, но в Java они описываются одним классом File
Попробуем создать свой файл и папку
47

48.

Работа с файлами
Важно, инициализация переменных dir и файл в java не приводит к созданию
папки и файла. Нужно воспользоваться соответствующими методами:
mkdir()
createNewFile()
Блок try-catch необходим, так как метод createNewFile() может пробросить
исключение, если путь к файлу будет некорректен
48

49.

Получение информации о файле
Попробуем вывести информацию нашем новом файле greetings.txt
49

50.

Получение информации о файле
Информация о состоянии файла
50

51.

Список объектов каталога
Добавим еще 2 файла в каталог и выведем по ним информацию
51

52.

Понятие потока
Поток - применительно к работе с файлами, это последовательность
данных, которая используется для чтения или записи информации. В Java
может быть определен поток, который связан с файлом, через который мы
сможем проводить чтение или запись файла.
Объект, из которого можно считать данные, называется потоком ввода.
Объект, в который можно записывать данные, - потоком вывода.
Например, если надо считать содержание файла, то применяется поток
ввода, а если надо записать в файл - то поток вывода.
52

53.

Классы для работы с потоками
Для работы с потоками байтов* используются классы:
FileInputStream — последовательное чтение из файла байтов (byte)
FileOutputStream — последовательная запись в файл байтов (byte)
Для работы с потоками символов** используются классы:
Reader — последовательное чтение из него символов (char)
Writer — последовательную запись в него символов (char)
53

54.

Запишем в файл строку
Для создания объекта FileOutputStream передадим в качестве параметра путь
к файлу для записи.
Если такого файла нет, то он автоматически создаётся при записи.
Для записи в файл используем метод write(), который принимает
преобразованную в массив байтов строку.
После использования потока его необходимо закрыть для освобождения
ресурса. Используем метод close()
54

55.

Используем try с ресурсами
Для автоматического закрытия файла и освобождения ресурса объект
FileOutputStream создаётся с помощью конструкции try...catch с ресурсами,
где в круглых скобках () передаем сам ресурс, который требуется закрыть
после выполнения блока кода в фигурных скобках {}. Тогда метод close() не
нужен.
Результат этого и прошлого примера – успешная запись строки в указанный
файл:
55

56.

Чтение из файла:
Для считывания данных из файла предназначен класс FileInputStream
Для создания объекта FileInputStream можно передать в качестве параметра
путь к считываемому файлу.
Если файл не может быть открыт (например, по указанному пути такого файла
не существует), то генерируется исключение FileNotFoundException
Вывод в консоль будет:
56

57.

Сделаем явное приведение:
Вывод в консоль будет
57

58.

FileWriter для записи строк:
Класс FileWriter используется для записи текстовых файлов. В параметр
передается путь к файлу. Если файла нет, то он будет создан. Либо можно
передать сразу объект класса File
Получаем файл с содержимым:
58

59.

FileWriter для записи строк:
Мы можем добавить второй параметр со значением false, тогда данные
будут перезаписаны в каждом вызове программы.
Получаем файл с содержимым. Наши предыдущие записи были удалены,
потому что мы добавили в FileWriter второй параметр false.
59

60.

FileReader для чтения файлов:
В параметр так же передаем путь к файлу или объект File
Вывод в консоль:
60

61.

BufferedReader для чтения файлов:
Класс BufferedReader считывает данные из входного источника во внутренний
буфер, что уменьшает количество операций ввода-вывода и делает считывание
более эффективным. Кроме того, BufferedReader предоставляет методы, такие
как readLine(), для считывания строк текста, что упрощает считывание и
обработку текстовых данных.
Сначала мы создали объект класса FileReader, а затем поместили его как
параметр для создания объекта BufferedReader. Это нам позволит считывать
файл построчно, используя метод readLine().
61

62.

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

63.

Практика
Используя класс File, создайте папку resources и поместить в нее файл text1.txt.
Наполнить файл 5 строками.
Напишите функцию, открывающую файл text1.txt, выводящую в терминал n
последних сток.
Значение n следует получить от пользователя в консоли.
.
.
63

64.

Практика
Создайте файл text2.txt.
Наполните файл 5 строками.
Напишите функцию, открывающую файл text2.txt и производящую конкатенацию
над всеми строками в файле.
Результат конкатенации необходимо вывести в терминал.
.
.
64

65.

Итоги
Теперь мы знаем что такое объект File в java
Как создавать папку и файл посредством кода
Умеем считывать информацию о файлах и папках
Записывать и считывать данные из файлов
65
English     Русский Rules