Метод 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.void—mainничего не возвращает. Код завершения Java-программы не является возвращаемым значением; он задаётся черезSystem.exit(...)или по умолчанию равен0при нормальном завершении.main— буквальное имя, которое ищет JVM. НапишитеMain,mianили любое другое имя — и JVM не запустится, выдавError: Main method not found in class ....String[] args— единственный параметр, массив строк, содержащий аргументы командной строки. Имя параметра не имеет значения (args,argv,cmdline) — важен только тип.
Параметр-массив можно также записать как varargs — String... 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.