W3docs

Метод main в Java

Что означает public static void main(String[] args), зачем нужен каждый модификатор и как передаются аргументы командной строки.

Каждое Java-приложение начинает работу внутри метода с очень конкретной сигнатурой: public static void main(String[] args). JVM ищет именно эту сигнатуру, вызывает её один раз, и программа выполняется до тех пор, пока этот вызов не вернёт управление (или программа не будет остановлена другим способом). Если какая-либо часть сигнатуры написана неверно, JVM отказывается запускать программу.

Вы пишете эту строку в каждом примере начиная с Hello World. В этой главе мы разберём её по частям, чтобы вы понимали, что делает каждое слово и какая гибкость допустима.

Сигнатура по словам

public static void main(String[] args) { ... }
  • public — JVM находится «снаружи» вашего класса. Чтобы вызвать main извне, он должен быть публичным. При более строгом доступе (private, package-private) JVM не сможет до него добраться.
  • static — JVM не создаёт экземпляр вашего класса перед вызовом; он вызывает main на самом классе. Поэтому main должен принадлежать классу — именно это означает static.
  • voidmain ничего не возвращает. Код завершения Java-программы не является возвращаемым значением; он задаётся через System.exit(...) или по умолчанию равен 0 при нормальном завершении.
  • main — буквальное имя, которое ищет JVM. Напишите Main, mian или любое другое имя — и JVM не запустится, выдав Error: Main method not found in class ....
  • String[] args — единственный параметр, массив строк, содержащий аргументы командной строки. Имя параметра не имеет значения (args, argv, cmdline) — важен только тип.

Параметр-массив можно также записать как varargsString... args — это тот же тип для JVM, поведение идентично:

public static void main(String... args) { ... }

Обе формы работают. В большинстве кода по соглашению используется String[] args.

Аргументы командной строки

Когда вы запускаете Java-программу из терминала, всё, что указано после имени класса, становится элементами массива args:

$ java Greet Ada Lovelace

Внутри Greet.main переменная args будет равна {"Ada", "Lovelace"}:

public class Greet {
  public static void main(String[] args) {
    if (args.length == 0) {
      System.out.println("Hello, stranger");
    } else {
      System.out.println("Hello, " + String.join(" ", args));
    }
  }
}
  • args.length — количество аргументов: 0, если ни одного не передано.
  • Каждый элемент всегда является String. Чтобы использовать числовой аргумент как число, его нужно распарсить: int n = Integer.parseInt(args[0]);.
  • Кавычки в оболочке объединяют слова с пробелами — java Foo "hello world" помещает один элемент "hello world" в args.

Что не допускается

Сигнатура фиксирована; небольшие отклонения успешно компилируются, но вызывают ошибку при запуске — JVM выводит Error: и завершает работу до того, как выполнится хоть строчка вашего кода:

  • public void main(String[] args) — отсутствует static. Error: Main method is not static in class ....
  • void main(String[] args) — отсутствует public static. Та же ошибка «not static».
  • public static int main(String[] args) — тип возврата int. Error: Main method must return a value of type void in class ....
  • public static void Main(String[] args) — заглавная M или любое другое имя. Error: Main method not found in class ....
  • public static void main(String args) — неверный тип параметра (одиночная String, а не массив). Error: Main method not found in class ....

Обратите внимание: это ошибки времени запуска, а не ошибки компиляции — javac принимает все эти варианты без возражений. Проверка происходит, когда java пытается найти точку входа.

Что допускается и не вызывает проблем:

  • final для параметра или метода: public static final void main(final String[] args).
  • Объявление исключений: public static void main(String[] args) throws Exception. Иногда удобно для быстрых экспериментов.
  • Форма с varargs: public static void main(String... args).

Несколько классов, один main

Каждый публичный класс верхнего уровня может иметь собственный main. Когда вы запускаете java SomeClass, JVM ищет main именно в этом классе. Поэтому в большом проекте могут быть десятки классов с собственным main — для тестирования или для отдельных точек входа; точкой входа данного запуска будет только тот, что указан в командной строке.

// File Greet.java
public class Greet {
  public static void main(String[] args) { System.out.println("greet"); }
}

// File Sum.java
public class Sum {
  public static void main(String[] args) {
    int total = 0;
    for (String s : args) total += Integer.parseInt(s);
    System.out.println(total);
  }
}

java Greet запускает первый класс; java Sum 1 2 3 запускает второй и выводит 6.

Завершение Java-программы

Нормальный возврат из main завершает программу с кодом выхода 0. Чтобы завершить программу досрочно или задать ненулевой код выхода (сигнализирующий об ошибке вызвавшей стороне), используйте System.exit:

if (args.length == 0) {
  System.err.println("usage: Sum <number>...");
  System.exit(1);
}

System.exit не возвращает управление — он останавливает JVM. Используйте его экономно; в библиотеках это почти никогда не правильный инструмент. В небольшой программе командной строки это стандартный способ сообщить: «я не смог выполнить свою задачу».

Рабочий пример

java— editable, runs on the server

Что дальше

На этом раздел о методах завершён: вы умеете писать методы, передавать параметры, перегружать их, использовать рекурсию, варьировать количество аргументов и объявлять точку входа, которая управляет всей программой. Следующий раздел знакомит с более крупным контейнером, внутри которого живут методы, — классами и объектами — и даёт первое представление об объектно-ориентированной модели Java.

Практика

Практика
Какое изменение в public static void main(String[] args) не позволит JVM запустить программу?
Какое изменение в public static void main(String[] args) не позволит JVM запустить программу?
Was this page helpful?