С методами мы уже неоднократно встречались на передыдущих уроках. В каждом примере у нас был метод main:
Метод main - это точка входа, с которой начинается выполнение программы.
String[] args - это аргументы командной строки, с которыми запускается приложение.
Напишем небольшую программу, которая выводит кол-во аргументов и сами аргументы:
Мы могли бы записать весь код только в одном методе main и, в теории, могли бы так написать любую программу, но проблема в том, что все это постепенно заняло бы несколько страниц кода. Все это сложно понять и удержать в голове.
Но мы можем разбить нашу большую “проблему”, на маленькие кусочки и дробить все это до такого уровня, где со сложностью уже можно иметь дело.
Одна из техник подразумевает, что мы можем разбить наш код на отдельные небольшие методы, в которых уже будем иметь дело с локальными кусочками большой задачи.
Для примера разобьем на отдельные методы пример с опросником из предыдущего урока:
Тот же исходник, но текстом (ссылка на исходник).
Мы вынесли в отдельные методы код, который задает вопросы - askQuestions, и код, который распечатывает ответы - printAnswers.
Рассматриваем методы с точки зрения управления сложностью, после добавления методов код должен становиться понятнее, а не запутанее. Можно рекомендовать следовать таким правилам:
- название метода должно отображать, что он делает
- задача локализованная внутри метода, должна быть достаточно узкой, внутри метода не распыляться и делать что-то одно
- задокументировать метод
Под документированием метода подразумеваем либо пару коментариев об особенностях метода, либо более полное описание метода с использованием тегов Javadoc
Рассмотрим подробнее декларацию (объявление) метода:
- static - специальный модификатор, рассмотри позже вместе с классами
- void - маркер, показывает, что метод не возвращает результат
- String[]titles, String[] answers - входные параметры
В общем виде объявление метода:
- <модификаторы_доступа> - static, public, private, protected, package-private
- <тип_выходного_параметра> - тип переменной, которую возвращаем из метода (примитивы, массивы или классы), либо void (специальный маркер, что ничего не возвращаем)
- <список_параметров_метода> - отдельные именованные параметры (аналогично переменным), либо вариант с переменным числом параметров
Если в качестве выходного параметра указан void, то из метода поток выполнения выходит, либо когда достигает закрывающей скобки метода, либо по оператору return.
Например здесь на выходе void, оператора return нет
из метода выходим по закрывающей скобке.
Но мы можем, к примеру, добавить проверку входных параметров при старте метода и выйти раньше по оператору return:
Если метод возвращает какое-то значение (не void), то выход из него должен быть выполнен с помощью оператора return с указанием значения, которое мы возвращаем.
Например:
В Java под сигнатурой метода понимается название метода и набор входных параметров.
Можно создавать методы с одинаковыми названиями, но разным набором параметров (т.е. методы различаются сигнатурой). Так мы получаем перегрузку метода.
Вспомните метод println стандартной библиотеки, который мы постоянно используем:
одно и тоже название, но разный набор параметров (см. println ).
Мы не сможем перегрузить метод (создать несколько методов с одинаковыми названиями), если отличие будет только в выходном параметре. Нужно, чтобы входные параметры различались, т.е. сигнатуры методов различались (выходной параметр не входит в определение сигнатуры в Java).
Так же есть возможность передать в метод опциональное число параметров. Для параметра используется синтаксис <тип>... <название_аргумента>.
Например напишем метод, который складывает произвольное число параметров:
здесь int... args это фактически массив int.
Передача по значению и по ссылке
Входные параметры передаются в метод по значению, либо по ссылке.
С практической точки зрения, если мы меняем параметр, который передали по ссылке, то изменения заметны снаружи метода, а для параметров переданных по значению - нет.
По значению передаются только примитивные типы, все остальные (массивы, классы) - по ссылке.
Пример передачи параметра по значению:
Мы присваиваем переменой x значение 10, передаем в метод changeInt, там меняем значение на 1. Дальше после завершения метода проверяем значени x(печатаем) и видим, что значение переменной x не изменилось. Все дело в том что в метод передается копия значения и дальше мы имем дело с локальной копией (переменная int a).
А вот пример, когда мы передаем массив (т.е. по ссылке) и меняем его содержимое:
Рекурсия
Так же методы обладают такой возможностью, как рекурсия т.е. возможностью вызвать сами себя.
Например напишем метод, который распечатает заданный диапазон целых положительных чисел:
Задание:
- Наберите программу-опросник, которую мы обсуждали в начале урока. Запустите на выполнение. Добавьте вопросов и ответов.
Используя рекурсию, напишите метод printChars, который распечатает каждый символ строковой переменной на отдельной строке.
- получить первый символ в строке str.charAt(0)
- получить строку, которая меньше текущей на 1 символ str.substring(1)
- условие выхода из рекурсии str.length() == 0
- распечатать символ на отдельной строке System.out.println(str[0]); где str - это String str;
Полезные ссылки: