检查命令行参数是否以有效顺序传递

Check if command line args are passed in valid order

我需要检查 java 命令行参数是否按以下顺序传递:

-shape  (optional - default polygon)
-color  (optional - default green)
-repeat (optional - default 5)
-name   (required)

并且没有使用未定义的参数。

如果未传递可选参数,则使用默认值。

有效:

java Game -shape triangle -color black -repeat 10 -name Tom
java Game -shape triangle -repeat 7 -name Jerry
java Game -repeat 11 -name Boby
java Game -name Pipy

无效:

java Game -shape triangle -x sth -name Tom (invalid argument: -x)
java Game -shape triangle (-name is required)
java Game -color white -shape triangle (wrong order: -shape must be before -color)

对优雅的解决方案有什么建议吗?

您可以将所有选项存储在一个列表中,然后简单地在命令行参数中一一尝试,直到找到匹配的选项:

public static class OptionParser<T> implements ParameterParser {

    private final String option;

    public OptionParser(String option, Function<String, ? extends T> parser) {
        if (parser == null) {
            throw new IllegalArgumentException();
        }
        this.option = "-" + option;
        this.parser = parser;
    }

    public OptionParser(String option, Function<String, ? extends T> parser, T defaultValue) {
        this(option, parser);
        this.value = defaultValue;
    }

    private final Function<String, ? extends T> parser;

    private T value;

    @Override
    public int parse(String[] args, int index) {
        if (args.length < index + 2 || !option.equals(args[index])) {
            return index;
        } else {
            value = parser.apply(args[index + 1]);
            return index + 2;
        }
    }

    public T getValue() {
        return value;
    }

}

public static interface ParameterParser {


    /**
     * Tries parsing the parameter and returns the new index after the
     * operation.
     *
     * @param args the parameter list
     * @param index the index of the first String to use.
     * @return the index of the next String after parsing the parameter or the index,
     * if the parameter wasn't parsable with this ParameterParser.
     */
    public int parse(String[] args, int index);
}

public static void main(String[] args) {
    OptionParser<String> shape = new OptionParser<>("shape", Function.identity(), "polygon");
    OptionParser<String> color = new OptionParser<>("color", Function.identity(), "green");
    OptionParser<Integer> repeat = new OptionParser<>("repeat", Integer::valueOf, 5);
    OptionParser<String> name = new OptionParser("name", Function.identity());

    List<ParameterParser> parameters = Arrays.asList(
            shape,
            color,
            repeat,
            name
    );

    Iterator<ParameterParser> iterator = parameters.iterator();

    for (int i = 0; i < args.length;) {
        if (!iterator.hasNext()) {
            throw new IllegalArgumentException("could not parse option at index " + i + ": " + args[i]);
        }
        i = iterator.next().parse(args, i);
    }

    if (name.getValue() == null) {
        throw new IllegalArgumentException("-name is required");
    }

    System.out.println("shape="+shape.getValue());
    System.out.println("color="+color.getValue());
    System.out.println("repeat="+repeat.getValue());
    System.out.println("name="+name.getValue());