Объявление и вызов методов
Структура метода, модификаторы, возвращаемый тип, return, void и принцип DRY
Что такое метод и зачем он нужен?
Представьте, что вы учитесь готовить. Каждый раз, когда вы хотите приготовить яичницу, вам приходится заново вспоминать все шаги: достать сковородку, разбить яйца, посолить, помешать, подождать... Звучит утомительно, правда?
А теперь представьте, что у вас есть записная книжка с рецептами. Вы открываете страницу «Яичница», читаете шаги и выполняете их. Завтра вы снова хотите яичницу — открываете ту же страницу. Послезавтра друг решает прийти на ужин — вы даёте ему эту же записную книжку, и он тоже успешно готовит.
Метод в Java — это именно такой рецепт. Это именованный блок кода, который выполняет конкретную задачу. Вы один раз «пишете рецепт» (объявляете метод), а потом сколько угодно раз «открываете страницу» (вызываете метод), чтобы выполнить нужные действия.
Давайте посмотрим на простой пример. Без методов ваш код мог бы выглядеть так:
public class Main {
public static void main(String[] args) {
System.out.println("Привет, мир!");
System.out.println("Это мой первый урок.");
System.out.println("Я изучаю Java!");
}
}
Здесь мы просто печатаем строки. Но что, если нам нужно выводить приветствие много раз в разных местах программы? Копировать одну и ту же строку десятки раз — плохая идея. Именно здесь на помощь приходят методы.
Вот тот же пример, но с использованием метода:
public class Main {
public static void main(String[] args) {
sayHello();
sayHello();
sayHello();
}
public static void sayHello() {
System.out.println("Привет, мир!");
System.out.println("Это мой первый урок.");
System.out.println("Я изучаю Java!");
}
}
Мы создали метод sayHello() и три раза его вызвали. Приветствие напечаталось три раза. Если завтра мы захотим изменить текст приветствия, нам нужно будет изменить его только в одном месте — внутри метода. А не искать и править каждую копию по отдельности.
Почему методы важны? Методы позволяют разбивать большую программу на маленькие, понятные части. Это делает код читаемым, повторно используемым и легким для отладки. Без методов программы быстро превращаются в неуправляемый хаос.
Ещё одна аналогия: представьте автомат в столовой. Вы нажимаете кнопку «Кофе» — и получаете кофе. Нажимаете «Сок» — получаете сок. Вам не нужно знать, как внутренний механизм нагревает воду, перемалывает зёрна и смешивает ингредиенты. Вы просто вызываете нужную функцию, и она делает всю работу. Методы в программировании работают так же: вы вызываете их по имени, и они выполняют свою задачу.
Структура метода: из чего состоит «рецепт»
Каждый метод в Java имеет строго определённую структуру. Давайте разберём её по частям, как разбирают двигатель автомобиля.
Вот общая форма объявления метода:
модификатор_доступа возвращаемый_тип имя_метода(параметры) {
// тело метода — здесь выполняются действия
}
Разберём каждый элемент на конкретном примере:
public int add(int a, int b) {
int result = a + b;
return result;
}
Здесь:
- public — модификатор доступа (кто может вызывать этот метод)
- int — возвращаемый тип (метод возвращает целое число)
- add — имя метода (то, по чему мы его вызываем)
- (int a, int b) — список параметров (данные, которые метод принимает)
- { ... } — тело метода (набор команд, которые выполняются при вызове)
Важно: Имя метода и список параметров вместе называются сигнатурой метода. Это как адрес метода в программе — именно по нему Java находит нужный метод для вызова.
Давайте рассмотрим более простой пример без параметров и без возвращаемого значения:
public static void printLine() {
System.out.println("================================");
}
Этот метод не принимает никаких данных (скобки пустые) и ничего не возвращает (тип void). Он просто печатает линию из знаков равно. Мы можем вызывать его столько раз, сколько нужно:
public static void main(String[] args) {
System.out.println("Начало отчёта");
printLine();
System.out.println("Продажи за январь: 150 000 руб.");
printLine();
System.out.println("Продажи за февраль: 200 000 руб.");
printLine();
System.out.println("Конец отчёта");
}
Результат:
Начало отчёта
================================
Продажи за январь: 150 000 руб.
================================
Продажи за февраль: 200 000 руб.
================================
Конец отчёта
Обратите внимание: мы написали printLine() только один раз, а используем его в трёх местах. Если завтра мы захотим заменить линию из «=» на линию из «-», достаточно будет изменить одну строку внутри метода.
Теперь давайте посмотрим на метод с параметрами и возвращаемым значением — он самый полный:
public static double calculateArea(double width, double height) {
double area = width * height;
return area;
}
Этот метод:
- Принимает два параметра: ширину и высоту (оба типа
double) - Вычисляет площадь, умножая одну величину на другую
- Возвращает результат вычисления (тип
double)
Вызов:
public static void main(String[] args) {
double roomArea = calculateArea(5.0, 3.5);
System.out.println("Площадь комнаты: " + roomArea);
double deskArea = calculateArea(1.2, 0.8);
System.out.println("Площадь стола: " + deskArea);
}
Результат:
Площадь комнаты: 17.5
Площадь стола: 0.96
Мы использовали один и тот же метод для вычисления площади двух разных объектов. Это и есть сила методов — они универсальны и переиспользуемы.
Модификаторы доступа: кто может «открыть книгу рецептов»
Модификатор доступа определяет, кто может вызывать данный метод. Это как уровень секретности документа: некоторые документы доступны всем (публичные), другие — только определённому кругу лиц (приватные).
В Java есть четыре основных модификатора доступа:
public — публичный доступ
Метод с модификатором public доступен отовсюду. Любой другой класс, любая другая программа может его вызвать. Это как дверь, которая всегда открыта.
public class Калькулятор {
public int сложить(int a, int b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
Калькулятор калькулятор = new Калькулятор();
int результат = калькулятор.сложить(5, 3);
System.out.println("5 + 3 = " + результат);
}
}
Метод сложить объявлен как public, поэтому мы можем вызвать его из класса Main.
private — приватный доступ
Метод с модификатором private доступен только внутри своего класса. Никто другой не может его вызвать. Это как личный дневник — только вы его читаете.
public class БанковскийСчёт {
private double получитьПроцентнуюСтавку() {
return 0.05;
}
public double рассчитатьПроценты(double сумма) {
double ставка = получитьПроцентнуюСтавку();
return сумма * ставка;
}
}
public class Main {
public static void main(String[] args) {
БанковскийСчёт счёт = new БанковскийСчёт();
double проценты = счёт.рассчитатьПроценты(100000);
System.out.println("Проценты: " + проценты);
}
}
Здесь метод получитьПроцентнуюСтавку() — приватный. Его нельзя вызвать из класса Main, но его может вызвать публичный метод рассчитатьПроценты() того же класса. Это способ спрятать детали реализации.
Почему это важно? Сокрытие деталей — один из принципов хорошего программирования. Вы создаёте «чёрный ящик»: другие программы знают, ЧТО делает метод (например, рассчитывает проценты), но не знают КАК он это делает (какая формула, какая ставка). Если вы завтра измените формулу, вам не придётся менять код в других местах.
protected — защищённый доступ
Метод с модификатором protected доступен внутри своего класса, в классах-наследниках (в других пакетах) и в классах того же пакета. Это как доступ для сотрудников филиала и центрального офиса.
public class Животное {
protected String имя;
protected void издатьЗвук() {
System.out.println("Животное издаёт звук");
}
}
public class Собака extends Животное {
public void гавкнуть() {
System.out.println("Гав!");
}
}
Метод издатьЗвук() доступен в классе Собака, потому что Собака — наследник Животное. Мы подробно изучим наследование позже, пока просто запомните, что protected — это нечто среднее между public и private.
package-private — доступ по умолчанию
Если не указать модификатор доступа вообще, метод становится доступен только для классов в том же пакете (папке). Это как доступ для сотрудников одного отдела.
public class Помощник {
void показатьПодсказку() {
System.out.println("Это подсказка");
}
}
public class Главный {
public static void main(String[] args) {
Помощник помощник = new Помощник();
помощник.показатьПодсказку();
}
}
Метод показатьПодсказку() не имеет модификатора — значит, он доступен только для классов в том же пакете. Если Помощник и Главный находятся в одной папке, всё работает.
Сравнительная таблица:
| Модификатор | Тот же класс | Тот же пакет | Наследник | Везде |
|---|---|---|---|---|
| public | Да | Да | Да | Да |
| protected | Да | Да | Да | Нет |
| private | Да | Нет | Нет | Нет |
| (нет модификатора) | Да | Да | Нет | Нет |
Для начала изучения Java запомните простое правило: метод main всегда public static, а для большинства ваших методов на данном этапе подходит модификатор public или отсутствие модификатора.
Возвращаемый тип: что метод «отдаёт» взамен
Каждый метод может что-то возвращать как результат своей работы. Это как автомат для напитков: вы нажимаете кнопку (вызываете метод), и получаете стаканчик (результат).
Тип значения, который метод возвращает, указывается перед его именем. Если метод ничего не возвращает, используется ключевое слово void.
Методы, возвращающие конкретные типы
Метод может возвращать числа, строки, логические значения и любые другие типы данных:
Пример: метод, возвращающий целое число (int)
public static int получитьКвадрат(int число) {
return число * число;
}
Этот метод принимает целое число и возвращает его квадрат. Если передать 5, получим 25. Если передать 10, получим 100.
public static void main(String[] args) {
int результат1 = получитьКвадрат(5);
int результат2 = получитьКвадрат(10);
int результат3 = получитьКвадрат(7);
System.out.println("5 в квадрате = " + результат1);
System.out.println("10 в квадрате = " + результат2);
System.out.println("7 в квадрате = " + результат3);
}
Результат:
5 в квадрате = 25
10 в квадрате = 100
7 в квадрате = 49
Пример: метод, возвращающий дробное число (double)
public static double перевестиВКилометры(double метры) {
return метры / 1000.0;
}
public static void main(String[] args) {
double расстояние = перевестиВКилометры(5000);
System.out.println("5000 метров = " + расстояние + " км");
double расстояние2 = перевестиВКилометры(12500);
System.out.println("12500 метров = " + расстояние2 + " км");
}
Результат:
5000 метров = 5.0 км
12500 метров = 12.5 км
Пример: метод, возвращающий строку (String)
public static String получитьПриветствие(String имя) {
return "Здравствуйте, " + имя + "!";
}
public static void main(String[] args) {
String приветствие1 = получитьПриветствие("Анна");
String приветствие2 = получитьПриветствие("Пётр");
System.out.println(приветствие1);
System.out.println(приветствие2);
}
Результат:
Здравствуйте, Анна!
Здравствуйте, Пётр!
Пример: метод, возвращающий логическое значение (boolean)
public static boolean являетсяЧётным(int число) {
return число % 2 == 0;
}
public static void main(String[] args) {
System.out.println("4 чётное? " + являетсяЧётным(4));
System.out.println("7 чётное? " + являетсяЧётным(7));
System.out.println("0 чётное? " + являетсяЧётным(0));
}
Результат:
4 чётное? true
7 чётное? false
0 чётное? true
Важное правило: Если метод объявлен с конкретным возвращаемым типом (например, int), он ОБЯЗАН вернуть значение этого типа. Компилятор выдаст ошибку, если в методе нет оператора return с подходящим значением.
Тип void — метод без результата
Иногда метод просто выполняет действие, но ничего не возвращает. Например, метод, который печатает сообщение — он делает свою работу (выводит текст), но вам не нужно получать от него какое-то значение.
public static void показатьМеню() {
System.out.println("=== МЕНЮ ===");
System.out.println("1. Начать игру");
System.out.println("2. Настройки");
System.out.println("3. Выход");
System.out.println("============");
}
public static void main(String[] args) {
показатьМеню();
}
Этот метод не возвращает никакого значения — он просто печатает меню на экран. Тип void означает «пустота» — ничего не возвращается.
Внутри метода типа void можно использовать return; (без значения) для раннего выхода, но об этом мы поговорим чуть позже.
Практическая аналогия: Метод с возвращаемым типом — это как функция калькулятора: вводите данные, получаете результат. Метод void — это как кнопка «включить свет»: вы нажимаете, комната освещается, но калькулятор ничего не «возвращает».
Ключевое слово return: как метод «отдаёт» результат
Оператор return выполняет две важные функции:
- Возвращает значение из метода тому, кто его вызвал
- Завершает выполнение метода и передаёт управление обратно
Представьте, что вы звоните в справочное бюро. Вы задаёте вопрос (вызываете метод), оператор ищет информацию (тело метода), а потом говорит вам ответ (return) и кладёт трубку (выход из метода).
Пример: return возвращает значение
public static int максимум(int a, int b) {
if (a > b) {
return a;
} else {
return b;
}
}
public static void main(String[] args) {
int наибольшее = максимум(15, 23);
System.out.println("Наибольшее: " + наибольшее);
}
Здесь return a; или return b; возвращает одно из значений. Второй return никогда не выполнится, потому что первый уже завершит работу метода.
Ранний выход из метода
Иногда нужно прервать выполнение метода досрочно. Например, если входные данные некорректны:
public static double разделить(double a, double b) {
if (b == 0) {
System.out.println("Ошибка: деление на ноль!");
return 0;
}
return a / b;
}
public static void main(String[] args) {
double результат1 = разделить(10, 2);
double результат2 = разделить(10, 0);
System.out.println("10 / 2 = " + результат1);
System.out.println("10 / 0 = " + результат2);
}
Если делитель равен нулю, метод выводит ошибку и сразу возвращает 0, не выполняя деление. Это защита от краша программы.
return без значения в методах void
В методе типа void можно использовать return; (без значения) для раннего выхода:
public static void проверитьВозраст(int возраст) {
if (возраст < 0) {
System.out.println("Возраст не может быть отрицательным!");
return;
}
if (возраст < 18) {
System.out.println("Вы ещё несовершеннолетний.");
} else {
System.out.println("Вы совершеннолетний.");
}
}
public static void main(String[] args) {
проверитьВозраст(-5);
проверитьВозраст(15);
проверитьВозраст(25);
}
Если возраст отрицательный, метод печатает ошибку и выходит, не выполняя остальной код.
Распространённая ошибка: Забыть указать return в методе, который возвращает значение. Компилятор выдаст ошибку: «missing return statement». Всегда проверяйте, что ваш метод возвращает значение, если его возвращаемый тип — не void.
Ещё один пример с ранним выходом — метод проверки пароля:
public static boolean проверитьПароль(String пароль) {
if (пароль == null || пароль.isEmpty()) {
System.out.println("Пароль не может быть пустым!");
return false;
}
if (пароль.length() < 6) {
System.out.println("Пароль слишком короткий (минимум 6 символов).");
return false;
}
System.out.println("Пароль принят!");
return true;
}
public static void main(String[] args) {
System.out.println("Пароль 'abc': " + проверитьПароль("abc"));
System.out.println("Пароль 'qwerty': " + проверитьПароль("qwerty"));
}
Результат:
Пароль слишком короткий (минимум 6 символов).
Пароль 'abc': false
Пароль принят!
Пароль 'qwerty': true
Именование методов: правила и соглашения
Имя метода — это его визитная карточка. Хорошее имя сразу говорит, что делает метод. Плохое имя заставляет читать код, чтобы понять его purpose.
Правила именования методов в Java:
- Имя начинается с маленькой буквы — в отличие от классов, которые начинаются с большой. Это convention (соглашение), не требование компилятора.
- camelCase (верблюжий регистр) — если имя состоит из нескольких слов, каждое следующее слово пишется с большой буквы без пробелов. Например:
получитьИмя(),рассчитатьСумму(),проверитьВозраст(). - Глагол в начале — имя метода должно начинаться с глагола, потому что метод выполняет действие:
напечатать(),получить(),установить(),проверить(),рассчитать(). - Без пробелов и специальных символов — только буквы, цифры, знак подчёркивания и символ доллара (но доллар лучше не использовать).
- Осмысленное имя — метод
д()бесполезен, а методполучитьДатуРождения()понятен сразу.
Хорошие имена методов:
public static void напечататьПриветствие(String имя) { ... }
public static int получитьКвадрат(int число) { ... }
public static double рассчитатьСреднее(double a, double b) { ... }
public static boolean являетсяПолнолетним(int возраст) { ... }
public static String получитьСтрочкуВВерхнемРегистре(String текст) { ... }
Плохие имена методов:
public static void Method1() { ... } // цифра, непонятно что делает
public static void doStuff() { ... } // что за "stuff"?
public static void A() { ... } // слишком короткое имя
public static void print_the_menu() { ... } // подчёркивания вместо camelCase
public static void НАПЕЧАТАТЬ() { ... } // ЗАГЛАВНЫЕ — плохой стиль
Совет на будущее: Когда вы пишете имя метода, задайте себе вопрос: «Если кто-то другой, не видя кода, увидит только имя метода, поймёт ли он, что делает этот метод?» Если ответ «нет» — придумайте более информативное имя.
Некоторые распространённые префиксы имен методов в Java:
- get...() — получить значение:
getИмя(),getВозраст() - set...() — установить значение:
setИмя("Анна") - is...() — проверить условие:
isActive(),isEmpty() - has...() — проверить наличие:
hasChildren() - print...() — напечатать:
printMenu()
Вызов метода: с объектом и без (static)
Методы можно вызывать двумя способами: через объект класса (экземплярные методы) или напрямую через имя класса (статические методы). Разберём разницу.
Статические методы (static)
Статический метод принадлежит классу, а не конкретному объекту. Его можно вызвать, не создавая экземпляр класса. Это как общедоступная кнопка: не нужно заходить в конкретный автомат, чтобы нажать кнопку.
public class Калькулятор {
public static int сложить(int a, int b) {
return a + b;
}
public static int вычесть(int a, int b) {
return a - b;
}
}
public class Main {
public static void main(String[] args) {
int сумма = Калькулятор.сложить(5, 3);
int разность = Калькулятор.вычесть(10, 4);
System.out.println("5 + 3 = " + сумма);
System.out.println("10 - 4 = " + разность);
}
}
Мы вызываем методы через имя класса: Калькулятор.сложить(), не создавая объект new Калькулятор(). Это возможно благодаря ключевому слову static.
Статические методы — это те методы, которые мы используем уже很久, не замечая этого:
public static void main(String[] args) {
System.out.println("Привет"); // println — статический метод
int a = Integer.parseInt("42"); // parseInt — статический метод
double b = Math.sqrt(144); // sqrt — статический метод
}
Эти методы мы вызываем через имя класса (System, Integer, Math), без создания объектов.
Экземплярные методы (без static)
Экземплярный метод принадлежит конкретному объекту. Чтобы его вызвать, нужно сначала создать объект класса.
public class Кошка {
String имя;
int возраст;
public void представиться() {
System.out.println("Меня зовут " + имя + ", мне " + возраст + " лет.");
}
public boolean старше(Кошка другаяКошка) {
return this.возраст > другаяКошка.возраст;
}
}
public class Main {
public static void main(String[] args) {
Кошка кошка1 = new Кошка();
кошка1.имя = "Мурка";
кошка1.возраст = 3;
Кошка кошка2 = new Кошка();
кошка2.имя = "Барсик";
кошка2.возраст = 5;
кошка1.представиться();
кошка2.представиться();
if (кошка2.старше(кошка1)) {
System.out.println(кошка2.имя + " старше, чем " + кошка1.имя);
} else {
System.out.println(кошка1.имя + " старше или равна " + кошка2.имя);
}
}
}
Результат:
Меня зовут Мурка, мне 3 лет.
Меня зовут Барсик, мне 5 лет.
Барсик старше, чем Мурка
Мы вызываем метод представиться() через объекты: кошка1.представиться() и кошка2.представиться(). Каждый объект «помнит» свои данные.
Когда что использовать? Статические методы подходят для утилитных функций (математические операции, конвертация форматов, проверки). Экземплярные методы — когда действие зависит от конкретного объекта (мой кот мяукает, мой счёт имеет баланс).
Ещё важный момент: статический метод не может обращаться к нестатическим переменным и методам класса. Это как вы не можете из автобуса забрать вещь из чужого чемодана:
public class Пример {
String имя = "Анна"; // нестатическая переменная
public static void показатьИмя() {
System.out.println(имя); // ОШИБКА! Статический метод не может обращаться к нестатической переменной
}
}
Если вам нужно обращаться к переменным класса из статического метода, либо сделайте переменную static, либо создайте объект:
public class Пример {
String имя = "Анна";
public static void показатьИмя() {
Пример объект = new Пример();
System.out.println(объект.имя);
}
}
Параметры метода: передача данных внутрь
Параметры — это переменные, которые метод получает при вызове. Это как аргументы в рецепте: «возьмите 2 яйца, 100 мл молока» — здесь 2 и 100 — это конкретные значения (аргументы), а «яйца» и «молоко» — это параметры.
Разберём ключевое понятие: параметр (parameter) — это переменная в объявлении метода, а аргумент (argument) — это конкретное значение, передаваемое при вызове.
// "int a" и "int b" — это параметры
public static int сложить(int a, int b) {
return a + b;
}
public static void main(String[] args) {
// 5 и 3 — это аргументы
int результат = сложить(5, 3);
}
Множественные параметры
Метод может принимать любое количество параметров (в разумных пределах — обычно до 7-8, дальше код становится трудночитаемым):
public static void показатьИнформацию(String имя, int возраст, double рост, String город) {
System.out.println("Имя: " + имя);
System.out.println("Возраст: " + возраст);
System.out.println("Рост: " + рост + " см");
System.out.println("Город: " + город);
}
public static void main(String[] args) {
показатьИнформацию("Анна", 25, 168.5, "Москва");
System.out.println("---");
показатьИнформацию("Пётр", 32, 185.0, "Санкт-Петербург");
}
Результат:
Имя: Анна
Возраст: 25
Рост: 168.5 см
Город: Москва
---
Имя: Пётр
Возраст: 32
Рост: 185.0 см
Город: Санкт-Петербург
Методы без параметров
Не все методы принимают данные. Некоторые работают автономно:
public static void показатьДату() {
java.time.LocalDate сегодня = java.time.LocalDate.now();
System.out.println("Сегодня: " + сегодня);
}
public static void напечататьРазделитель() {
System.out.println("=============================");
}
public static void main(String[] args) {
показатьДату();
напечататьРазделитель();
System.out.println("Начало программы");
напечататьРазделитель();
}
Правило порядка параметров: Параметры передаются строго по порядку. Первый аргумент попадает в первый параметр, второй — во второй, и так далее. Если перепутать порядок, программа может работать некорректно (например, принять возраст вместо имени).
Вот пример, где порядок параметров критически важен:
public static void создатьПользователя(String имя, String фамилия, int возраст) {
System.out.println("Создан пользователь: " + имя + " " + фамилия + ", " + возраст + " лет");
}
public static void main(String[] args) {
создатьПользователя("Иван", "Петров", 25); // Правильно
создатьПользователя(25, "Иван", "Петров"); // ОШИБКА КОМПИЛЯЦИИ! int вместо String
}
Компилятор выдаст ошибку, потому что типы аргументов не совпадают с типами параметров.
Принцип DRY (Don't Repeat Yourself)
DRY — это один из самых важных принципов в программировании. Он гласит: никогда не повторяй один и тот же код дважды. Если вы видите, что одна и та же команда или блок кода появляется в нескольких местах — это сигнал, что пора создать метод.
Аналогия из жизни: если каждый день вы собираете одни и те же продукты по одному и тому же списку, вы ведь записываете этот список один раз и пользуетесь им? А не пишете заново каждый день?
Пример 1: Повторяющийся вывод
До (плохо — код повторяется):
public static void main(String[] args) {
System.out.println("╔══════════════════════╗");
System.out.println("║ ОТЧЁТ О ПРОДАЖАХ ║");
System.out.println("╚══════════════════════╝");
System.out.println("Продажи за январь: 500 000 руб.");
System.out.println("╔══════════════════════╗");
System.out.println("║ ОТЧЁТ О ПРОДАЖАХ ║");
System.out.println("╚══════════════════════╝");
System.out.println("Продажи за февраль: 650 000 руб.");
System.out.println("╔══════════════════════╗");
System.out.println("║ ОТЧЁТ О ПРОДАЖАХ ║");
System.out.println("╚══════════════════════╝");
System.out.println("Продажи за март: 720 000 руб.");
}
После (хорошо — код не повторяется):
public static void напечататьЗаголовок() {
System.out.println("╔══════════════════════╗");
System.out.println("║ ОТЧЁТ О ПРОДАЖАХ ║");
System.out.println("╚══════════════════════╝");
}
public static void main(String[] args) {
напечататьЗаголовок();
System.out.println("Продажи за январь: 500 000 руб.");
напечататьЗаголовок();
System.out.println("Продажи за февраль: 650 000 руб.");
напечататьЗаголовок();
System.out.println("Продажи за март: 720 000 руб.");
}
Пример 2: Повторяющиеся вычисления
До (плохо):
public static void main(String[] args) {
double цена1 = 1500;
double количество1 = 10;
double сумма1 = цена1 * количество1;
double скидка1 = сумма1 * 0.1;
double итого1 = сумма1 - скидка1;
System.out.println("Заказ 1: " + итого1 + " руб.");
double цена2 = 2300;
double количество2 = 5;
double сумма2 = цена2 * количество2;
double скидка2 = сумма2 * 0.1;
double итого2 = сумма2 - скидка2;
System.out.println("Заказ 2: " + итого2 + " руб.");
double цена3 = 800;
double количество3 = 20;
double сумма3 = цена3 * количество3;
double скидка3 = сумма3 * 0.1;
double итого3 = сумма3 - скидка3;
System.out.println("Заказ 3: " + итого3 + " руб.");
}
После (хорошо):
public static double рассчитатьИтого(double цена, double количество) {
double сумма = цена * количество;
double скидка = сумма * 0.1;
return сумма - скидка;
}
public static void main(String[] args) {
double итого1 = рассчитатьИтого(1500, 10);
System.out.println("Заказ 1: " + итого1 + " руб.");
double итого2 = рассчитатьИтого(2300, 5);
System.out.println("Заказ 2: " + итого2 + " руб.");
double итого3 = рассчитатьИтого(800, 20);
System.out.println("Заказ 3: " + итого3 + " руб.");
}
Мы вынесли расчёт в отдельный метод. Теперь, если формула скидки изменится (например, с 10% на 15%), нам нужно будет изменить только одну строку — внутри метода рассчитатьИтого().
Пример 3: Повторяющиеся проверки
До (плохо):
public static void main(String[] args) {
int возраст1 = 15;
if (возраст1 >= 0 && возраст1 <= 150) {
System.out.println("Возраст " + возраст1 + " допустим");
} else {
System.out.println("Возраст " + возраст1 + " недопустим");
}
int возраст2 = 200;
if (возраст2 >= 0 && возраст2 <= 150) {
System.out.println("Возраст " + возраст2 + " допустим");
} else {
System.out.println("Возраст " + возраст2 + " недопустим");
}
}
После (хорошо):
public static boolean являетсяВалиднымВозрастом(int возраст) {
return возраст >= 0 && возраст <= 150;
}
public static void main(String[] args) {
int возраст1 = 15;
if (являетсяВалиднымВозрастом(возраст1)) {
System.out.println("Возраст " + возраст1 + " допустим");
} else {
System.out.println("Возраст " + возраст1 + " недопустим");
}
int возраст2 = 200;
if (являетсяВалиднымВозрастом(возраст2)) {
System.out.println("Возраст " + возраст2 + " допустим");
} else {
System.out.println("Возраст " + возраст2 + " недопустим");
}
}
Почему DRY так важен?
- Легче исправлять ошибки — баг исправляется в одном месте, а не в дюжине копий
- Код становится короче — меньше строк, меньше шум, легче читать
- Легче тестировать — тестирование одного метода вместо повторного кода
- Легче менять логику — изменение одной строки обновляет все места использования
Методы из стандартной библиотеки Java
Java поставляется с огромным набором готовых методов в стандартной библиотеке. Зачем изобретать велосипед, если можно воспользоваться готовыми решениями?
Класс Math — математические операции
Класс Math содержит статические методы для математических вычислений:
public static void main(String[] args) {
System.out.println("Math.abs(-10) = " + Math.abs(-10)); // 10 (модуль числа)
System.out.println("Math.abs(5) = " + Math.abs(5)); // 5
System.out.println("Math.max(10, 20) = " + Math.max(10, 20)); // 20 (большее)
System.out.println("Math.min(10, 20) = " + Math.min(10, 20)); // 10 (меньшее)
System.out.println("Math.sqrt(144) = " + Math.sqrt(144)); // 12.0 (кв. корень)
System.out.println("Math.pow(2, 10) = " + Math.pow(2, 10)); // 1024.0 (степень)
System.out.println("Math.random() = " + Math.random()); // случайное 0.0-1.0
System.out.println("Math.round(3.7) = " + Math.round(3.7)); // 4 (округление)
System.out.println("Math.ceil(3.2) = " + Math.ceil(3.2)); // 4.0 (округление вверх)
System.out.println("Math.floor(3.9) = " + Math.floor(3.9)); // 3.0 (округление вниз)
}
Все эти методы — статические, поэтому мы вызываем их через имя класса Math, не создавая объекты.
Класс String — работа со строками
Строки в Java — это объекты, поэтому их методы вызываются через конкретную строку:
public static void main(String[] args) {
String имя = "Привет, мир!";
System.out.println("Длина строки: " + имя.length()); // 12
System.out.println("Символ [0]: " + имя.charAt(0)); // П
System.out.println("Символ [7]: " + имя.charAt(7)); // м
System.out.println("Верхний регистр: " + имя.toUpperCase()); // ПРИВЕТ, МИР!
System.out.println("Нижний регистр: " + имя.toLowerCase()); // привет, мир!
System.out.println("Содержит 'мир'? " + имя.contains("мир")); // true
System.out.println("Начинается с 'Привет'? " + имя.startsWith("Привет")); // true
System.out.println("Заканчивается на 'мир!'? " + имя.endsWith("мир!")); // true
System.out.println("Замена: " +名称.replace("мир", "Java")); // Привет, Java!
}
Обратите внимание: length(), toUpperCase(), contains() — это методы строки. Мы вызываем их через объект имя.
Класс System.out — вывод на экран
Вы уже использовали System.out.println(), но есть и другие методы вывода:
public static void main(String[] args) {
System.out.println("Это строка с переносом"); // выводит и переносит строку
System.out.print("Без переноса "); // выводит без переноса
System.out.print("на той же строке"); // продолжает на той же строке
System.out.println(); // пустая строка
System.out.printf("Сумма: %.2f руб.", 1234.5); // форматированный вывод
}
Результат:
Это строка с переносом
Без переноса на той же строке
Сумма: 1234.50 руб.
Как узнать, какие методы доступны? В среде разработки (IDE) наберите имя класса или объекта и поставьте точку — IDE покажет список доступных методов с описаниями. Также можно прочитать официальную документацию Oracle по Java.
Параметры по умолчанию: как обойти ограничение Java
В некоторых языках программирования можно задавать значения параметров по умолчанию. В Java这样的功能 нет, но есть классический приём — перегрузка методов (мы изучим её подробно в следующем уроке) или использование «пустышек».
Пока что запомните: все параметры метода обязательны. Если метод объявлен как void приветствие(String имя), вы обязаны передать имя при вызове.
Практический совет: Не создавайте методы слишком длинными (больше 20-30 строк). Если метод становится длинным, разбейте его на несколько меньших методов. Это делает код чище и понятнее.
Композиция методов: методы из методов
Методы можно вызывать внутри других методов. Это как конструктор LEGO: одна деталь собирается из других деталей, а те — из ещё более мелких.
public static String получитьИмяВРодительномПадеже(String имя) {
return имя + "ой";
}
public static String получитьПриветствие(String имя) {
String имяВРодПадеже = получитьИмяВРодительномПадеже(имя);
return "Добро пожаловать, " + имяВРодПадеже + "!";
}
public static void показатьКарточку(String имя, int возраст) {
String приветствие = получитьПриветствие(имя);
System.out.println(приветствие);
System.out.println("Возраст: " + возраст + " лет");
}
public static void main(String[] args) {
показатьКарточку("Иван", 25);
System.out.println("---");
показатьКарточку("Мария", 30);
}
Результат:
Добро пожаловать, Иваной!
Возраст: 25 лет
---
Добро пожаловать, Марияой!
Возраст: 30 лет
Каждый метод делает одну маленькую задачу, а метод показатьКарточку координирует работу всех остальных. Это принцип «одна ответственность» — каждый метод должен отвечать за одну конкретную вещь.
Область видимости переменных в методах
Переменные, объявленные внутри метода, существуют только внутри этого метода. Это как содержимое шкафа — оно видно только тому, кто открывает этот шкаф, а не соседнему.
public static void метод1() {
int число = 10;
System.out.println("В методе 1: " + число);
}
public static void метод2() {
System.out.println(число); // ОШИБКА! Переменная "число" не видна здесь
}
public static void main(String[] args) {
метод1();
метод2();
}
Переменная число объявлена внутри метод1(), поэтому она «умирает», как только метод завершается. Метод метод2() не имеет к ней доступа.
Внутри метода переменные также имеют свою область видимости — от места объявления до конца блока:
public static void пример() {
int a = 10;
System.out.println(a); // Работает
if (a > 5) {
int b = 20;
System.out.println(a); // Работает
System.out.println(b); // Работает
}
System.out.println(a); // Работает
System.out.println(b); // ОШИБКА! Переменная b не видна за пределами if
}
Переменная b объявлена внутри блока if, поэтому она существует только в пределах этого блока. После закрывающей фигурной скобки } она недоступна.
Почему это важно? Область видимости защищает от случайных ошибок. Вы не можете случайно изменить переменную из другого метода, потому что она просто не видна. Это делает код безопаснее и предсказуемее.
Полные примеры: всё вместе
Давайте соберём всё вместе и создадим несколько полноценных примеров.
Пример 1: Простой калькулятор
public class Калькулятор {
public static double сложить(double a, double b) {
return a + b;
}
public static double вычесть(double a, double b) {
return a - b;
}
public static double умножить(double a, double b) {
return a * b;
}
public static double разделить(double a, double b) {
if (b == 0) {
System.out.println("Ошибка: деление на ноль!");
return 0;
}
return a / b;
}
public static double получитьПроцент(double число, double процент) {
return число * процент / 100;
}
public static void показатьРезультат(String операция, double a, double b, double результат) {
System.out.println(a + " " + операция + " " + b + " = " + результат);
}
public static void main(String[] args) {
double a = 15;
double b = 4;
double сумма = сложить(a, b);
показатьРезультат("+", a, b, сумма);
double разность = вычесть(a, b);
показатьРезультат("-", a, b, разность);
double произведение = умножить(a, b);
показатьРезультат("*", a, b, произведение);
double частное = разделить(a, b);
показатьРезультат("/", a, b, частное);
double процент = получитьПроцент(сумма, 10);
System.out.println("10% от " + сумма + " = " + процент);
}
}
Результат:
15.0 + 4.0 = 19.0
15.0 - 4.0 = 11.0
15.0 * 4.0 = 60.0
15.0 / 4.0 = 3.75
10% от 19.0 = 1.9
Пример 2: Генератор паролей
public class ГенераторПаролей {
static String буквы = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static String цифры = "0123456789";
static String спецсимволы = "!@#$%^&*";
public static char получитьСлучайныйСимвол(String набор) {
int индекс = (int) (Math.random() * набор.length());
return набор.charAt(индекс);
}
public static String сгенерироватьПароль(int длина, boolean сЦифрами, boolean соСпецсимволами) {
String доступныеБуквы = буквы;
if (сЦифрами) доступныеБуквы += цифры;
if (соСпецсимволами) доступныеБуквы += спецсимволы;
StringBuilder пароль = new StringBuilder();
for (int i = 0; i < длина; i++) {
пароль.append(получитьСлучайныйСимвол(доступныеБуквы));
}
return пароль.toString();
}
public static void показатьПароль(String описание, String пароль) {
System.out.println(описание + ": " + пароль);
}
public static void main(String[] args) {
String пароль1 = сгенерироватьПароль(8, false, false);
показатьПароль("Только буквы", пароль1);
String пароль2 = сгенерироватьПароль(10, true, false);
показатьПароль("Буквы + цифры", пароль2);
String пароль3 = сгенерироватьПароль(12, true, true);
показатьПароль("Буквы + цифры + спецсимволы", пароль3);
}
}
Примерный результат (каждый раз разный):
Только буквы: KXQMZRBP
Буквы + цифры: 8FKQ2M9X4T
Буквы + цифры + спецсимволы: K8#M2@Q9$F4R
Пример 3: Конвертер температуры
public class КонвертерТемпературы {
public static double вЦельсий(double фаренгейт) {
return (фаренгейт - 32) * 5.0 / 9.0;
}
public static double вФаренгейт(double цельсий) {
return цельсий * 9.0 / 5.0 + 32;
}
public static String описаниеТемпературы(double цельсий) {
if (цельсий < 0) return "мороз";
if (цельсий < 15) return "холодно";
if (цельсий < 25) return "комфортно";
if (цельсий < 35) return "тепло";
return "жарко";
}
public static void показатьКонвертацию(double температура, String исходнаяШкала) {
if (исходнаяШкала.equals("F")) {
double цельсий = вЦельсий(температура);
System.out.printf("%.1f°F = %.1f°C (%s)%n", температура, цельсий, описаниеТемпературы(цельсий));
} else {
double фаренгейт = вФаренгейт(температура);
System.out.printf("%.1f°C = %.1f°F%n", температура, фаренгейт);
}
}
public static void main(String[] args) {
показатьКонвертацию(32, "F");
показатьКонвертацию(100, "F");
показатьКонвертацию(0, "C");
показатьКонвертацию(20, "C");
показатьКонвертацию(37, "C");
}
}
Примерный результат:
32.0°F = 0.0°C (мороз)
100.0°F = 37.8°C (тепло)
0.0°C = 32.0°F
20.0°C = 68.0°F
37.0°C = 98.6°F
Пример 4: Проверка валидности email
public class ПроверкаПочты {
public static boolean содержитСобаку(String email) {
return email.contains("@");
}
public static boolean содержитТочку(String email) {
return email.contains(".");
}
public static boolean неПустой(String email) {
return email != null && !email.isEmpty();
}
public static boolean являетсяВалиднымEmail(String email) {
if (!неПустой(email)) {
System.out.println("Email не может быть пустым!");
return false;
}
if (!содержитСобаку(email)) {
System.out.println("Email должен содержать '@': " + email);
return false;
}
if (!содержитТочку(email)) {
System.out.println("Email должен содержать '.': " + email);
return false;
}
int позицияСобаки = email.indexOf("@");
int позицияТочки = email.lastIndexOf(".");
if (позицияСобаки >= позицияТочки) {
System.out.println("Точка должна быть после '@': " + email);
return false;
}
return true;
}
public static void main(String[] args) {
String[] emailы = {"user@mail.ru", "invalid-email", "missing.at.com", "@missing.com", "user.name@mail.ru"};
for (String email : emailы) {
boolean валидный = являетсяВалиднымEmail(email);
System.out.println(email + " -> " + (валидный ? "валиден" : "невалиден"));
System.out.println();
}
}
}
Результат:
user@mail.ru -> валиден
Email должен содержать '@': invalid-email
invalid-email -> невалиден
Email должен содержать '.': missing.at.com
missing.at.com -> невалиден
Точка должна быть после '@': @missing.com
@missing.com -> невалиден
user.name@mail.ru -> валиден
Обратите внимание, как каждый метод отвечает за одну проверку. Это делает код читаемым и позволяет легко добавлять новые проверки.
Распространённые ошибки при работе с методами
Давайте разберём типичные ошибки, которые допускают новички при работе с методами.
Ошибка 1: Забыли return в методе с возвращаемым типом
public static int получитьКвадрат(int число) {
int результат = число * число;
// ОШИБКА: отсутствует return
}
Компилятор выдаст: «missing return statement». Исправление: добавить return результат;.
Ошибка 2: Неправильное количество аргументов
public static int сумма(int a, int b) {
return a + b;
}
public static void main(String[] args) {
int результат = сумма(5); // ОШИБКА: метод принимает 2 аргумента, передан 1
}
Компилятор выдаст: «method sum in class ... cannot be applied to given types».
Ошибка 3: Попытка вернуть неправильный тип
public static int получитьИмя() {
return "Анна"; // ОШИБКА: метод возвращает int, а передаётся String
}
Компилятор выдаст: «incompatible types: String cannot be converted to int».
Ошибка 4: Вызов нестатического метода из статического контекста
public class Пример {
String имя = "Анна";
public void показатьИмя() {
System.out.println(имя);
}
public static void main(String[] args) {
показатьИмя(); // ОШИБКА: статический метод не может вызвать нестатический
}
}
Исправление: создать объект или сделать метод static.
Совет: Всегда читайте сообщения компилятора! Java даёт понятные и подробные описания ошибок. Они часто подсказывают, что именно пошло не так и как это исправить.
Практические задания
Попробуйте решить следующие задачи, используя методы:
Задание 1: Создайте метод double получитьПлощадьКруга(double радиус), который возвращает площадь круга (формула: π * r²). Используйте Math.PI.
public static double получитьПлощадьКруга(double радиус) {
return Math.PI * радиус * радиус;
}
public static void main(String[] args) {
System.out.println("Площадь круга r=5: " + получитьПлощадьКруга(5));
System.out.println("Площадь круга r=10: " + получитьПлощадьКруга(10));
}
Задание 2: Создайте метод String получитьИменованноеЧисло(int число), который возвращает строку вида: «1 яблоко», «2 яблока», «5 яблок».
public static String получитьИменованноеЧисло(int число) {
int последняяЦифра = число % 10;
int последниеДве = число % 100;
if (последниеДве >= 11 && последниеДве <= 19) {
return число + " яблок";
} else if (последняяЦифра == 1) {
return число + " яблоко";
} else if (последняяЦифра >= 2 && последняяЦифра <= 4) {
return число + " яблока";
} else {
return число + " яблок";
}
}
public static void main(String[] args) {
for (int i = 0; i <= 20; i++) {
System.out.println(получитьИменованноеЧисло(i));
}
}
Задание 3: Создайте метод boolean являетсяПалиндромом(String слово), который проверяет, читается ли слово одинаково в обоих направлениях.
public static boolean являетсяПалиндромом(String слово) {
String прямое = слово.toLowerCase();
String обратное = new StringBuilder(прямое).reverse().toString();
return прямое.equals(обратное);
}
public static void main(String[] args) {
System.out.println("мадам: " + являетсяПалиндромом("мадам"));
System.out.println("привет: " + являетсяПалиндромом("привет"));
System.out.println("шалаш: " + являетсяПалиндромом("шалаш"));
}
Итоги урока
- ✅ Метод — это именованный блок кода, который выполняет определённую задачу. Аналогия: рецепт в записной книжке
- ✅ Структура метода: модификатор доступа, возвращаемый тип, имя, параметры, тело
- ✅ Модификаторы доступа:
public(везде),protected(тот же пакет + наследники),private(только свой класс), без модификатора (тот же пакет) - ✅ Возвращаемый тип:
void— ничего не возвращает; конкретный тип (int,String,booleanи т.д.) — возвращает значение - ✅ Ключевое слово
returnвозвращает значение и завершает выполнение метода. Вvoid-методах можно использоватьreturn;для раннего выхода - ✅ Имена методов пишутся в camelCase, начинаются с глагола, содержат осмысленное описание
- ✅ Статические методы (
static) вызываются через имя класса:Math.abs(-5); экземплярные — через объект:кошка.мяукнуть() - ✅ Принцип DRY (Don't Repeat Yourself): никогда не повторяй один и тот же код — выноси его в метод
- ✅ Стандартная библиотека предоставляет готовые методы:
Math.abs(),Math.max(),String.length(),System.out.println() - ✅ Переменные, объявленные внутри метода, доступны только в пределах этого метода (область видимости)
- ✅ Методы можно вызывать внутри других методов для создания сложной логики из простых частей
Следующий урок:
Перегрузка методов (Overloading) →Тест по уроку: Объявление и вызов методов
10 вопросов