Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Теоретический материалСтр 1 из 2Следующая ⇒
Цель занятия Научиться разрабатывать программы с использованием исключений и потоков ввода/вывода. Теоретический материал Исключение - это ненормальная ситуация, возникающая во время выполнения последовательности кода. Т.е., исключение - это ошибка, возникающая во время выполнения. Исключение в 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
|