Вступ
Як ми знаємо, мова Java є об'єктно-орієнтованою мовою програмування. Тобто базова концепція, т.к. сказати основа основ, у тому, що є об'єкт. Об'єкти описуються за допомогою класів.
У свою чергу, у класів є стан і поведінка. Наприклад, банківський рахунок може мати стан як кількість грошей на рахунку і мати поведінки збільшення і зменшення балансу. Поведінка 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
спрацював би правильно. Колеги за такий подарунок явно не подякують.
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
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ