Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Сигнатура метода Java: Основы программирования

Возврат значений

Методы, которые мы определяли в предыдущих уроках, заканчивали свою работу тем, что печатали на экран какие-то данные:

public class App {
    public static void greeting() {
        System.out.println("Winter is coming");
    }
}

Пользы от таких методов не очень много, так как их результатом работы невозможно воспользоваться внутри программы. Рассмотрим это на примере. Возьмем задачу обработки электронной почты. Когда пользователь регистрируется на каком-то сайте, то он может ввести email любым способом:

  • Добавив случайно пробелы в начале или в конце _support@hexlet.io__
  • Использовав буквы в разном регистре SUPPORT@hexlet.io

Если мы сохраним его в таком виде в базу данных, то пользователь, скорее всего, не сможет войти на сайт, так как будет вбивать адрес без пробелов и используя другой регистр символов. Чтобы этого не произошло, email нужно подготовить к записи в базу, привести его к нижнему регистру и обрезать пробельные символы по краям строки. Вся задача решается в пару строчек:

class App {
    public static void main(String[] args) {
        // В реальности email приходит из формы
        var email = "  SuppORT@hexlet.IO";
        // обрезаем пробельные символы
        var trimmedEmail = email.trim();
        // приводим к нижнему регистру
        var preparedEmail = trimmedEmail.toLowerCase();
        System.out.println(preparedEmail); // => "support@hexlet.io"
        // здесь будет запись в базу данных
    }
}

Этот код стал возможен только благодаря возврату значения. Методы trim() и toLowerCase() ничего не печатают на экран (в консоль), они возвращают результат своей работы и поэтому мы можем записать его в переменные. Если бы они вместо этого печатали на экран, мы бы не могли присвоить результат их работы переменной. Как мы не можем сделать с определенным выше методом greeting():

// Java будет ругаться что `greeting()` ничего не возвращает
// Код не заработает
var message = App.greeting();

Изменим метод greeting() таким образом, чтобы он начал возвращать данные, вместо их печати. Для этого нам понадобится выполнить две правки:

  • Описать тип возвращаемых данных. В нашем случае это строка String
  • Выполнить возврат вместо печати на экран
class App {
    public static String greeting() {
        return "Winter is coming!";
    }
}

Вместо void теперь написано String, потому что у метода есть возврат. Так мы указали Java, что результатом работы метода будет строка. return – особая инструкция, которая берёт выражение, записанное справа, и отдаёт его наружу, тому коду, который вызвал метод. Как только Java натыкается на return, выполнение метода на этом завершается.

// Теперь этот код работает
var message = App.greeting();
// Мы можем выполнить какие-то действия над результатом
System.out.println(message.toUpperCase()); // => "WINTER IS COMING!"

Любой код после return не выполняется:

class App {
    public static String greeting() {
        return "Winter is coming!";
        // Любой код ниже не выполнится никогда
        System.out.println("Я никогда не выполнюсь");
    }
}

Даже если метод возвращает данные, это не ограничивает его в том, что он печатает. Кроме возврата данных мы можем и печатать:

class App {
    public static String greeting() {
        System.out.println("Я появлюсь в консоли");
        return "Winter is coming!";
    }
}

// Где-то в другом методе
// И напечатает текст на экран и вернет значение
var value = App.greeting();

Возвращать можно не только конкретное значение. Так как return работает с выражениями, то справа от него может появиться почти все что угодно. Здесь нужно руководствоваться принципами читаемости кода:

class App {
    public static String greeting() {
        var message = "Winter is coming!"
        return message;
    }
}

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

class App {
    public static long doubleFive() {
        // или return 5 + 5;
        var result = 5 + 5;
        return result;
    }
}

В этом примере в определении метода использовался long так как возвращается целое число.

Вопрос на самопроверку. Что выведет этот код?

// Определение
class App {
    public static int run() {
        return 5;
        return 10;
    }
}

// Использование
App.run(); // => ?

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

Методы могут не только возвращать значения, но и принимать их в виде параметров. С параметрами методов мы уже сталкивались много раз:

// Принимает на вход один параметр любого типа
System.out.println("я параметр");
// Принимает на вход индекс, по которому извлекается символ
"какой-то текст".charAt(3); // 'о'
// Принимает на вход два строковых параметра
// первый - что ищем, второй - на что меняем
"google".replace("go", "mo"); // "moogle"
// Принимает на вход два числовых параметра
// первый - начальный индекс (включая), второй - конечный индекс (не включая)
"hexlet".substring(1, 3); // "ex"

В этом уроке мы научимся создавать методы, которые принимают на вход параметры. Представим, что перед нами стоит задача, реализовать статический метод App.getLastChar(), возвращающий последний символ в строке, переданной ему на вход как параметр. Вот как будет выглядеть использование этого метода:

// Передача параметров напрямую без переменных
App.getLastChar("Hexlet"); // 't'
App.getLastChar("Goo"); // 'o'
// Передача параметров через переменные
var name1 = "Hexlet";
App.getLastChar(name1); // 't'
var name2 = "Goo";
App.getLastChar(name2); // 'o'

Из описания и примеров кода мы можем сделать следующие выводы:

  • Нам нужно определить статический метод getLastChar() в классе App
  • Метод должен принимать на вход один параметр типа String
  • Метод должен возвращать значение типа char

Определение метода:

class App {
    public static char getLastChar(String str) {
        // Вычисляем индекс последнего символа как длина строки - 1
        return str.charAt(str.length() - 1);
    }
}

Разберем его. char - говорит нам о типе возвращаемого значения. В скобках указывается тип параметра (String) и его имя (str). Так как внутри метода мы не знаем, с каким конкретно значением идет работа, то параметры всегда описываются как переменные. Имя параметра может быть любым, оно не связано с тем, как вызывается метод. Главное чтобы это имя отражало смысл того значения, которое содержится внутри. Конкретное значение параметра будет зависеть от вызова этого метода.

Параметры в Java всегда обязательны. Если попробовать вызвать метод без параметра, то компилятор выдаст ошибку:

App.getLastChar(); // такой код не имеет смысла
method getLastChar in class App cannot be applied to given types;
  required: String
  found:    no arguments
  reason: actual and formal argument lists differ in length

Точно таким же образом можно указывать два, три и более параметров. Каждый параметр отделяется от другого запятой.

class App {
    // Метод по нахождению среднего числа
    // Возвращаемый тип double,
    // так как в результате деления может получиться дробное число
    public static double average(int x, int y) {
        return (x + y) / 2.0;
    }
}
  App.average(1, 5); // 3.0
  App.average(1, 2); // 1.5

Необязательные параметры методов

В программировании большое количество функций и методов имеют параметры, которые редко меняются. В таких случаях этим параметрам задают значения по умолчанию, которые можно поменять по необходимости. Этим немного сокращается количество одинакового кода. Гипотетический пример:

class App {
    // Функция возведения в степень
    // Второй параметр имеет значение по умолчанию 2
    function pow(x, base = 2) {
      return x ** base;
    }
}

App.pow(3); // 9, так как по умолчанию во вторую степень
App.pow(3, 3); // 27

В Java нет возможности задать значение по умолчанию, но, ее можно имитировать с помощью перегрузки методов. Что это такое? Java позволяет создать несколько методов с одинаковым именем. У этих методов должны быть либо другие типы входных параметров, либо другое число параметров или все это одновременно. Посмотрим на примере метода, складывающего два числа:

class App {
    public static int sum(int x, int y) {
        return x + y;
    }
}

App.sum(2, 3); // 5

Теперь напишем другой метод sum(), который принимает только один параметр и складывает его с числом 10.

class App {
    public static int sum(int x) {
        return x + 10;
    }
}

App.sum(2); // 12
App.sum(2, 1); // 3

Компилятор без проблем выполнит такой код и создаст два метода с одним именем. Каким образом Java узнает какой метод нужно использовать? Все очень просто, во время компиляции выбирается та версия метода, которая совпадает по типу и количеству параметров. Если такой метод не был найден, то возникнет ошибка.

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

// Вызываются два разных метода с одним именем
"hexlet".substring(3); // "let"
"hexlet".substring(3, 5); // "le"

Перегрузка методов может приводить к дублированию кода, особенно когда речь идет про значения по умолчанию. Логика, в таких ситуациях, одинаковая, разница лишь в начальной инициализации. Для снижения дублирования достаточно определить сначала общий метод, который принимает больше всего параметров, а затем вызывать его из тех методов, где есть значения по умолчанию:

class App {
    public static int sum(int x, int y) {
        return x + y;
    }

    public static int sum(int x) {
        // Вызываем уже готовый метод суммирования
        return App.sum(x, 10);
    }
}

В этом примере мы не сократили код, но он наглядно показывает принцип описанный выше.

Сигнатура и контракт

Комбинация имени метода и его параметров, включая их количество и порядок, называется сигнатурой. А контрактом метода называется сочетание его сигнатуры и возвращаемого значения, включая его тип.

// Сигнатуры
App.sum(int x, double y)
App.max(int x, int y, int z)

// Контракты
public static int sum(double y, int x)
public static int max(int x, int y, int z)

Знать эти понятия полезно, потому что они встречаются и в разговорах и в документации и в статьях. Но ничего страшного если вы их не запомните, на привыкание нужно время.


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.

Об обучении на Хекслете

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 130 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Java-разработчик
Профессия
Разработка приложений на языке Java
25 мая 10 месяцев

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»