Полная версия
Объектно-ориентированное программирование на Java. Платформа Java SE
Представьте, что у нас есть программа, где есть целочисленная переменная с именем x,
Которую мы инициализируем в значение 1.
И у нас также есть метод «f», который имеет целочисленный параметр.
И мы просто решили назвать его «х».
Вопрос, можем ли мы это сделать?
И если да, то что этот метод вернет в качестве результата?
Ответ на этот вопрос при написании кода на Java – да, мы можем это сделать.
Каким образом, мы управляем двумя x?
Каждый x действителен в определенном контексте, при выполнении определенного сегмента кода.
У нас есть черный x, который действителен, и который существует, и для которого мы сохраняем пространство в памяти, когда объявляем переменную.
Мы также зарезервировали пространство в памяти для z.
И когда мы вызываем f с x плюс 1, значение x равно 1.
1 плюс 1 равно 2, и мы вызываем f с 2.
Далее мы переходим к определению метода.
Вызываем f с 2.
Таким образом, красный x равен 2.
Итак, мы выполняем x плюс x со значением 2.
2 плюс 2 равно 4.
И это то, что этот метод возвращает и что хранится в z.
Теперь помните, что параметр x метода f является просто заполнителем.
Поэтому, если f вызывается с переменной x, а значение x равно 2, f с x возвращает 4.
И с этим нет никаких проблем.
Мы говорим, что первое x является глобальной переменной, тогда как параметр x является локальным для метода.
В этом примере мы видим, что эта локальная переменная – этот параметр – создается дважды: во-первых, для внутреннего вызова f с x плюс 1, со значением 2, – и второй раз для внешнего вызова со значением 4.
После выхода из каждого определения метода, созданная переменная будет уничтожена.
И выделенное пространство в памяти компьютера будет освобождено.
Поэтому, если вы хотите использовать внешнюю переменную в теле метода, вы должны выбрать другое имя.
Здесь мы видим, как использовать глобальную переменную x и параметр y в теле метода.
В этом случае у нас есть переменная x, которая видна во всем теле метода и за его пределами, и у нас есть переменная y, которая существует и видна только в теле метода.
Вне этого метода y не существует.
В этом примере, все, что мы только что сказали для параметров метода, применяется к переменным, объявленным внутри тела метода.
Здесь переменная y является локальной переменной в методе f.
В этом методе мы используем глобальную переменную x и локальную переменную y.
Этот пример аналогичен предыдущему.
Но в этом случае мы решили назвать локальную переменную внутри метода x, так же, как и глобальную переменную.
Таким образом, в этом случае у нас нет доступа к глобальной переменной.
Когда мы вызываем f для вычисления z, мы вызываем f, где внутри определяется x со значением 2.
Таким образом, мы возвращаем 2 плюс 2, равно 4.
Метод f всегда возвращает 4.
И это то, что мы сохраним в переменной z.
Таким образом, мы видели, что у нас есть глобальные и локальные переменные.
Глобальные переменные существуют, начиная с объявления и для остальной части программы.
Но они могут временно затеняться другими локальными переменными с тем же именем.
В этом примере показан цикл.
Для циклов также объявляются локальные переменные.
Здесь переменная x цикла for не позволяет нам видеть глобальную переменную при выполнении цикла.
Здесь у нас есть глобальная переменная x и глобальная переменная y.
Они инициализируются 1 и 0 соответственно.
Затем у нас есть глобальная переменная z, которая сохраняет значение y, но после выполнения этого цикла for.
Этот цикл for выполняется дважды.
Один раз для x равного 1 и один раз для x равного 2.
В каждом цикле for, y накапливает значение x.
Таким образом, при первом запуске y получает значение 1, а во втором y получает значение 1 плюс 2, равно 3.
Когда мы выходим из цикла for, локальная переменная x исчезает, остается только глобальная.
y имеет значение 3, и это значение, которое мы сохраняем в z.
Таким образом, мы видим точно такое же поведение для этих переменных в цикле for, как мы видели с локальными переменными в методах и с параметрами в методах.
В этом примере у нас есть глобальная переменная x.
И у нас есть метод с параметром x.
И внутри этого метода у нас есть цикл for с другой переменной x.
Таким образом, в этом случае у нас есть 3 переменных x.
Поэтому, когда мы вызываем f с x плюс 2, в последней строке, где x равно 1, мы вызываем f с 3, чтобы вычислить z.
В методе, параметр x равен 3.
Внутри метода мы объявляем переменную y, инициализированную 0, и затем мы определяем цикл for.
Этот цикл for выполняется два раза, как в предыдущем примере.
Здесь, мы объявляем другую переменную x, которая делает невидимыми предыдущие две переменные x, пока мы не выполним цикл for.
Здесь мы увеличиваем значение y.
y в конце получает 3 и возвращает y плюс x.
Но что это за х?
Это не та переменная x в цикле for, потому что мы вышли из цикла for.
Эта x равна 3 и это параметр метода.
Поэтому возвращается 3 плюс 3.
Это то, что мы возвращаем z, и что добавляется к x, но в этом случае это глобальная переменная x, поэтому мы получаем 7 и присваиваем 7 в z.
Этот пример легко проанализировать.
Метод f определяется в контексте, где x равно 1.
Таким образом, этот метод всегда возвращает 1 независимо откуда он был вызван.
x равно 1 и z также присваивается 1.
Важно отметить, что f получает свое определение в том месте, где он определен.
Если он определен в том месте, где x равно 1, метод f определяется, чтобы вернуть 1.
И это видно в этом примере.
В этом примере у нас есть два метода: f и g.
g вызывает f, и он вызывает его в контексте, где x равно 0.
И здесь нужно учитывать, что метод f был определен в контексте, где x равно 1.
И мы уже сказали, что метод f всегда возвращает 1 независимо от того, где он вызывается.
Так как здесь x равно 1.
Это называется лексической областью действия или статической областью действия в отличие от динамической области действия.
Большинство языков программирования имеют статическую область действия, в том числе и Java.
Поэтому, как только метод определен, его значение и его поведение, зафиксированы.
Теперь, если мы удалим самое верхнее объявление x, переменная x не определяется при объявлении f.
Следовательно, этот сегмент кода выдаст ошибку во время компиляции.
Далее мы проанализируем взаимосвязь между частично определенными функциями в математике, и методами в Java, которые не определены для некоторых входных значений.
В математике мы изучаем функции, т. е. отображения между множествами значений, где значения области определения X сопоставляются значениям множества Y.
Обычно для всех значений из множества X существуют значения во множестве Y.
Однако может быть случай, когда для некоторых значений X нет отображения, определенного в Y.
В этом случае мы говорим о частично определенной функции.
Если вы хотите избежать частично определенных функций и всегда работать с полными функциями, вы можете выделить в X меньшее множество, где все значения имеют отображение.
Теперь вернемся к Java.
Предположим, мы хотим вычислить квадратный корень из 4.
Здесь есть два результата, плюс 2 и минус 2.
Предположим, что наш метод просто возвращает положительное значение, плюс 2.
Мы всегда можем получить другое решение, добавив знак минус.
Теперь, что произойдет, если мы вызовем метод square с аргументом минус 4?
Мы знаем, что решением в этом случае являются не действительные числа, а мнимые числа.
Таким образом, не существует реального числа, которое может быть предложено в качестве результата метода.
Метод не определен для отрицательных чисел.
В математике мы можем определить функции более подробно.
Мы можем настроить область определения в соответствии с тем, что нам нужно.
Например, мы могли бы сказать, что область определения этой функции не множество целых чисел, а множество натуральных чисел, то есть 0 и положительные целые числа.
Таким образом, функция будет определена для всех значений в этой области определения натуральных чисел.
Но в программировании мы имеем дело с существующими типами.
Теперь, как мы определяем в Java частично определенные функции или частично определенные методы?
Что мы можем сделать в случае метода, который не определен для всех возможных входных значений.
Во-первых, так как возникает ошибка при вызове метода square с отрицательным числом, мы будем ожидать ошибку, и программа должна завершиться с ошибкой.
Это, конечно, не самый удобный способ для решения этой проблемы.
Во-вторых, мы можем проверять значения параметров метода в самом методе или при вызове метода.
Или мы можем перехватить и обработать возникшую ошибку в самом методе или после его вызова, и об этом мы поговорим, когда будем обсуждать исключения Java.
Комментарии. Javadoc
В прошлой лекции мы говорили о том, что мы можем сделать в случае метода, который не определен для всех возможных входных значений.
Программы могут содержать сотни тысяч строк кода.
И очень сложно отслеживать все возможности.
Поэтому мы также можем использовать языковые конструкции, чтобы избежать ошибки, как для себя, так и для других программистов, которые могут использовать ваш код.
Для этого можно использовать комментарии.
Комментарии представляют собой текст, чередующийся с кодом, и этот текст не должен выполняться компьютером, а должен читаться людьми.
Еще одна возможность – это изготовить сопроводительную документацию к программе.
Javadoc – это инструмент, который является генератором документации на основе специальных комментариев.
Если вы используете эти специальные комментарии, вы можете автоматически создать хорошую документацию.
Таким образом, комментарий представляет собой текст в программе, бесполезный с точки зрения компьютера, но который может быть полезен для программиста.
Здесь мы видим один из возможных способов написания комментария.
Комментарий начинается с косой черты и звездочки и заканчивается звездочкой и косой чертой.
Комментарий может включать в себя несколько строк.
Здесь у нас есть еще один комментарий.
Это комментарий, так как он начинается с косой черты и звездочкой и заканчивается несколькими строками позже звездочкой и косой чертой.
Но на разных строках есть еще несколько звездочек.
И это указание для специальной программы под названием Javadoc.
Javadoc принимает в качестве входа Java-код с этими специальными комментариями и выдает документацию для ее использования программистами.
Специальные команды, такие как @param и @return, имеют смысл, который Javadoc понимает при подготовке итоговой документации.
Операционная система компьютера, веб-браузер, приложения мобильного телефона, все они – состоят из очень сложных частей программного обеспечения.
Например, смартфон с операционной системой Android имеет более 12 миллионов строк кода.
Из них более 2 миллионов написано на языке Java.
Представьте себе, что вы кодируете все эти строки самостоятельно.
Вам понадобится много времени.
Как программистам, нам нужно работать с другими программистами для достижения цели.
Нам также необходимо расширять или изменять предыдущие программы, написанные другими людьми, которых мы не знаем.
Также и другие программисты вполне вероятно будут работать с нашим кодом.
Попытка понять все строки кода, которые нам нужно использовать, требует огромных усилий.
Поэтому очень полезно писать заметки в наших программах, чтобы помочь другим и нам самим понять код, используя человеческий язык в этих заметках, но при этом не подвергая опасности выполнение нашей программы.
Эти примечания в программе – это то, что мы называем комментариями.
Это дополнительный текст, который мы добавляем в наш код, чтобы улучшить его читаемость и повторное использование.
Эти комментарии прозрачны для компьютера, поскольку они служат только для людей, но не имеют вычислительного смысла.
Как и во всем, что есть в жизни, существуют разные подходы в том, как мы можем писать эти комментарии.
Комментарии полезны для разных целей.
Например, описание кода, то есть резюмирование целей сегмента кода.
Описание алгоритма, который вы создаете.
Комментирование сегмента кода, который не работает должным образом.
Или автоматическое создание документации.
В Java существуют разные способы написания комментариев.
Сначала, мы сосредоточимся на тех типах комментариев, которые направленны на предоставление сведений о вашем коде вам и другим программистам.
Если для нашего комментария нужна только одна строка, мы будем писать две косые черты перед текстом комментария.
И комментарий будет идти до конца строки.
Если мы хотим включить комментарий из нескольких строк, мы будем писать косую черту, за которой следует звездочка.
И мы закончим комментарий звездочкой, а затем косой чертой.
При этом начало и конец комментария могут быть в одной строке или в разных строках.
Будьте осторожны и избегайте вложения друг в друга этих типов комментариев.
Существуют рекомендации по написанию кода на языке Java.
Советуют использовать комментарии с несколькими строками только при комментировании блока кода.
И использовать однострочные комментарии для всего остального.
Вы можете задаться вопросом, сколько комментариев вы можете вставить в свой код.
Для этого нет однозначного ответа.
Убедитесь, что ваши комментарии соответствуют вашему коду.
Не забывайте обновлять свои комментарии при изменении кода.
Хороший программист создает не только хороший код, но также предоставляет другим возможность использовать свой код.
То есть, дает хорошие комментарии.
Есть еще один полезный и почти обязательный тип комментариев, который предназначен для создания подробной документации о нашем коде.
Существует программа под названием Javadoc, которая генерирует документацию из кода Java в HTML-файлы, чтобы мы могли легко их прочитать в нашем браузере.
Документация в Java-коде должна начинаться с косой черты, а затем идут две звездочки, и заканчивается одной звездочкой, а затем косой чертой.
Javadoc просматривает вашу программу, ища строки, начинающиеся с косой черты и двух звездочек, и создает HTML-документацию.
Но почему мы должны использовать этот комментарий?
Вместо поиска комментариев в миллионах строк кода, вы можете открыть веб-страницу и найти всю важную информацию о программе.
Когда мы говорим в Java об автоматической генерации документации, мы используем термин Javadoc.
Какую информацию мы должны включить в Javadoc?
На сайте Oracle вы можете найти руководство по эффективной практике написания комментариев для инструмента Javadoc.
Мы попытаемся обобщить наиболее важные из них, используя пример.
Мы начнем с определения Javadoc-комментария.
Комментарий Javadoc написан в формате HTML и должен предшествовать коду.
Он состоит из двух частей: описания и блока тегов.
Рассмотрим теги, которые вы должны использовать и как их использовать.
Давайте посмотрим на метод, который здесь указан, и вид информации, которая должна быть предоставлена для него в Javadoc.
Вы должны начать свой комментарий Javadoc с краткого и полного описания того, что делает этот метод.
Если в вашем Javadoc-комментарии есть несколько абзацев, разделите их тэгом p.
Затем вставьте пустую строку комментария, между описанием и блоком тегов.
Обратите внимание, что каждый комментарий Javadoc имеет только одно описание.
И как только инструмент Javadoc найдет пустую строку, он решит, что описание закончено.
Затем вы используете теги для добавления информации о вашем методе.
Наконец, вы должны поместить в конце строку со звездочкой и косой чертой, чтобы отметить конец комментария Javadoc.
Какая информация должна быть включена в блок тегов?
Для описания метода нам понадобятся, в основном, два типа тегов – @param и @return.
@param описывает аргумент метода.
И его необходимо указать для всех аргументов метода.
За тегом всегда следует имя аргумента.
Это имя всегда указывается в нижнем регистре.
Затем идет описание аргумента.
Далее вы должны всегда указывать тип данных аргумента.
Единственным исключением является тип данных, int, который вы можете опустить.
Чтобы разделить имя, описание и тип данных аргумента, вы можете добавить один или несколько пробелов.
Теги @param должны быть перечислены в порядке объявления аргумента.
Что касается описания, если это фраза без глагола, начните его с маленькой буквы.
Если это предложение с глаголом, начните его с заглавной буквы.
Таким образом, Javadoc – это полезный инструмент, который позволяет программистам автоматически генерировать HTML-страницы с документацией из их кода.
Исключения
Когда мы говорили о том, что мы можем сделать в случае метода, который не определен для всех возможных входных значений, мы сказали, что мы можем запрограммировать, что нужно сделать в исключительной ситуации.
То есть мы можем программировать, что делать в обычных случаях, и что делать в исключительных случаях.
Это сделает нашу программу более надежной.
Таким образом, у нас есть исключения.
В этом случае мы используем не комментарии, а используем конструкции программирования языка Java.
Мы программируем, что делать для значений, которые не желательны.
Часто бывает, что наши программы хорошо написаны, их синтаксис и последовательность инструкций верны.
И они прекрасно компилируются.
Но когда мы их запускаем, возникают ошибки.
Java обрабатывает ошибки, возникающие в наших программах, во время выполнения с использованием исключений.
Oracle определяет исключения как события, которые происходят во время выполнения программы, и которые нарушают нормальный поток выполнения инструкций.
Однако важно учитывать, что совсем не плохо иметь программы, которые выбрасывают исключения.
Исключения позволяют отделить основную логику программы от действий, которые нужно предпринять, когда происходит что-то необычное.
Кроме того, исключения позволяют классифицировать и дифференцировать типы ошибок систематическим образом.
Таким образом, исключение – это ошибка, возникающая во время выполнения программы. Исключения могут возникать во многих случаях, например:
Пользователь ввел некорректные данные.
Или файл, к которому обращается программа, не найден.
Или сетевое соединение с сервером было утеряно во время передачи данных.
Рассмотрим некоторые из наиболее распространенных исключений в программах Java, а также механизм их обработки, чтобы обеспечить нормальный поток программы, даже если во время выполнения происходят ошибки.
Первое исключение, которое мы здесь видим, это ArithmeticException.
Это исключение выбрасывается при возникновении арифметических ошибок, например, при делении целого на ноль.
Эти сегменты кода вызывают исключение ArithmeticException.
Если вы программируете метод, в котором вы используете математическое деление, вы всегда должны проверять, что делитель отличается от нуля, так как вы не знаете, какие значения будут иметь аргументы, которые вы принимаете в этом методе.
Другим распространенным исключением является ArrayIndexOutOfBoundsException.
Это исключение вызывается, когда пытаются получить доступ к элементу массива с недействительным индексом.
Если мы определим, например, четырехэлементный массив, то это исключение будет выбрасываться при попытке доступа к элементу массива с индексом четыре или выше, а также при попытке доступа к элементу массиву с отрицательным индексом.
Поэтому, когда метод должен получить доступ к элементу в массиве, важно сначала проверить, что нужная позиция находится в пределах массива.
Еще одно исключение, это NumberFormatException.
Это исключение вызывается, когда пытаются преобразовать строку в числовой тип, например, double или integer, но при этом строка не содержит числа.
Стандартный способ управления этими инструкциями, которые могут выбросить исключение, это заключить их в оператор try-catch.
Здесь вы видите, что код метода printDivision заключен в выражение try-catch.
В этом случае нет необходимости проверять значение b, делителя.
Если b отличен от нуля, будет выполнен метод System.out.printIn (a / b);
В противном случае Java выбросит исключение ArithmeticException с сообщением, что вы не можете делить на ноль.
Поток программы будет продолжен, как обычно, после обнаружения этого исключения.
Выражение try-catch также может быть применено к примерам ArrayIndexOutOfBoundsException и NumberFormatException, которые мы видели ранее.
В обоих случаях, и благодаря выражению try-catch, мы можем гарантировать, что, если возникает исключение, пользователь получит соответствующую информацию, и поток выполнения программы продолжится далее нормально.
Вы также можете не обрабатывать исключения блоком try-catch в методе, а передать это право вызывающему этот метод.