1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
package bjc.utils.funcdata;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import bjc.utils.data.Pair;
/**
* Functional wrapper over map providing some useful things
*
* @author ben
*
* @param <K>
* The type of this map's keys
* @param <V>
* The type of this map's values
*
*/
public class FunctionalMap<K, V> {
private final class TransformedMap<V2> extends FunctionalMap<K, V2> {
private FunctionalMap<K, V> mapToTransform;
private Function<V, V2> transformer;
public TransformedMap(FunctionalMap<K, V> destMap,
Function<V, V2> transform) {
mapToTransform = destMap;
transformer = transform;
}
@Override
public V2 get(K key) {
return transformer.apply(mapToTransform.get(key));
}
}
private Map<K, V> wrappedMap;
/**
* Create a new blank functional map
*/
public FunctionalMap() {
wrappedMap = new HashMap<>();
}
/**
* Create a new functional map wrapping the specified map
*
* @param wrap
* The map to wrap
*/
public FunctionalMap(Map<K, V> wrap) {
if (wrap == null) {
throw new NullPointerException("Map to wrap must not be null");
}
wrappedMap = wrap;
}
/**
* Create a new functional map with the specified entries
*
* @param entries
* The entries to put into the map
*/
@SafeVarargs
public FunctionalMap(Pair<K, V>... entries) {
this();
for (Pair<K, V> entry : entries) {
entry.doWith((key, val) -> {
wrappedMap.put(key, val);
});
}
}
/**
* Add an entry to the map
*
* @param key
* The key to put the value under
* @param val
* The value to add
* @return The previous value of the key in the map, or null if the key
* wasn't in the map. However, note that it may also return
* null if the key was set to null.
*
*/
public V put(K key, V val) {
if (key == null) {
throw new NullPointerException("Key must not be null");
}
return wrappedMap.put(key, val);
}
/**
* Get the value assigned to the given key
*
* @param key
* The key to look for a value under
* @return The value of the key
*
*
*/
public V get(K key) {
if (key == null) {
throw new NullPointerException("Key must not be null");
}
if (wrappedMap.containsKey(wrappedMap)) {
return wrappedMap.get(key);
} else {
throw new IllegalArgumentException(
"Key " + key + " is not present in the map");
}
}
/**
* Transform the values returned by this map.
*
* NOTE: This transform is applied once for each lookup of a value, so
* the transform passed should be a proper function, or things will
* likely not work as expected.
*
* @param <V2>
* The new type of returned values
* @param transformer
* The function to use to transform values
* @return The map where each value will be transformed after lookup
*/
public <V2> FunctionalMap<K, V2>
mapValues(Function<V, V2> transformer) {
if (transformer == null) {
throw new NullPointerException("Transformer must not be null");
}
return new TransformedMap<>(this, transformer);
}
/**
* Check if this map contains the specified key
*
* @param key
* The key to check
* @return Whether or not the map contains the key
*/
public boolean containsKey(K key) {
return wrappedMap.containsKey(key);
}
}
|