Метод в Java это именованный блок кода внутри класса, который решает одну задачу и который можно вызывать сколько угодно раз. Объявление метода читается слева направо и состоит из четырех частей: модификатор доступа (кто имеет право вызвать метод), возвращаемый тип (что метод отдает обратно, или void, если ничего), имя (глагол в нижнем верблюжьем регистре) и список параметров в круглых скобках. Дальше в фигурных скобках идет тело, то есть то, что метод собственно делает. Разберем каждую часть по очереди.

Кратко

  • Метод это именованный блок кода внутри класса. Объявление состоит из модификатора доступа, возвращаемого типа, имени и списка параметров.
  • Модификаторов доступа четыре: public, protected, пакетный (когда слова нет вовсе) и private. Они задают, откуда метод виден.
  • Возвращаемый тип указывать обязательно. Если возвращать нечего, пишут void: тогда return не нужен, но им можно досрочно выйти из метода.
  • Имя начинают со строчной буквы и пишут в верблюжьем стиле, а начинают обычно с глагола: getCat, createCar, delete.
  • Параметров может не быть вовсе, а может быть переменное число через многоточие: String... names. Внутри метода это обычный массив.
  • Перегрузка это несколько методов с одним именем и разными параметрами. Нужный компилятор выбирает сам, по типам аргументов на месте вызова.
Кухня ресторана, где у каждого повара подписана своя роль: Dish Pit, Prep, Line Cook, Sous Chef, Chef de CuisineВ Java приложение состоит из классов. Классы, в свою очередь, состоят из переменных. Они отвечают за хранение данных и методов, которые отвечают за поведение класса: иначе говоря, логику, которую он может предоставлять (например, обработку некоторых данных, вызов других методов, и т. д.). Говорить о таких составляющих как переменные можно долго, но мы сегодня не для этого собрались. Давайте лучше поговорим о такой составляющей класса как метод. Кадр-мем с подписью «Это не наш метод»Метод это именованный блок кода, объявляемый внутри класса. Он содержит некоторую законченную последовательность действий (инструкций), направленных на решение отдельной задачи, который можно многократно использовать. Иными словами, метод это некоторая функция: что-то, что умеет делать ваш класс. В других языках тоже присутствуют функции. Только в Java они являются членами классов и, согласно терминологии ООП, называются методами. Но прежде чем продолжить, давайте рассмотрим небольшой пример:

public String constructHelloSentence(String name) {
  String resultSentence = "Hello world! My name is " + name;
  System.out.println(resultSentence);
  return resultSentence;
}
Тут ничего сложного: метод Java, задача которого сформировать строку приветствия, с именем, которое мы ему передаем. Как например Hello world! My name is Bobby Давайте как следует разберемся с построением метода, рассмотрев каждое ключевое слово в объявлении метода (слева направо). Наше первое ключевое слово это public, и оно обозначает модификатор доступа:

Модификаторы доступа

Модификаторы доступа указывают допустимую область видимости для членов класса, то есть ограничение мест, в которых разрешается использовать какую-то переменную или метод. Пирамида модификаторов доступа: снизу вверх public, protected, default (package-private), private, стрелка вниз показывает убывание уровня закрытостиВ языке Java применяют такие модификаторы доступа:
  • public: публичный. Методы или поля с этим модификатором общедоступны, видимы другим классам (а точнее, их методам и полям) из текущего пакета и из внешних пакетов. Это самый широкий уровень доступа из известных;

  • protected: к методам или переменным с этим модификатором есть доступ из любого места в текущем классе или пакете, или в классах, наследующих данный, а заодно и методы или поля, даже если они находятся в других пакетах

    
    protected String constructHelloSentence(String name) {...}
    
  • Модификатор по умолчанию. Если у поля или метода класса нет модификатора, применяется модификатор по умолчанию. В таком случае поля или методы видны всем классам в текущем пакете (как protected, только с отсутствием видимости при наследовании).

    
    String constructHelloSentence(String name) {...}
    
  • private: антипод модификатора public. Метод или переменная с таким модификатором доступны исключительно в классе, в котором они объявлены.

    
    private String constructHelloSentence(String name) {...}
    
Если свести все четыре в одну таблицу, картина такая:
Модификатор Свой класс Свой пакет Наследник из другого пакета Любой класс
private Да Нет Нет Нет
без модификатора (пакетный) Да Да Нет Нет
protected Да Да Да Нет
public Да Да Да Да
Далее мы имеем String в сигнатуре метода (первая строка метода, описывающая его свойства).

Возвращаемое значение

Возвращаемое значение это данные (некий результат выполнения метода), которые приходят на его место после вызова. Каждый метод имеет возвращаемое значение. Или нет?

Методы с возвращаемым значением

Это значение может быть данными любого вида: как переменной простого типа, так и ссылочного. В рассматриваемом примере мы указываем, что метод должен вернуть объект типа String, что как мы помним, является классом, описывающим строку. Второй момент здесь это слово return. Оно имеет прямое отношение к возвращаемому значению: значение, стоящее после него, будет отправлено назад, на место вызова метода, а сам же метод после return закроется. Это слово обычно идет в последней строке метода (кроме методов с различными ветвлениями типа if, else...). Если написать код в следующей строке после return:

private String constructHelloSentence(String name) {
  String resultSentence = "Hello world! My name is " + name;
  return resultSentence;
  System.out.println(resultSentence);
}
то мы получим ругательства компилятора, что не очень хорошо (компилятор ерунду не посоветует). Также нужно помнить, что тип данных после return должен совпадать с объявленным в сигнатуре метода. Подробнее о return читайте здесь.

void

Для чего служит void в Java? Не у всех методов есть возвращаемое значение. Некоторым или нечего, или не нужно ничего возвращать. Что же тогда делать? Тогда в сигнатуре метода на место возвращаемого значения мы пишем void. Как бы выглядел наш метод без возвращаемого значения?

protected void constructHelloSentence(String name) {
  String resultSentence = "Hello world! My name is " + name;
  System.out.println(resultSentence);
}
Вы наверняка заметили, что вместе с возвращаемым значением у нас исчезло слово return. Так и есть, ведь наш метод и не должен ничего возвращать. Тем не менее, его можно тут поставить, но без какого-то значения, просто return; в последней строке. Это в целом бесполезно, поэтому в методах с void он необязателен. Тем не менее, его можно применять с пользой в void методах, например, при ветвлениях или циклах, когда нужно немедленно выйти из метода. Далее в объявлении метода у нас шло constructHelloSentence.

Названия методов

constructHelloSentence это название метода, отличительная особенность, по которой мы сможем отличать тот или иной метод. И, соответственно, вызывать тот или иной метод. Желтый стикер на пробковой доске с надписью What is your nameНазвания методов должны начинаться с маленькой буквы и при этом использовать верблюжий стиль (CamelCase, верблюжий регистр): т.е. каждое следующее слово в названии стоит впритык к предыдущему и пишется с большой буквы. Наименования методов должны описывать метод (лучший комментарий это правильное именование). Для этого используйте глаголы или сочетания с глаголами: getCat, delete, createCar, и так далее. В пределах одного класса имена методов должны быть уникальными (не считая перегрузки методов, о чем поговорим немного ниже). Не путай перегрузку с переопределением: это разные вещи, хотя названия и похожи. Смотрим дальше разбираемый нами метод и видим (String name)

Параметры метода

Методы могут иметь (или не иметь) определенные данные, которые будут поступать снаружи, а именно с места, где и был вызван метод. В нашем случае мы видим, что приходит объект типа String с именем name и в дальнейшем мы используем эту переменную в нашем методе. В методе можно использовать неограниченное количество параметров, но больше 7 уже не рекомендуется.

Переменное число аргументов

Когда мы не знаем точное количество элементов, но все эти элементы нужны для одной цели и будут одного типа (например, String), используется многоточие:

public void constructHelloSentence(String...name) {
 ...
}
Обращение к каждому элементу будет такого вида: name[0] Ничего не напоминает? Верно, массив! Внутри метода это он и есть, так что тело можно не менять:

protected void constructHelloSentence(String[] name) {
 ...
}
Обращение к элементам также будет вида: name[1] А вот снаружи разница принципиальная. Метод с многоточием вызывают так, будто никакого массива нет, и можно вообще без аргументов:

constructHelloSentence("Ден", "Ира");
constructHelloSentence();
А метод с массивом требует собрать этот массив руками:

constructHelloSentence(new String[]{"Ден", "Ира"});
То есть «ничего не изменится» верно для тела метода, но не для места вызова. Ради удобства на месте вызова многоточие и придумали. И два жестких правила, о которых стоит знать сразу. Спецификация языка формулирует их так: «At most one variable arity parameter is permitted for a method or constructor. It is a compile-time error if a variable arity parameter appears anywhere in the list of parameter specifiers except the last position». Проще говоря, параметр с многоточием может быть только один и обязан стоять последним. Такая сигнатура не скомпилируется:

// ошибка компиляции: многоточие стоит не последним
public void wrong(String... names, int count) {
 ...
}

Параметры с модификатором final

И еще кое-что. Аргументы метода могут быть final:

public String constructHelloSentence(final String name) {
  ...
}
Это значит, что ссылка name привязана к конкретному объекту String, и переопределить ее нельзя. Про работу с ссылочными переменными и их взаимодействие с зарезервированным словом final можно прочитать в материале “Ссылочные типы данных в Java”.

Вызов методов

Итак, с созданием методов разобрались, теперь давайте поговорим об их использовании. Как вызвать метод в Java? Кот спит, прижавшись мордой к телефону-раскладушкеПочти каждый метод в Java находится в классе. «Почти» тут не случайно: с Java 8 методы с телом умеют жить и в интерфейсах, там появились default- и static-методы, а с Java 9 к ним добавились еще и private (JEP 213: «It is also proposed that interfaces be allowed to have private methods»). Свои методы есть и у перечислений, и у рекордов. Устроены и вызываются они по тем же правилам, так что разбираться будем на самом привычном случае, на классе:

public class StringConstructor {
  public String constructHelloSentence(String name) {
     String resultSentence = "Hello world! My name is " + name;
     System.out.println(resultSentence);
     return resultSentence;
  }
}
Так как у нас метод не является статическим (это отдельная тема для разговора, выходящая за рамки сегодняшней статьи), для его вызова нужно сперва создать объект, и уже у него вызвать метод:

class Application{
  public static void main(String[] args) {
     StringConstructor stringConstructor = new StringConstructor();
     stringConstructor.constructHelloSentence("Den");
  }
}
В аргументы нашего метода мы передали строку (имя), которую хотим видеть в результирующей строке, выведенной на экран:

Hello world! My name is Den
Также стоит напомнить, что методы можно переиспользовать то количество раз, сколько нам потребуется, ограничений нет.

this

Часто в коде можно увидеть ключевое слово this, как например в сеттерах:

public void setValue(Long value) {
   this.value = value;
}
И что же оно значит? this в Java это ссылка на текущий объект данного класса. Например, если мы создали объект:

StringConstructor stringConstructor = new StringConstructor();
то this внутри объекта stringConstructor будет ссылкой на этот же объект. this используется как для ссылки на переменную объекта (как в сеттере выше), так и для вызова некоторого метода. Мы можем немного переписать наш класс:

public class StringConstructor {
 
  public String constructHelloSentence(String name) {
     String resultSentence = this.getSentence()  + name;
     System.out.println(resultSentence);
     return resultSentence;
  }
 
  private String getSentence() {
     return "Hello world! My name is ";
  }
}
Через this мы вызываем метод данного объекта, для взятия необходимой строки. Но все же как правило для методов this почти не используется, так как и без него идет ссылка на метод данного объекта, в основном он используется для ссылки на переменную объекта.

Перегрузка методов

Предположим нам понадобился метод, выполняющий по сути ту же самую логику, но в предложении Hello world! вместо world мы хотим вставить свое слово (строку). Но ведь у нас уже есть метод constructHelloSentence. Значит, нам нужно придумать новое название для метода, который выполняет по сути тот же функционал? Как бы не так: в этот момент на помощь нам приходит перегрузка методов. Попугай крупным планом с широко открытым клювомПерегрузка методов это использование одного и того же имени метода несколько раз при его объявлении в классе. С точки зрения синтаксиса языка, не может быть двух одинаковых имен в некотором локальном пространстве. Но при этом допускается объявление методов с одинаковыми именами но отличающимися аргументами. Иными словами, класс содержит в себе перегруженные методы, когда есть два и более методов с одинаковыми названиями, но различными входными данными:

public class Constructor {
 
  public String constructHelloSentence(String name) {
     String resultSentence = "Hello world! My name is " + name;
     System.out.println(resultSentence);
     return resultSentence;
  }
 
  protected String constructHelloSentence(String firstName, String secondName) {
     String resultSentence = "Hello " + firstName + "! My name is " + secondName;
     System.out.println(resultSentence);
     return resultSentence;
  }
}
Здесь мы видим, что методы не обязаны содержать одинаковый модификатор доступа (как и возвращаемый тип). Но тут есть важная оговорка: различаться только возвращаемым типом перегруженные методы не могут. Возвращаемый тип в сигнатуру не входит, поэтому для компилятора два таких метода это один и тот же метод, объявленный дважды. Спецификация не оставляет вариантов: «It is a compile-time error to declare two methods with override-equivalent signatures in a class». Вот так писать нельзя:

// ошибка компиляции: отличается только возвращаемый тип
public String constructHelloSentence(String name) { ... }
public int constructHelloSentence(String name) { ... }
Различать перегрузки может только список параметров: их типы, количество или порядок. Если вызывается перегруженный метод, то из нескольких объявленных методов компилятор автоматически определяет нужный по параметрам, которые указываются при вызове.

Вопросы и ответы

Из чего состоит объявление метода в Java?

Из четырех частей, которые идут строго в этом порядке. Модификатор доступа говорит, откуда метод разрешено вызывать. Возвращаемый тип говорит, что метод отдает обратно, и если отдавать нечего, там стоит void. Дальше имя метода, а за ним в круглых скобках список параметров. После этого в фигурных скобках идет тело метода. Первая строка целиком, от модификатора до закрывающей круглой скобки, называется сигнатурой.

Чем отличаются модификаторы доступа?

Шириной круга тех, кто может обратиться к методу. Private виден только внутри своего класса. Отсутствие модификатора, его называют пакетным доступом, открывает метод всему своему пакету. Protected добавляет к пакету еще и наследников, даже если они лежат в других пакетах. Public открывает метод вообще всем. Если метод не обязан быть доступен снаружи, разумнее начинать с private и расширять доступ только по необходимости.

Что такое void и нужен ли в таком методе return?

Void это заглушка на месте возвращаемого типа, она означает, что метод ничего не возвращает. Писать return в конце такого метода не нужно, он и так завершится, дойдя до закрывающей скобки. Но пустой return без значения там разрешен, и он полезен внутри условий или циклов, когда нужно выйти из метода досрочно.

Зачем нужно ключевое слово this?

Это ссылка объекта на самого себя. Чаще всего его пишут в сеттерах и конструкторах, где имя параметра совпадает с именем поля: this.value указывает на поле объекта, а просто value на параметр. Для вызова своих же методов this обычно не пишут, потому что метод и без него ищется у текущего объекта.

Что такое перегрузка методов?

Это несколько методов с одинаковым именем в одном классе, различающихся списком параметров. Нужна она там, где логика одна и та же, а входные данные разные: незачем придумывать похожие имена вроде printOne и printTwo. Какой именно метод вызвать, компилятор решает сам, глядя на типы и количество аргументов на месте вызова.

Как правильно называть методы?

Имя начинают со строчной буквы и пишут в верблюжьем стиле, то есть каждое следующее слово с заглавной и без пробелов: constructHelloSentence. Начинать лучше с глагола, потому что метод это действие: getCat, createCar, delete. Хорошее имя избавляет от необходимости писать комментарий, что метод делает.

Читайте также