I have a list of Station, in each Station there is a list of radios. I need to create a lookup Map of radio to Station. I know how to use Java 8 stream forEach to do it:
You can do it without Streams, of course, probably making it a bit more readable.
Map LOOK_UP = new HashMap<>();
List stations = ...
stations.forEach(station -> {
station.getRadios().forEach(radio -> {
LOOK_UP.put(radio, station);
});
});
This is not very different than a plain loop with:
for (Station station : stations) {
for (Radio radio : station.getRadios()) {
LOOK_UP.put(radio, station);
}
}
The obvious problem here is that LOOK_UP::put
will always replace the value for a certain key, hiding the fact that you ever had duplicates. For example:
[StationA = {RadioA, RadioB}]
[StationB = {RadioB}]
When you search for RadioB
- what should you get as a result?
If you could have such a scenario, the obvious thing is to change the LOOK-UP
definition and use Map::merge
:
Map> LOOK_UP = new HashMap<>();
List stations = new ArrayList<>();
stations.forEach(station -> {
station.getRadios().forEach(radio -> {
LOOK_UP.merge(radio,
Collections.singletonList(station),
(left, right) -> {
List merged = new ArrayList<>(left);
merged.addAll(right);
return merged;
});
});
});
Another possibility is to throw an Exception when there are these kid of mappings:
stations.forEach(station -> {
station.getRadios().forEach(radio -> {
LOOK_UP.merge(radio, station, (left, right) -> {
throw new RuntimeException("Duplicate Radio");
});
});
});
The problem with this last snippet, is that you can't really log the radio
that is to be blamed for non-uniqueness. left
and right
are Stations
s. If you want that too, you will need to use a merger that does not rely on Map::merge
internally, like in this answer.
So you can see, that it all depends on how and what exactly you need to handle.