В.В. Кулямин - Технологии программирования. Компонентный подход (1133554), страница 47
Текст из файла (страница 47)
следующий вид инструкций), чем обработка обычныхрезультатов работы операции.Исключения в обоих языках относятся к особым типам — классам исключений. Толькообъекты таких классов могут быть выброшены в качестве исключений. Классамиисключений являются все наследники классов java.lang.Throwable в Java иSystem.Exception в C#.Объекты-исключения содержат, как минимум, следующую информацию.o Сообщение о возникшей ситуации (его должен определить автор кода операции,выбрасывающей это исключение).В Java это сообщение можно получить с помощью метода String getMessage(), а в C#— с помощью свойства string Message.o Иногда возникают цепочки «наведенных» исключений, если обработка одноговызывает выброс другого.
Каждый объект-исключение содержит ссылку на другоеисключение, непосредственно вызвавшее это. Если данное исключение не вызваноникаким другим, эта ссылка равна null.В Java эту ссылку можно получить с помощью метода Throwable getCause(), а в C# —с помощью свойства System.Exception.InnerException.o Для описания ситуации, в которой возникло исключение, используется состояние стекаисполнения программы — список методов, которые вызывали друг друга перед этим, иуказание на место в коде каждого такого метода. Это место обозначает место вызоваследующего метода по стеку или, если это самый последний метод, то место, где ивозникло исключение.
Обычно указывается номер строки, но иногда он недоступен,если соответствующий метод присутствует в системе только в скомпилированном видеили является внешним для Java машины.Информация о состоянии стека на момент возникновения исключения, как и егосообщение, автоматически выводится в поток сообщений об ошибках, если этоисключение остается необработанным в программе.В Java состояние стека для данного исключения можно получить с помощью методаStackTraceElement[] getStackTrace(), возвращающего массив элементов стека.Каждый такой элемент несет информацию о файле (String getFileName()), классе(String getClassName()) и методе (String getMathodName()), а также о номере строки(int getLineNumber()).В C# можно сразу получить полное описание состояния стека в виде одной строки спомощью свойства string StackTrace.Блок обработки исключительных ситуаций выглядит так.try{ statements } Agcatch ( type_1 e_1 ) { statements_1 } Ag… Agcatch ( type_n e_n ) { statements_n } Agfinally{ statements_f } AgЕсли во время выполнения одной из инструкций в блоке, следующем за try, возникаетисключение, управление передается на первый блок catch, обрабатывающий исключениятакого же или более широкого типа.
Если подходящих блоков catch нет, выполняется блокfinally и исключение выбрасывается дальше.Блок finally выполняется всегда — сразу после блока try, если исключения не возникло,или сразу после обрабатывавшего исключение блока catch, даже если он выбросил новоеисключение.В этой конструкции могут отсутствовать блоки catch или блок finally, но не то и другоеодновременно. В C# разрешается опускать имя объекта-исключения в catch, если он неиспользуется при обработке соответствующей исключительной ситуации.159using System;public class A{public static void main(String[] args){try {if(args.length > 0)System.out.println("Some arguments are specified");else throw newIllegalArgumentException("No arguments specified");}catch(RuntimeException e){System.out.println("Exception caught");System.out.println("Exception type is " +e.getClass().getName());System.out.println("Exception message is \"" +e.getMessage() + "\"");}finally{System.out.println("Performing finalization");}}}public class A{public static void Main(string[] args){try {if(args.Length > 0)Console.WriteLine("Some arguments are specified");else throw newArgumentException("No arguments specified");}catch(Exception e){Console.WriteLine("Exception caught");Console.WriteLine("Exception type is " +e.GetType().FullName);Console.WriteLine("Exception message is \"" +e.Message + "\"");}finally{Console.WriteLine("Performing finalization");}}}В Java, начиная с версии 1.4, появиласьинструкция assert, предназначенная длявыдачи отладочных сообщений.Эта инструкция имеет один из двух видов:assert expression ;assert expression : expression_s ;Выражение expression должно иметьлогический тип, а выражение expression_s —произвольный.Проверка таких утверждений может бытьвыключена.
Тогда эта инструкция ничего неделает, и значения входящих в нее выраженийне вычисляются.Если проверка утверждений включена, товычисляется значение expression. Если оноравно true, управление переходит дальше,иначе в обоих случаях выбрасываетсяисключение java.lang.AssertionError.Во втором случае еще до выброса исключениявычисляется значение выраженияexpression_s, оно преобразуется в строку изаписывается в качестве сообщения всоздаваемое исключение.В C# имеется возможность использоватьинструкцию goto.
Эта инструкция передает160управления на инструкцию, помеченнуюметкой, которая следует за goto.Как мы уже видели, помимо обычных меток, вgoto могут использоваться метки case вместесо значениями и метка default. В этих случаяхинструкция goto должна находиться внутриблока switch, в котором имеются эти метки.При выходе с помощью goto из блока try илиблока catch, у которых имеетсясоответствующий блок finally, сначалавыполняется содержимое этого блока finally.Ключевые слова checked и unchecked в C#могут помечать блок, определяя тем самымконтекст вычислений в рамках этого блока (см.раздел о целочисленных типах).Инструкция using может быть использована вC#, чтобы выполнить действия, требующиезахвата каких-либо ресурсов, безнеобходимости заботиться потом об ихосвобождении.Эта инструкция имеет видusing ( expression ) statement илиusing ( declaration ) statementгде declaration — это декларация одной илинескольких переменных.Первый вид этой инструкции сводится ковторому — если тип используемого выраженияT, и имя v нигде не используется, то онэквивалентенusing ( T v = expression ) statementЭта конструкция, в свою очередь, эквивалентнаследующей.{T v = expression;try { statement }finally { disposal }}Здесь disposal представляет вызов методаDispose(), который должен быть у типа T, свозможной предварительной проверкой того,что переменная v не равна null, и приведениемее к типу System.IDisposable, если T являетсяего подтипом.В версии 2.0 в C# введены две инструкцииyield, предназначенные для более удобногопостроения итераторов.Блок, содержащий инструкцию yield,называется итерационным (iterator block) иможет быть телом метода, оператора илиметода доступа к свойству и не должен быть161блоком finally, catch или блоком try, укоторого есть соответствующие catch-блоки.Этот блок порождает последовательностьзначений одного типа.
Сам метод или оператордолжен возвращать объект одного из четырехтипов:System.Collections.IEnumerable,System.Collections.IEnumerator,System.Collections.Generic.IEnumerable<T>,System.Collections.Generic.IEnumerator<T>.В первых двух случаях порождаются объектытипа object, во вторых двух — значения типа T.Для возвращения одного из этойпоследовательности значений используетсяинструкция yield return expression;Выражение в ней должно иметьсоответствующий тип, object или T.Для указания на то, что порождаемаяитерационным блоком последовательностьзначений завершилась, используетсяинструкция yield break;Пример реализации итератора коллекции сиспользованием yield приведен ниже.using System;public class MyArrayList<T>{T[] items = new T[10];int size = 0;public int Count{ get { return size; } }public T this[int i]{get{if(i < 0 || i >= size) throw newIndexOutOfRangeException();else return items[i];}set{if(i < 0 || i > size) throw newIndexOutOfRangeException();else if (i == size){T[] newItems =new T[size + 10];Array.Copy(items, newItems, size++);}items[i] = value;}}162}public IEnumerator<T> GetEnumerator(){for(int i = 0; i < size; i++)yield return items[i];}public class A{public static void Main(){MyArrayList<string> l =new MyArrayList<string>();l[0] = "First";l[1] = "Second";l[2] = "Third";}}foreach (string s in l)Console.WriteLine(s);Инструкции обоих языков, предназначенные для синхронизации работы нескольких потоков,рассматриваются в следующей лекции, в разделе, посвященном разработке многопоточныхпрограмм.Пользовательские типыВ обоих рассматриваемых языках имеются ссылочные типы и типы значений.
Объектыссылочных типов имеют собственную идентичность, а значения такой идентичности не имеют.Объекты ссылочных типов можно сравнивать на совпадение или несовпадение при помощиоператоров == и !=. В C# эти операторы могут быть перегружены, поэтому, чтобы сравнитьобъекты на идентичность, лучше привести их сначала к типу object.В обоих языках можно создавать пользовательские ссылочные типы, определяя классы иинтерфейсы. Кроме того, можно использовать массивы значений некоторого типа. В C# можноопределять пользовательские типы значений, а в Java типами значений являются толькопримитивные.Класс представляет собой ссылочный тип, объекты которого могут иметь сложную структуруи могут быть задействованы в некотором наборе операций.
Структура данных объектов классазадается набором полей (fields) этого класса. В каждом объекте каждое поле имеет определенноезначение, могущее быть ссылкой на другой или тот же самый объект.Над объектом класса можно выполнять операции, определенные в этом классе. Термин«операция» будет употребляться для обозначения методов обоих языков, а также операторов,методов доступа к свойствам, индексерам и событиям в C# (см. ниже). Для каждой операции вклассе определяются ее сигнатура и реализация.Полная сигнатура операции — это ее имя, список типов, значения которых она принимает вкачестве параметров, а также тип ее результата и список типов исключений, которые могут бытьвыброшены из нее. Просто сигнатурой будем называть имя и список типов параметров операции— этот набор обычно используется для однозначного определения операции в рамках класса.
Всеоперации одного класса должны различаться своими (неполными) сигнатурами, хотя некоторые изних могут иметь одинаковые имена. Единственное исключение из этого правила касается толькоC# и будет описано ниже.Реализация операции представляет собой набор инструкций, выполняемых каждый раз, когдаэта операция вызывается. Абстрактный класс может не определять реализации для некоторых163своих операций — такие операции называются абстрактными. И абстрактные классы, и ихабстрактные операции помечаются модификатором abstract.Поля и операции могут быть статическими (static), т.е. относиться не к объекту класса, а кклассу в целом.