I wrote myself a MapFilter class to handle this efficiently. Essentially, you create a Map and then filter it by specifying a prefix for the key. There is also a constructor that takes a Properties for convenience.
Be aware that this just filters the main map. Any changes applied to the filtered map are also applied to the base map, including deletions etc but obviously changes to the main map will not be reflected in the filtered map until something causes a rebuild.
It is also very easy (and efficient) to filter already filtered maps.
public class MapFilter implements Map {
// The enclosed map -- could also be a MapFilter.
final private Map map;
// Use a TreeMap for predictable iteration order.
// Store Map.Entry to reflect changes down into the underlying map.
// The Key is the shortened string. The entry.key is the full string.
final private Map> entries = new TreeMap<>();
// The prefix they are looking for in this map.
final private String prefix;
public MapFilter(Map map, String prefix) {
// Store my backing map.
this.map = map;
// Record my prefix.
this.prefix = prefix;
// Build my entries.
rebuildEntries();
}
public MapFilter(Map map) {
this(map, "");
}
private synchronized void rebuildEntries() {
// Start empty.
entries.clear();
// Build my entry set.
for (Map.Entry e : map.entrySet()) {
String key = e.getKey();
// Retain each one that starts with the specified prefix.
if (key.startsWith(prefix)) {
// Key it on the remainder.
String k = key.substring(prefix.length());
// Entries k always contains the LAST occurrence if there are multiples.
entries.put(k, e);
}
}
}
@Override
public String toString() {
return "MapFilter (" + prefix + ") of " + map + " containing " + entrySet();
}
// Constructor from a properties file.
public MapFilter(Properties p, String prefix) {
// Properties extends HashTable