Viacheslav
3 уровень
Санкт-Петербург

Оператор return в Java

Статья из группы Random

Вступление

Как мы знаем, язык Java является объектно-ориентированным языком программирования. То есть базовая концепция, т.к. сказать основа основ, заключается в том, что всё есть объект. Объекты описываются при помощи классов. Оператор return в Java - 1В свою очередь у классов есть состояние и поведение. Например, банковский счёт может иметь состояние в виде количестве денег на счету и иметь поведения увеличение и уменьшение баланса. Поведение в Java реализуется при помощи методов. То, каким образом описывать методы, приводится в самом начале пути изучения Java. Например, в официальном tutorial от Oracle: «Defining Methods». Тут можно выделить два важных аспекта:
  • Каждый метод имеет сигнатуру. Сигнатура состоит из имени метода и его входных параметров;
  • Для методов должно быть указан тип возвращаемого значения (return type);
  • Тип возвращаемого значения не входит в сигнатуру метода.
Опять же, это следствие того, что Java язык строго типизированный и компилятор хочет заранее понимать, какие типы и где используются на столько, на сколько это возможно. Опять же, чтобы уберечь нас от ошибок. В общем, всё во благо. Ну и нам это лишний раз прививает культуру обращения с данными, как мне кажется. Итак, для методов указывается тип значения. А чтобы вернуть это самое значение из методов используется ключевое слово return.

Ключевое слово оператор return в Java

Ключевое слово оператор return относится к выражениям «управления ходом выполнения», о чём указано в oracle tutorial «Control Flow Statements». О том, как нужно возвращать значения можно так же прочитать в официальном tutorial: «Returning a Value from a Method». Компилятор тщательно следит, на сколько у него хватает сил, за тем, чтобы возвращаемое из метода значение соответствовало указанному у метода типу возвращаемого значения. Воспользуемся для примера Online IDE от tutorialspoint. Посмотрим на изначальный пример:

public class HelloWorld {
    public static void main(String []args) {
        System.out.println("Hello World");
    }
}
Как мы видим, здесь выполняется main метод, который является точкой входа в программу. Строчки кода выполняются сверху вниз. Наш main метод не может возвращать значения, иначе мы получим ошибку: «Error: Main method must return a value of type void». Поэтому, метод просто выполнит вывод на экран. Давайте теперь вынесем получение строки в отдельный метод получения сообщения:

public class HelloWorld {

    public static void main(String []args) {
        System.out.println(getHelloMessage());
    }
    
    public static String getHelloMessage() {
        return "Hello World";
    }
    
}
Как мы видим, при помощи ключевого слова return мы указали возвращаемое значение, которое использовали далее в методе println. В описании (определении) метода getHelloMessage мы указали, что он вернёт нам String. Это позволяет компилятору проверить, что действия метода согласуются с тем, каким образом он объявлен. Естественно, тип возвращаемого значения, указанного в определении метода, может быть более широким чем тип возвращаемого из кода значения, т.е. главное чтобы типы приводились друг к другу. В противном случае мы получим ошибку во время компиляции: «error: incompatible types». Кстати, наверно сразу появился вопрос: Почему return относится к операторам управления ходом выполнения программы. А потому, что он может нарушать обычный ход выполнения программы "сверху вниз". Например:

public class HelloWorld {

    public static void main(String []args){
        if (args.length == 0)  {
            return;
        }
        for (String arg : args)  {
            System.out.println(arg);
        }
    }
    
}
Как видно из примера, мы прерываем выполнение метода main в том случае, если java программа наша вызвана без параметров. Важно помнить, что если у вас после return есть код, он становится недоступным. И это заметит наш умный компилятор и не даст вам запустить такую программу. Например, данный код не скомпилируется:

public static void main(String []args) {
        System.out.println("1");
        return;
        System.out.println("2");
 }
Есть один «грязный хак» для обхода такого. Например, для целей отладки или ещё почему-то. Выше указанный код можно починить обернув return в if блок:

if (2==2)  {
    return;
}

Оператор Return при обработке ошибок

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

public class HelloWorld  {

    public static void main(String []args) {
        System.out.println("Value is: " + getIntValue());
    }
    
    public static int getIntValue()  {
        int value = 1;
        try {
            System.out.println("Something terrible happens");
            throw new Exception();
        } catch (Exception e) {
            System.out.println("Catched value: " + value);
            return value;
        } finally {
            value++;
            System.out.println("New value: " + value);
        }
    }
    
}
На первый взгляд кажется, что должно вернуться 2, ведь finally выполняется всегда. Но нет, значение будет 1, а изменение переменной в finally будет проигнорировано. Более того, если бы value содержала бы объект и мы в finally сказали бы value = null, то из catch вернулась бы всё равно ссылка на объект, а не null. А вот из блока finally оператор return сработал бы правильно. Коллеги за такой подарок явно не скажут спасибо.
Что еще почитать:

Оператор return

void.class

Ну и напоследок. Можно написать странную конструкцию вида void.class. Казалось бы, зачем и в чём смысл? На самом деле, в различных фрэймворках и хитрых случаях, когда используется Java Reflection API, это может очень понадобится. Например, можно проверять, какой тип возвращает метод:

import java.lang.reflect.Method;

public class HelloWorld {

    public void getVoidValue() {
    }

    public static void main(String[] args) {
        for (Method method : HelloWorld.class.getDeclaredMethods()) {
            System.out.println(method.getReturnType() == void.class);
        }
    }
}
Это может быть полезно в тестовых фрэймворках, где необходимо подменять реальный код методов. Но для этого нужно понимать, как этот метод себя ведёт (т.е. какие типы возвращает). Есть ещё второй способ реализации метода main из кода выше:

public static void main (String[] args) {
        for (Method method : HelloWorld.class.getDeclaredMethods()) {
            System.out.println(method.getReturnType() == Void.TYPE);
        }
 }
Довольно интересное обсуждение разницы между ними можно прочитать на stackoverflow: What is the difference between java.lang.Void and void? #Viacheslav
Комментарии (13)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
YesOn Уровень 9, Томск, Россия
3 сентября 2021
Доброго всем времени суток! Нашёл таки тот самый абзац на стороннем ресурсе, которого так не хватает в этой статье для объяснения принципа работы оператора return. Вопрос: в каких случаях нам обязательно нужно применить return мучил меня несколько недель! Для кого-то из новых студентов это многое может прояснить: "В методе в качестве типа возвращаемого значения вместо void используется любой другой тип. В данном случае метод sum возвращает значение типа int, поэтому этот тип указывается перед названием метода. Причем если в качестве возвращаемого типа для метода определен любой другой, отличный от void, то метод обязательно должен использовать оператор return для возвращения значения."

public class Program{
      
    public static void main (String args[]){
          
        int x = sum(1, 2, 3);
        int y = sum(1, 4, 9);
        System.out.println(x);  // 6
        System.out.println(y);  // 14
    }
    static int sum(int a, int b, int c){
         
        return a + b + c;
    }
}



Единственное тогда не понятно, правильно ли в данной статье среди примеров кода применили оператор return в методе main? Эксперты, могли бы Вы высказать своё мнение по этому поводу? Нашёл такой ответ в той же статье: "Оператор return применяется для возвращаения значения из метода, но и для выхода из метода. В подобном качестве оператор return применяется в методах, которые ничего не возвращают, то есть имеют тип void.
Barm Уровень 37, Минск
21 марта 2021

public static int value = 1;

  public static void main(String []args) {

      System.out.println("Value is: " + getIntValue());
      System.out.println("The final value is " + value);
  }

    public static int getIntValue()  {
        //int value = 1;
        try {
            System.out.println("Something terrible happens");
            throw new Exception();
        } catch (Exception e) {
            System.out.println("Catched value: " + value);
            return value;
        } finally {
            value++;
            System.out.println("New value: " + value);
        }
Что-то с return и finally недопонял или ошибка в статье. После return в finally прекрасно считает value++. Код выше это демонстрирует
SolomonVP🌅 Уровень 35, 🏔, Россия
2 сентября 2020
Итак квест на завтра... целый день гуглить что такое return...:))))))) (03.09.2020, 2 уровень)
татьяна чернышева Уровень 39, Владивосток
11 мая 2020
это не для 3 уровня
Игорь Кучер Уровень 38, Киев, Украина Expert
12 сентября 2019
По-моему, кроме ссылок на туториал, ничего в статье полезного нет...
NoName Уровень 0
27 июля 2019
Оооо святой Билли, я надеюсь что в будущем при видя такого когда я буду смеяться из за его простоти. Но на сейу минуту, этот код глядя на мои жалкие попитки его изменить смееться из меня((
Youvulir Уровень 4, Гомель, Беларусь
8 июля 2019
моя твоя не понимать. надо гуглить ещё
Дмитрий Войтенко Уровень 31, Харьков, Украина
26 февраля 2019
Спасибо за статью. Комментатор ниже точно не станет программистом. Карма его настигнет ;)
CapitalArt Уровень 3, Москва, Россия
1 октября 2018
Надеюсь, однажды я это пойму и буду смеяться над простотой идеи.