Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Теоретический материал






Цель занятия

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

Теоретический материал

Исключение - это ненормальная ситуация, возникающая во время выполнения последовательности кода. Т.е., исключение - это ошибка, возникающая во время выполнения.

Исключение в Java представляет собой объект, описывающий исключительную (т.е. ошибочную) ситуацию, возникающую в определенной части программного кода. Когда возникает такая ситуация, в вызвавшем ошибку методе генерируется объект, который представляет исключение. Этот метод может обработать исключение самостоятельно или же пропустить его. Так или иначе, в определенный момент исключение перехватывается и обрабатывается. Исключения могут генерироваться автоматически исполняющей системой Jаvа или вручную в прикладном коде. Исключения, генерируемые исполняющей системой Jаvа, имеют отношение к фундаментальным ошибкам, нарушающим правила языка Jаvа или ограничения, накладываемые исполняющей системой Java. А исключения, генерируемые вручную, обычно служат для уведомления вызывающего кода о некоторых ошибках в вызываемом методе.

Исключения делятся на несколько классов (см. рисунок 1), но все они имеют общего предка — класс Throwable. Его потомками являются подклассы Exception и Error.

Рисунок 1 - Иерархия классов исключений

 

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

Ошибки (Errors) представляют собой более серьёзные проблемы, которые, согласно спецификации Java, не следует пытаться обрабатывать в собственной программе, поскольку они связаны с проблемами уровня JVM. Например, исключения такого рода возникают, если закончилась память, доступная виртуальной машине. Программа дополнительную память всё равно не сможет обеспечить для JVM.

В Java все исключения делятся на три типа: контролируемые исключения (checked) и неконтролируемые исключения (unchecked), к которым относятся ошибки (Errors) и исключения времени выполнения (RuntimeExceptions, потомок класса Exception).

Контролируемые исключения представляют собой ошибки, которые можно и нужно обрабатывать в программе, к этому типу относятся все потомки класса Exception (но не RuntimeException).

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

Управление обработкой исключений в Java осуществляется с помощью пяти ключевых слов: try, catch, throw, throws и finally.

Операторы программы, которые требуется отслеживать на предмет исключений, размещаются в блоке try. Если исключение возникает в блоке try, оно генерируется. Прикладной код может перехватить исключение, используя блок catch, а затем обработать его некоторым рациональным способом. Системные исключения автоматически генерируются исполняющей системой Java. Для генерирования исключения вручную служит ключевое слово throw. Любое исключение, генерируемое в теле метода, должно быть обозначено в его объявлении ключевым словом throws. А любой код, который должен быть непременно выполнен по завершении блока try, размещается в блоке finally. Ниже приведена общая форма блока обработки исключений.

try {

// Блок кода, в котором должны отслеживаться ошибки

}

catch (тип_исключения_1 объект_исключения) {

// Обработчик исключения тип_исключения_1

}

catch (тип_исключения_2 объект_исключения) {

// Обработчик исключения тип_исключения_2

}

//...

finally

// блок кода, который должен быть непременно

// выполнен по завершении блока try

}

 

Здесь тип_исключения обозначает тип происходящего исключения.

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

Все потоки ввода последовательности байтов являются подклассами абстрактного класса InputStream (см. рисунок 2), потоки вывода — подклассами абстрактного класса OutputStream (см. рисунок 3). При работе с файлами используются подклассы этих классов, соответственно, FileInputStream и FileOutputStream, конструкторы которых открывают поток и связывают его с соответствующим физическим файлом. Существуют классы-потоки для ввода массивов байтов, строк, объектов, а также для выбора из файлов и сетевых соединений.

Для чтения байта или массива байтов используются реализации абстрактных методов int read() и int read(byte[] b) класса InputStream. Метод int read() возвращает –1, если достигнут конец потока данных, поэтому возвращаемое значение имеет тип int, а не byte. При взаимодействии с информационными потоками возможны различные исключительные ситуации, поэтому обработка исключений вида try-catch при использовании методов чтения и записи является обязательной.

В классе FileInputStream метод read() читает один байт из файла, а поток System.in как объект подкласса InputStream позволяет вводить байт с консоли.

 

 

Рисунок 2 - Иерархия классов байтовых потоков ввода

 

Реализация абстрактного метода write(int b) класса OutputStream записывает один байт в поток вывода. Оба эти метода блокируют поток до тех пор, пока байт не будет записан или прочитан. После окончания чтения или записи в поток его всегда следует закрывать с помощью метода close(), для того, чтобы освободить ресурсы приложения. Класс FileOutputStream используется для вывода одного или нескольких байт информации в файл.

 

Рисунок 3 - Иерархия классов байтовых потоков вывода

 

Для работы с физическим файлами и каталогами (директориями), расположенными на внешних носителях, в приложениях Java используются классы из пакета java.io.

Для обработки символьных потоков в формате Unicode применяется отдельная иерархия подклассов абстрактных классов Reader (см. рисунок 4) и Writer (см. рисунок 5), которые почти полностью повторяют функциональность байтовых потоков, но являются более актуальными при передаче текстовой информации.

 

Рисунок 4 - Иерархия символьных потоков ввода

 

 

Рисунок 5 - Иерархия символьных потоков вывода

 

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

Объект класса File создается одним из нижеприведенных способов:

File obFile = new File(" \\com\\file.txt");

File obDir = new File(" c: /jdk/src/java/io");

File obFile1 = new File(obDir, " File.java");

File obFile2 = new File(" c: \\com", " file.txt");

File obFile3 = new File(new URI(" Интернет-адрес"));

В первом случае создается объект, соответствующий файлу, во втором —подкаталогу. Третий и четвертый случаи идентичны. Для создания объекта указывается каталог и имя файла. В пятом — создается объект, соответствующий адресу в Интернете.

При создании объекта класса File любым из конструкторов компилятор не выполняет проверку на существование физического файла с заданным путем.

Система ввода/вывода языка Java содержит стандартные потоки ввода, вывода и вывода ошибок. Класс System пакета java.lang содержит поле in, которое является ссылкой на объект класса InputStream, и поля out, err — ссылки на объекты класса PrintStream, объявленные со спецификаторами public static и являющиеся стандартными потоками ввода, вывода и вывода ошибок соответственно. Эти потоки связаны с консолью, но могут быть переназначены на другое устройство. Для назначения вывода текстовой информации в произвольный поток следует использовать класс PrintWriter, являющийся подклассом абстрактного класса Writer. Для наиболее удобного вывода информации в файл (или в любой другой поток) следует организовать следующую последовательность инициализации потоков с помощью класса PrintWriter:

new PrintWriter(new BufferedWriter(new FileWriter(new File(" text\\data.txt"))));

Класс Scanner. Объект класса java.util.Scanner принимает форматированный объект или ввод из потока и преобразует его в двоичное представление. При вводе могут использоваться данные из консоли, файла, строки или любого другого источника, реализующего интерфейсы Readable, InputStream или ReadableByteChannel. Класс Scanner предлагает наиболее удобный и полный интерфейс для извлечения информации практически из любых источников.

Некоторые конструкторы класса:

Scanner(String source)

Scanner(File source) throws FileNotFoundException

Scanner(File source, String charset) throws FileNotFoundException

Scanner(InputStream source)

Scanner(InputStream source, String charset)

Scanner(Path source)

Scanner(Path source, String charset),

где source — источник входных данных, а charset — кодировка.

Объект класса Scanner читает лексемы из источника, указанного в конструкторе, например из строки или файла. Лексема — это набор символов, выделенный набором разделителей (по умолчанию пробельными символами).

В случае ввода из консоли следует определить объект:

Scanner con = new Scanner(System.in);

После создания объекта его используют для ввода информации в приложение, например лексему или строку,

String str1 = con.next();

String str2 = con.nextLine();

или типизированных лексем, например, целых чисел,

if(con.hasNextInt()) {

int n = con.nextInt();

}

В классе Scanner определены группы методов, проверяющих данные заданного типа на доступ для ввода. Для проверки наличия произвольной лексемы используется метод hasNext(). Проверка конкретного типа производится с помощью одного из методов boolean hasNextТип() или boolean hasNextТип(int radix), где radix — основание системы счисления. Например, вызов метода hasNextInt() возвращает true, только если следующая входящая лексема —целое число. Если данные указанного типа доступны, они считываются с помощью одного из методов Тип nextТип(). Произвольная лексема считывается методом String next(). После извлечения любой лексемы текущий указатель устанавливается перед следующей лексемой.

Рассмотрим пример работы с исключениями, а также использование потоков ввода/вывода.

package by.practical5.run;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

 

public class ExceptionExample {

public static String fileName = " exampleFile.txt";

public static String filePath = " /Users/olga/Documents/workspace/ADP/src/by/practical5/run/";

 

public static void main(String[] args) {

// дляполученияошибкираскомментируйте 6 строку

// triggerStackOverflowError();

 

int [] intArray = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 };

/*

* RuntimeException – этонепроверяемых (unchecked) исключения. Онивозникаютво

* времявыполненияприложения. К такимисключениямотносится, например,

* NullPointerException. Онинетребуютобязательногозаключения в блок

* try-catch. Когда RuntimeException возникает, этосвидетельствует о

* ошибке, допущеннойпрограммистом (неинициализированныйобъект, выход

* запределымассива и т.д.). Поэтомуданноеисключениененужно

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

* вновьневозникало.

*/

 

// Примерынепроверяемыхисключений

 

// Делениенанольприведет к ArithmeticException

// раскомментируйтестроки 35 - 36 длятого, чтобыполучить

// ArithmeticException

// таккакнепроверяемыхисключениянеобязательнозаключать

// в try-catch

// блок,

// топрикомпиляциикомпиляторневыдастошибку

// double res1 = intArray[8] / 0;

// System.out.println(" res1 = " + res1);

try {

double catchedRes1 = intArray[8] / 0;

System. out. println(" catchedRes1 = " + catchedRes1);

} catch (ArithmeticException e) {

System. out. println(" Catching exception: " + e);

}

// внутриодногоблокаможнообрабатыватьболееодногоисключения

try {

Double d = null;

System. out. println(" d = " + d. toString()); // сгенерируется

// NullPointerException,

// т.к. d не

// проинициализирован

double res2 = intArray[10] / 9; // сгенерируется

// ArrayIndexOutOfBoundsException,

// т.к. вышлизапределымассива

System. out. println(" res2 = " + res2);

} catch (ArrayIndexOutOfBoundsException oobe) {

System. out. println(" Getting " + oobe.getMessage());

} catch (NullPointerException npe) {

npe.printStackTrace();

System. out. println(" Getting NullPointerException");

}

// такженесколькотиповисключенияможнообработать в одном catch блоке

int intFirstArgument = 0;

try {

String firstArgument = args[1];

System. out. println(" First argument = " + firstArgument);

intFirstArgument = Integer. parseInt (firstArgument);

System. out. println(" You've entered valid integer value " + intFirstArgument);

} catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {

System. out. println(" Handling exception: " + e);

}

 

System. out. println(" after cathing exception");

double square = getSquare (2, 7);

System. out. println(String. format (" square = %f", square));

 

System. out. println(" after printing square");

// примерработы с потокамиввода / вывода

 

// записьстроки в файл

String textToFile = " Hello from file";

boolean isFileUpdated = writeStringToFile (textToFile, fileName, filePath);

System. out. println(String. format (" file updated [%b] with text [%s]", isFileUpdated, textToFile));

 

// чтениеизфайла в строку

System. out. println(" file " + filePath + fileName + " content: " + readFromFile (fileName, filePath));

 

}

 

static void triggerStackOverflowError() {

triggerStackOverflowError ();

}

 

public static double getSquare(double height, double width) throws IllegalArgumentException {

if (height < 0) {

throw new IllegalArgumentException(" height< 0");

} else if (width < 0) {

throw new IllegalArgumentException(" width< 0");

}

return height * width;

}

 

public static boolean writeStringToFile(String textToFile, String pFileName, String pFilePath) {

boolean fileUpdated = true;

FileOutputStream fos = null;

File file;

try {

// необходимозадатьполныйпуть к файлу

file = new File(pFilePath + pFileName);

fos = new FileOutputStream(file);

 

/*

* Необходимопроверить, существуетлифайл. Если

* файланет - создаемновый

*/

if (! file.exists()) {

file.createNewFile();

}

 

/*

* Объект String неможетбытьнапрямуюзаписан в

* файл. Необходимо

* преобразоватьобъект String в массив bytes

*/

byte [] bytesArray = textToFile.getBytes();

fos.write(bytesArray);

fos.flush();

System. out. println(" File Written Successfully");

} catch (IOException ioe) { // обработкапроверяемых

// (checked) исключений

fileUpdated = false;

ioe.printStackTrace();

} finally {

try {

if (fos! = null) {

fos.close();

}

} catch (IOException ioe) {

System. out. println(" Error in closing the Stream");

}

}

return fileUpdated;

}

 

public static String readFromFile(String pFileName, String pFilePath) {

File file = new File(pFilePath + pFileName);

FileInputStream fis = null;

StringBuilder builder = new StringBuilder();

try {

fis = new FileInputStream(file);

 

System. out. println(" Размер файла (в байтах): "

+ fis.available());

int iCh;

while ((iCh = fis.read())! = -1) {

char ch = (char) iCh;

builder.append(ch);

}

 

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

if (fis! = null)

fis.close();

} catch (IOException ex) {

ex.printStackTrace();

}

}

 

return builder.toString();

}

 

}

Результат работы программы:

You've entered valid integer value 2

after cathing exception

square = 14, 000000

after printing square

File Written Successfully

file updated [true] with text [Hello from file]

Размер файла (в байтах): 15

file /Users/olga/Documents/workspace/ADP/src/by/practical5/run/exampleFile.txt content: Hello from file






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.