Самый простой и базовый способ – с помощью метода
Runtime.getRuntime().exec(). В качестве параметра ему передается строка системной команды. Опциональные можно передать рабочую директорию, и переменные окружения в виде массива строк
"имя=значение". Если команде нужны аргументы, они передаются либо массивом, либо в той же строке команды через пробелы.
Рекомендуемый, и более управляемый способ – использование класса
ProcessBuilder. Он же применяется внутри метода
exec. Билдер дает, например, средства для использования в команде
пайплайнов и
редиректов ввода-вывода.
В результате запуска команды создается объект класса
Process. Его можно сконвертировать в более современный (Java 9+) и функциональный
ProcessHandle. Через эти объекты идет работа с вводом-выводом процесса, его характеристиками и статусом.
Команда запускается в отдельном подпроцессе операционной системы. Это значит, что лозунг «Write once, run anywhere» перестает здесь работать – ваша программа становится платформо-зависимой. Обращение к ОС, а тем более выделение нового процесса обычно занимает немало ресурсов компьютера. Запуск внешних программ
не считается плохой практикой, но всё-таки при возможности стоит его избегать.