Simple Java Command Line Argument Parser Implementation
Tags: java, programming, codenewbie, tutorial
Published: 2021-02-24 12:43:48

Here, we will create a Custom CommandLineParser class to parse the arguments passed via the command line in Java.  
Let's first see the sample entry point for the Java program. 
```java
public class MyProgram{
    public static void main(String args[])
    {
        System.out.println("This is my program.");
    }
}
```
Ever wondered why do we need to pass an array of strings as arguments in main method of Java?  
It's for the command line arguments. When you run your Java program from the command line:
```bash
java MyProgram Oshan 
```
It takes "Oshan" as an argument. So, if you want your program to access this `String`, you can access it using the array of String passed in the main method.
```java
// inside main method 
    //Prints "My name is Oshan"
    System.out.println("My name is ", args[0]);
```

You can pass the initial configuration you want your Java program to follow via command-line arguments. For example:  
```bash
## if you want to send file path
java MyProgram -filePath file1.txt 

## if you want to send multiple file paths
java MyProgram -filePath file1.txt file2.txt 

## or, if you just want to send flags 
java MyProgram -noprint 
```

By default, Java takes each string as an argument and cannot differentiate between argument names, values, or flags. So, today, we'll write a simple program that will parse the arguments passed through the command line. This way we don't have to hard code the values of the arguments as `args[1]` or `args[2]` in our program. Instead, we will be able to see the argument list and choose values using argument names rather than an array of strings. 

Here is the code:
```java
import java.util.HashMap;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

public class CommandLineParser {
    List <String> args = new ArrayList<>();
    HashMap<String, List<String>> map = new HashMap<>();
    Set<String> flags = new HashSet<>();

    CommandLineParser(String arguments[])
    {
        this.args = Arrays.asList(arguments);
        map();
    }

    // Return argument names
    public Set<String> getArgumentNames()
    {
        Set<String> argumentNames = new HashSet<>();
        argumentNames.addAll(flags);
        argumentNames.addAll(map.keySet());
        return argumentNames;
    }
    
    // Check if flag is given
    public boolean getFlag(String flagName)
    {
        if(flags.contains(flagName))
            return true;
        return false;
    }

    // Return argument value for particular argument name
    public String[] getArgumentValue(String argumentName)
    {
        if(map.containsKey(argumentName))
            return map.get(argumentName).toArray(new String[0]);
        else
            return null;
    }

    // Map the flags and argument names with the values 
    public void map()
    {
        for(String arg: args)
        {
            if(arg.startsWith("-"))
            {
                if (args.indexOf(arg) == (args.size() - 1))
                {
                    flags.add(arg.replace("-", ""));
                }
                else if (args.get(args.indexOf(arg)+1).startsWith("-"))
                {
                    flags.add(arg.replace("-", ""));
                }
                else
                {
                    //List of values (can be multiple)
                    List<String> argumentValues = new ArrayList<>();
                    int i = 1;
                    while(args.indexOf(arg)+i != args.size() && !args.get(args.indexOf(arg)+i).startsWith("-"))
                    {
                        argumentValues.add(args.get(args.indexOf(arg)+i));
                        i++;
                    }
                    map.put(arg.replace("-", ""), argumentValues);
                }
            }
        }
    }
}

```

Now, you can add the above class to any program you want and easily parse the values.  
Let's try with a simple program:
```java 
public class MyProgram
{
    public static void main (String args[])
    {
        CommandLineParser clp = new CommandLineParser(args);
    }
}
```
Make sure you include the `CommandLineParser` class in the classpath when you compile your program.
```
javac -classpath /pathToTheCommandLineParserClass MyProgram.java
 
java MyProgram.java -name Oshan -prints 3 -test
```
Now, in our program you can easily get these values and use it.
```java
// inside main method
    String name = clp.getArgumentValue("name");
    int prints = Integer.parseInt(clp.getArgumentValue("prints"));
    boolean isTest = clp.getFlag("test");

    if(isTest)
        System.out.println("This is only a test");

    for(int i = 0; i < prints; i++)
    {
        System.out.print(name+" ");
    }
```
The output of the above program will be:
```
This is only a test
Oshan
Oshan
Oshan
```
You can also use the method `getArgumentNames` to see the passed argument names.  
I recently encountered a problem that made me write this custom `CommandLineParser`. Obviously, you can modify this to fit your requirements or go with the traditional approach. But, making such class removes the ambiguity when multiple arguments are passed via command line.   
I hope you find this useful.

Thanks for reading.