CLI утилиты на Java: превращаем скучный код в настоящий инструмент
Помните то чувство, когда вы написали полезный алгоритм на Java, но чтобы им воспользоваться, приходится каждый раз открывать IDE, менять hardcode и снова запускать? Знакомо? Пора это исправить. Сегодня мы поговорим о том, как создавать CLI утилиты на Java, которые работают как настоящие профессиональные инструменты.
CLI (Command Line Interface) — это не просто "черное окно с текстом". Это мощнейший интерфейс, который любят системные администраторы, DevOps-инженеры и опытные разработчики. И Java здесь не отстает: с ее помощью можно создавать консольные приложения, которые по удобству не уступают GUI, а по скорости и гибкости — превосходят их.
В этой статье мы разберем создание CLI утилит на Java от А до Я. Вы узнаете, как обрабатывать аргументы командной строки, как парсить сложные параметры и как собрать готовый JAR-файл, который можно запустить одной командой. Поехали!
Почему Java для CLI — это круто?
Многие думают, что CLI — это удел Python или Bash. Но Java консольные приложения имеют неоспоримые преимущества:
- Кроссплатформенность: ваша утилита будет работать на Windows, Linux и macOS без единой правки кода.
- Производительность: JIT-компиляция делает Java-программы очень быстрыми.
- Богатая экосистема: библиотеки для парсинга аргументов, работа с сетью, базами данных — все под рукой.
- Типобезопасность: компилятор отлавливает ошибки до того, как они попадут в продакшн.
Давайте перейдем к практике и создадим нашу первую CLI утилиту на Java.
Настройка проекта и базовый каркас
Для начала создадим простейшую структуру. Нам понадобится Maven или Gradle (я буду использовать Maven, так как он проще для понимания).
Шаг 1: Создаем Maven проект
Создайте файл pom.xml с минимальной конфигурацией:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.pythonlib</groupId>
<artifactId>file-utils</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.pythonlib.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
Шаг 2: Пишем простейший Main класс
Создайте файл src/main/java/com/pythonlib/Main.java:
package com.pythonlib;
public class Main {
public static void main(String[] args) {
System.out.println("Привет, это CLI утилита на Java!");
System.out.println("Передано аргументов: " + args.length);
for (int i = 0; i < args.length; i++) {
System.out.println("args[" + i + "] = " + args[i]);
}
}
}
Соберите проект: mvn clean package. После этого запустите:
java -jar target/file-utils-1.0-SNAPSHOT.jar hello world 123
Вы увидите, как Java командная строка обработала ваши аргументы. Но это только начало — ручной разбор args[] быстро становится адом, когда параметров много. Нужна библиотека для парсинга.
Picocli — лучший друг Java-разработчика
На рынке есть несколько библиотек для создания CLI: Apache Commons CLI, JCommander, args4j. Но Picocli — мой фаворит. Почему?
- Минимальный boilerplate code
- Автоматическая генерация help-сообщений
- Поддержка подкоманд (git-style)
- Работает с Java 8+
- Tab-completion для bash/zsh
Добавим Picocli в pom.xml:
<dependencies>
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
<version>4.7.5</version>
</dependency>
</dependencies>
Реальный пример: утилита для подсчета строк в файлах
Давайте создадим полезную CLI утилиту на Java, которая считает строки, слова и символы в текстовых файлах. Аналог wc из Linux, но с расширенными возможностями.
package com.pythonlib;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.Callable;
@Command(name = "wc",
mixinStandardHelpOptions = true,
version = "1.0",
description = "Подсчет строк, слов и символов в файле")
public class WordCounter implements Callable<Integer> {
@Option(names = {"-l", "--lines"},
description = "Показать только количество строк")
private boolean showLines = false;
@Option(names = {"-w", "--words"},
description = "Показать только количество слов")
private boolean showWords = false;
@Option(names = {"-c", "--chars"},
description = "Показать только количество символов")
private boolean showChars = false;
@Parameters(description = "Файл(ы) для анализа", arity = "1..*")
private File[] files;
@Override
public Integer call() throws Exception {
// Если не указаны флаги — показываем всё
if (!showLines && !showWords && !showChars) {
showLines = showWords = showChars = true;
}
long totalLines = 0, totalWords = 0, totalChars = 0;
for (File file : files) {
if (!file.exists() || !file.isFile