How transform String[] args with "=" split in java 8

Viewed 2045

I need to transform

String[] args = {"--path=C:/log", "--time=hourly"};

into

String[] args = {"--path", "C:/log", "--time", "hourly"};

How can I do this in Java 8, in an elegant way?

List<String> newArgs = Lists.newArrayList();

for (String s : args) {
    String[] split = s.split("=");
    newArgs.add(split[0]);
    newArgs.add(split[1]);
}

String[] strarray = new String[newArgs.size()];
return newArgs.toArray(strarray);
6 Answers
String[] result = Stream.of(args)
        .flatMap(a -> Stream.of(a.split("=")))
        .toArray(String[]::new);

The other answers are all fine technically, but the real answer is: don't.

Do not re-invent the wheel. Parsing command line options is actually hard. Whatever you come up with works for the first step, but assuming that we are talking about something that is intended to last, and good enough to attract users - then sooner or later, you spent more and more time on dealing with the options.

Thus: instead of doing any of this yourself (which is of course a bit of fun) accept that parsing command line options is a solved problem. Simply get one of the existing solutions, see here for starters.

Explanation

As you want to use Java 8 code you may use the Stream API (documentation).

Therefore you should first transform your args array into a Stream<String> using the utility method Arrays#stream (documentation). Then you split the arguments by = using String#split (documentation) and afterwards collect them again into an array using Stream#toArray (documentation).

In order to treat each split value as regular value (and not as nested data) you may want to flatten the Stream. So instead of Stream<String[]> you want to have a flattened structure like Stream<String>. You do so by using the Stream#flatMap method (documentation).


Code

Here is variant using the explained approach:

String[] data = Arrays.stream(args)  // String
    .map(arg -> arg.split("="))      // String[]
    .flatMap(Arrays::stream)         // String
    .toArray(String[]::new);

You can also memorize the pattern beforehand and then use Pattern#splitAsStream (documentation):

Pattern patt = Pattern.compile("=");
List<String> data = Arrays.stream(args)  // String
    .map(patt::splitAsStream)            // String[]
    .flatMap(Arrays::stream)             // String
    .toArray(String[]::new);

This will produce a List, but you can transform it.

final List<String> parts = Arrays.stream(args)
    .flatMap(argument -> Arrays.stream(argument.split("=")))
    .collect(Collectors.toList());

You might consider argument.split("=", 2).

    String[] args = {"--path=C:/log", "--time=hourly"};
    args = String.join("=", args).split("=");
    System.out.println(Arrays.toString(args));

I was a little suspicious about the stream performance, but thanks to a comment of Hulk, I realized that you need to warm up the lambda executions (run it at least twice) to get reasonable result.

public class StreamTest {
    public static void main(String[] args) {
        // will include lambda warm up time
        java8test();

        java8test();

        java7test();
    }


    public static void java8test() {
        List<String> test = new ArrayList<>();
        test.add("--path=C:/log");
        test.add("--time=hourly");

        long start = System.nanoTime();
        List<String> result = test.stream().flatMap(e->{
            String[] array = e.split("=");
            return Stream.of(array);
        }).collect(Collectors.toList());

        long end = System.nanoTime();

        System.out.println("Java 8 style: " + (end-start) + "ns: " + result);
    }

    public static void java7test() {
        String[] test2 = {"--path=C:/log", "--time=hourly"};

        long start = System.nanoTime();
        test2 = String.join("=", test2).split("=");
        long end = System.nanoTime();
        System.out.println("old style: " + (end-start) + "ns:" + Arrays.toString(test2));
    }

}

Performance:

Java 8 style: 188154148ns: [--path, C:/log, --time, hourly]
Java 8 style: 129220ns: [--path, C:/log, --time, hourly]
old style: 364275ns:[--path, C:/log, --time, hourly]
Related