CLI frameworks for Java: creating powerful console applications
Developing console (CLI) applications in Java is a task every developer faces. Manually handling command-line arguments through main(String[] args) quickly becomes cumbersome and error-prone. Fortunately, the Java ecosystem has mature frameworks that handle parsing, validation, autocompletion, and help generation. In this article, we will look at three leading tools: Picocli, JCommander, and Spring Shell.
1. Picocli — modern and high-performance
Picocli is a framework with a minimal footprint (only 1.5 MB) that requires no external dependencies. It supports annotations, Bash/Zsh autocompletion, and built-in help generation. Picocli is ideal for microservices and command-line tools.
Key features:
- Annotations
@Command,@Option,@Parameters - Nested subcommands
- Typed parameters (int, boolean, enum, collections)
- Automatic validation (required parameters, ranges)
- Colored output and progress bars
- GraalVM native compilation
Code example:
import picocli.CommandLine;import picocli.CommandLine.Command;import picocli.CommandLine.Option;import picocli.CommandLine.Parameters;
@Command(name = "greet", description = "Greets a user")public class GreetCommand implements Runnable {
@Option(names = {"-n", "--name"}, description = "User name", required = true) private String name;
@Option(names = {"-c", "--count"}, description = "Number of repetitions", defaultValue = "1") private int count;
@Parameters(index = "0", description = "Message", defaultValue = "Hello") private String message;
@Override public void run() { for (int i = 0; i < count; i++) { System.out.println(message + ", " + name + "!"); } }
public static void main(String[] args) { int exitCode = new CommandLine(new GreetCommand()).execute(args); System.exit(exitCode); }}Run: java GreetCommand -n World -c 2 "Hello" will output:
Hello, World!Hello, World!2. JCommander — time-tested
JCommander is one of the oldest CLI frameworks (since 2010), used in projects like Jenkins and TestNG. It supports annotations, complex types, and internationalization. JCommander is known for its simple API and excellent documentation.
Key features:
- Annotations
@Parameterwith names and descriptions - Support for nested commands via
JCommander.addCommand() - Validation through custom
IParameterValidator - Help generation with
usage() - Working with configuration files
Code example:
import com.beust.jcommander.JCommander;import com.beust.jcommander.Parameter;import com.beust.jcommander.Parameters;
@Parameters(commandDescription = "Calculator")public class CalculatorCommand {
@Parameter(names = {"--a"}, description = "First number", required = true) private int a;
@Parameter(names = {"--b"}, description = "Second number", required = true) private int b;
@Parameter(names = {"--op"}, description = "Operation: add/sub/mul/div") private String operation = "add";
public void run() { double result; switch (operation) { case "add": result = a + b; break; case "sub": result = a - b; break; case "mul": result = a * b; break; case "div": result