7

I want to pass, both, named and unnamed arguments to the main method.

Currently I am passing arguments as:

 java -jar myfile.jar param1 param2

and handling them as:

public static void main(String[] args) throws IOException {
    String param1 = args[0];
    String param2 = args[1];
}

However, I want to pass the arguments in a more dynamic way - namely, so that:

  1. I can pass, both, named and unnamed arguments;
  2. I can fetch/handle these arguments with their names;
  3. I will not be required to pass them in the same order, every time I execute the main method.

Passing in a way Something like this:

   java -jar myJar param3name=param3 param2name=param2 param1name=param1 param5 param6

and handling in a way something like this:

public static void main(String[] args) throws IOException {
    //something like
    String param3 = getvaluemethod("param3name");
    String param1 = getvaluemethod("param1name");
     .....
    String param5 = args[n]
    String param6 = args[n+1]
     .....
}

I am fine to work with some external libraries which would make my work easier.

I have already seen this and it is not comprehensive.

Any input on how to accomplish the task?

Giorgi Tsiklauri
  • 9,715
  • 8
  • 45
  • 66
sun_dare
  • 1,146
  • 2
  • 13
  • 33

4 Answers4

8

Apache Commons CLI is what I use to parse java command line arguments. Examples can be found here and can be used to do any of the following option formats:

  • POSIX like options (ie. tar -zxvf foo.tar.gz)
  • GNU like long options (ie. du --human-readable --max-depth=1)
  • Java like properties (ie. java -Djava.awt.headless=true -Djava.net.useSystemProxies=true Foo)
  • Short options with value attached (ie. gcc -O2 foo.c)
  • long options with single hyphen (ie. ant -projecthelp)
Archangel33
  • 496
  • 8
  • 22
  • I had a look at Commons CLI and args4j. Both are good but I am going with args4j. I felt it easier – sun_dare Jul 25 '14 at 14:27
  • args4j is also a good choice. I used CLI because I've always done it that way since I was told to use it in a project a long long time ago by the senior devs. Never really looked at args4j but may now take a look to see what else may be out there. – Archangel33 Jul 25 '14 at 21:23
  • JSAP is the way to go... http://www.martiansoftware.com/jsap/ May seem overkill for simple command line applications but it quickly pays off. – Hugo Zaragoza Sep 09 '16 at 17:48
3

Based on @Mac70's answer and a few additions,

private static Map<String, String> map;
private static void makeMap(String[] args) {
    map = new HashMap<>();
    for (String arg : args) {
        if (arg.contains("=")) {
            //works only if the key doesn't have any '='
            map.put(arg.substring(0, arg.indexOf('=')),
                    arg.substring(arg.indexOf('=') + 1));
        }
    }
}

public static void main(String[] args) {
    makeMap(args);

    //.. 
    String param3 = map.get("param3name");
    String param1 = map.get("param1name");
}

If you need anything extensive, you need to look at @Archangel33's answer.

Phani Rahul
  • 840
  • 7
  • 22
1

As long as params and names don't contain spaces - you can get all of them, split at "=" key and add key/value pairs to the HashMap. Later you can just get any value you want using key.

Edit: If you want to not add some elements to the map, then you can ignore them if these elements don't contain "=" key.

Mac70
  • 320
  • 5
  • 15
  • Thank you for you reply. :) what if the value has "=" in that? – sun_dare Jul 22 '14 at 16:02
  • If you don't want to use any libraries, you can pass parameters in this format: "key"="value" - this way instead of = key you can search for "=" keys (but the whole thing needs more parsing). You can use other key you will not use instead of =, too. – Mac70 Jul 22 '14 at 16:07
  • 1
    well, there is no point in using `=` as the key if it is allowed in the value part. you can either escape `=` or use `""` like @Mac70 suggested. – Phani Rahul Jul 22 '14 at 16:46
0

Currently I don't know what is the best practice to solve "-drop-value abc", but usually it is better to retrieve value as "-drop-value=abc"


import java.util.HashMap;

public class ArgumentParser {
    public HashMap<Integer, String> index;
    public String[] arguments;
    public HashMap<String, String> named_arguments;

    public ArgumentParser(String[] args) {
        String arg;
        for (int i = 0; i < args.length; i++) {
            arg = args[i];
            if (arg.startsWith("--") || arg.startsWith("-")) {
                String[] split = arg.split("="); // Split on the first occurrence of "="
                // Raise an error if the key is already in the dictionary
                if (this.named_arguments.containsKey(split[0])) {
                    throw new IllegalArgumentException("Argument " + split[0] + " already exists.");
                }

                if (split.length == 1) {
                    this.named_arguments.put(split[0], null); // If there is no "="
                } else {
                    this.named_arguments.put(split[0], split[1]);
                }
                this.index.put(i, split[1]);
            } else {
                this.arguments[i] = arg;
                this.index.put(i, arg);
            }
        }
    }

    public HashMap<Integer, String> GetIndex() { return this.index; }
    public String[] GetArguments() { return this.arguments; }
    public HashMap<String, String> GetNamedArguments() { return this.named_arguments; }
}