Reputation: 3636
I'm trying to read Java system properties at runtime, filter based on an includes
list (hard coded here but normally injected in via properties file) and finally sorted by key and converted to a Map<String, String>
. This is what I've come up with but not sure if it's the most elegant solution.
final List<String> includes = Arrays
.asList("java.version", "PID", "os.name", "user.country"); // hard coded here but (usually defined in a properties file)
Map<String, String> systemMap = System.getProperties()
.entrySet().stream()
.filter(s -> includes != null && includes.contains(s.getKey()))
.sorted(Comparator.comparing(
Map.Entry::getKey, Comparator.comparing(e -> (String) e))
)
.collect(Collectors.toMap(
e -> (String) e.getKey(),
e -> (String) e.getValue(),
(e1, e2) -> e2,
LinkedHashMap::new)
);
I'm keen to know if the code can be tidied up.
Upvotes: 4
Views: 5997
Reputation: 1906
My opinion, get all properties (about 100) to filter 4 is suboptimal.
My proposal is:
// hard coded here but (usually defined in a properties file)
final List<String> includes = Arrays.asList("java.version", "PID",
"os.name", "user.country");
Map<String, String> systemMap = includes.stream()
.collect(Collectors.toMap(e -> e,
e -> System.getProperty(e)));
UPDATE: sorted version
final List<String> includes = Arrays.asList("java.version", "PID",
"os.name", "user.country");
Map<String, String> systemMap = includes.stream()
.collect(Collectors.toMap(e -> e,
e -> System.getProperty(e),
(e1, e2) -> e2,
TreeMap::new));
return systemMap;
Upvotes: 3
Reputation: 49606
The "good" part here is that Properties extends Hashtable<Object,Object>
which is a source of problems. Unsurprisingly, the System.getProperties().entrySet()
returns a Set<Map.Entry<Object, Object>>
.
Therefore, we need one additional mapping operation to turn each Entry<Object, Object>
into a Entry<String, String>
before we move on to filtering and sorting:
final Map<String, String> map = System.getProperties()
.entrySet()
.stream()
.map(e -> new AbstractMap.SimpleEntry<>(e.getKey().toString(), e.getValue().toString()))
.filter(e -> includes.contains(e.getKey()))
.sorted(Comparator.comparing(AbstractMap.SimpleEntry::getKey))
.collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
The method references look vague, so the last 2 operations would use shorter lambda expressions:
.sorted(Comparator.comparing(e -> e.getKey()))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
Another option is iterating over the includes
list which seems to be smaller than the System.getProperties()
:
final Properties properties = System.getProperties();
final Map<String, String> map2 = includes
.stream()
.filter(properties::containsKey)
.sorted()
.collect(Collectors.toMap(Function.identity(), properties::getProperty));
Upvotes: 2
Reputation: 82899
How about reversing it and using a stream
of the includes
list instead? This way, you don't have to unpack those map entries all the time, you can just use sorted
, and if includes
only includes valid properties, you might not even need the filter
. (Also, lookup in the map is faster than lookup in the list, but that probably does not matter much.)
Properties props = System.getProperties();
Map<String, String> systemMap = includes.stream()
.filter(props::containsKey)
.sorted()
.collect(Collectors.toMap(s -> s, props::getProperty,
(e1, e2) -> e2,
LinkedHashMap::new)
);
Upvotes: 5