javaintermediate

CLI Argument Parser

Parse command-line arguments with flags, options, positional args, and help text without external libraries.

java
import java.util.*;

public class CliParser {
    private final Map<String, Option> options = new LinkedHashMap<>();
    private final Map<String, String> parsed = new HashMap<>();
    private final List<String> positional = new ArrayList<>();
    private final String programName;

    record Option(String shortFlag, String longFlag, String description,
                  boolean hasValue, String defaultValue) {}

    public CliParser(String programName) {
        this.programName = programName;
        addOption("-h", "--help", "Show help", false, null);
    }

    public CliParser addOption(String shortFlag, String longFlag,
                                String desc, boolean hasValue, String defaultVal) {
        Option opt = new Option(shortFlag, longFlag, desc, hasValue, defaultVal);
        options.put(shortFlag, opt);
        options.put(longFlag, opt);
        if (defaultVal != null) parsed.put(longFlag, defaultVal);
        return this;
    }

    public CliParser parse(String[] args) {
        for (int i = 0; i < args.length; i++) {
            String arg = args[i];

            if (arg.equals("-h") || arg.equals("--help")) {
                printHelp();
                System.exit(0);
            }

            Option opt = options.get(arg);
            if (opt != null) {
                if (opt.hasValue()) {
                    if (i + 1 >= args.length) {
                        throw new IllegalArgumentException("Missing value for " + arg);
                    }
                    parsed.put(opt.longFlag(), args[++i]);
                } else {
                    parsed.put(opt.longFlag(), "true");
                }
            } else if (arg.startsWith("-")) {
                throw new IllegalArgumentException("Unknown option: " + arg);
            } else {
                positional.add(arg);
            }
        }
        return this;
    }

    public String get(String flag) { return parsed.get(flag); }
    public String get(String flag, String fallback) { return parsed.getOrDefault(flag, fallback); }
    public int getInt(String flag, int fallback) {
        String val = parsed.get(flag);
        return val != null ? Integer.parseInt(val) : fallback;
    }
    public boolean has(String flag) { return "true".equals(parsed.get(flag)); }
    public List<String> getPositional() { return positional; }

    public void printHelp() {
        System.out.println("Usage: " + programName + " [options] [args]");
        System.out.println("\nOptions:");
        options.values().stream().distinct().forEach(opt ->
            System.out.printf("  %s, %-15s %s%s%n",
                opt.shortFlag(), opt.longFlag(), opt.description(),
                opt.defaultValue() != null ? " (default: " + opt.defaultValue() + ")" : ""));
    }

    public static void main(String[] args) {
        args = new String[]{"-o", "result.txt", "--verbose", "-n", "10", "file1.txt", "file2.txt"};

        CliParser cli = new CliParser("myapp")
            .addOption("-o", "--output", "Output file", true, "stdout")
            .addOption("-n", "--count", "Number of results", true, "5")
            .addOption("-v", "--verbose", "Verbose output", false, null)
            .parse(args);

        System.out.println("Output: " + cli.get("--output"));
        System.out.println("Count: " + cli.getInt("--count", 5));
        System.out.println("Verbose: " + cli.has("--verbose"));
        System.out.println("Files: " + cli.getPositional());
    }
}

Use Cases

  • Command-line tool argument parsing
  • Configuration via CLI flags
  • Build tools and dev utility scripts

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.