We regularly need to write some code setting system properties. Whether it is to setup some environment in tests, production or to toggle some feature at runtime.

Using streams is not that natural until you start from an array of String. In such a case, the pair entries are the keys, and the other entry the values. For example:

public enum Environments {
    TEST(
      "environment", "test",
      "app.log", "file"),
    PRODUCTION(
      "environment", "prod",
      "app.log", "kafka");

    private final String[] systemProperties;

    Environments(final String.... systemProperties) {
        this.systemProperties = systemProperties;
    }

    public String[] systemProperties() { return systemProperties; }
}

In such a case you will need to iterate over the values by pairs but it is not that trivial with streams.

One solution is to use a local counter and check with a modulo operator the parity of the current value:

final Environments environments = getEnv(); // just to get the list

// set the properties
final AtomicInteger counter = new AtomicInteger();
Stream.of(environments.systemProperties())
  .collect(groupingBy(it -> {
    final int i = counter.getAndIncrement();
    return i % 2 == 0 ? i : i - 1;
  }))
  .values()
  .forEach(kv -> System.setProperty(kv.get(0), kv.get(1)));

High level the idea is to iterate over the strings and group them per index. The index is just the index in the array for the pair entries and the previous one for the others (this way it works for the element at index 0). The output is a map where the key is the pair index and the value a list of two elements. This is why in the previous snippet we extracted only the values() of the grouping and access element 0 and 1 of each list to set the system properties.

The lesson learnt in this post is that you can do pretty much anything with streams However, keep in mind that it is not always the best idea. Unless it serves a concern, the famous "keep it simple" principle should probably be priviledge. To illustrate that, here is the plain old way to write the "same" code - functionnally:

final String[] props = getEnv().systemProperties();
for (int i = 0; i < props.length; i += 2) {
    System.setProperty(props[i], props[i + 1]);
}

Simpler ... don't you think?

From the same author:

In the same category: