I built a generic cache that fetches values on miss by delegating to a ValueGenerator component. Internally, it has a map for values it has already obtained, and another map for in-flight requests so that they can be re-used across subscribers.
Here's the simplified code before I attempt to make it thread safe. My questions will follow.
public class NetworkCache<K, V> {
private final Map<K, V> mValues;
private final Map<K, Observable<V>> mRequests;
private final ValueGenerator<K, V> mValueGenerator;
public NetworkCache(ValueGenerator<K, V> valueGenerator) {
mValues = new HashMap<>();
mRequests = new HashMap<>();
mValueGenerator = valueGenerator;
}
public Observable<V> get(final K key) {
V value = mValues.get(key);
if (value != null) {
// We already had the value
return Observable.just(value);
}
Observable<V> requestObservable = mRequests.get(key);
if (requestObservable == null) {
// New request to fetch the value
requestObservable = mValueGenerator.generate(key);
// Store in-flight request for potential re-use
mRequests.put(key, requestObservable);
requestObservable.subscribe(new Subscriber<V>() {
#Override
public void onCompleted() { mRequests.remove(key); }
#Override
public void onError(Throwable e) { mRequests.remove(key); }
#Override
public void onNext(V value) { mValues.put(key, value); }
});
}
return requestObservable;
}
public interface ValueGenerator<K, V> {
Observable<V> generate(K key);
}
}
Now I'm trying to think how this could break under concurrency scenarios. I believe the focus should be on those two Map that are queried in get(), and modified in the subscribe callback.
I think it's reasonable to assume/enforce that this class can only be called on the main thread. The ValueGenerator, however, should be able to schedule its work on a different thread, as my use case is actually network requests.
I see 3 options, and I'd like help to figure out which one to use.
1. Use ConcurrentHashMap instead of HashMap
Constructor would change to:
public NetworkCache(ValueGenerator<K, V> valueGenerator) {
mValues = new ConcurrentHashMap<>();
mRequests = new ConcurrentHashMap<>();
mValueGenerator = valueGenerator;
}
With this approach, I don't know if it is sufficient and/or overkill.
2. Observe ValueGenerator call on main thread
To me, this means that all map operations would happen on the main thread (assuming that NetworkCache is only used there), even if the ValueGenerator used subscribeOn(Schedulers.io()). This would mean it is thread safe.
if (requestObservable == null) {
// New request to fetch the value
requestObservable = mValueGenerator
.generate(key)
.observeOn(AndroidSchedulers.mainThread());
...
3. Synchronize every access to the maps
I would keep using HashMap and the get method would become the following. Here, is synchronizing on the maps themselves the right approach? Do I need to block on every operation, or just put & remove?
public Observable<V> get(final K key) {
V value;
synchronized (mValues) {
value = mValues.get(key);
}
if (value != null) {
return Observable.just(value);
}
Observable<V> requestObservable;
synchronized (mRequests) {
requestObservable = mRequests.get(key);
}
if (requestObservable == null) {
requestObservable = mValueGenerator.generate(key);
synchronized (mRequests) {
mRequests.put(key, requestObservable);
}
requestObservable.subscribe(new Subscriber<V>() {
#Override
public void onCompleted() {
synchronized (mRequests) {
mRequests.remove(key);
}
}
#Override
public void onError(Throwable e) {
synchronized (mRequests) {
mRequests.remove(key);
}
}
#Override
public void onNext(V value) {
synchronized (mValues) {
mValues.put(key, value);
}
}
});
}
return requestObservable;
}
A little background on the utilization: the cache's get method would be called in rapid succession 1-10 times for different keys. That event would be infrequent, but could happen within a few seconds. It's when the second series of calls arrives, mixed with the observables from the first series coming back, that I worry about the execution.
I would do this with a single ConcurrentMap and AsyncSubject:
public class RequestCache<K, V> {
final ConcurrentMap<K, AsyncSubject<V>> values;
final Function<? super K, ? extends Observable<? extends V>> valueGenerator;
public RequestCache(
Function<? super K, ? extends Observable<? extends V>> valueGenerator) {
this.values = new ConcurrentHashMap<>();
this.valueGenerator = valueGenerator;
}
public Observable<V> get(K key) {
AsyncSubject<V> result = values.get(key);
if (result == null) {
result = AsyncSubject.create();
AsyncSubject<V> current = values.putIfAbsent(key, result);
if (current == null) {
Observable<? extends V> source = valueGenerator.apply(key);
source.subscribe(result);
} else {
result = current;
}
}
return result;
}
}
This is fully threadsafe and calls valueGenerator once per key only.
I think you should synchronize whole getter and setter functions.
Related
I tried looking at cache mechanisms, such as Guava's Cache. Their expiration is only since last update.
What I'm looking for is a data structure that stores keys and cleans the keys after a time has passed since the first insertion. I'm planning for the value to be some counter.
A scenario might be a silent worker that does some work for the first time but keeps silent for an expiry period of time - even if work is requested. If work is requested after the expiry time has passed, he'll do the work.
Know of such a data structure? Thanks.
There are a few options for this.
Passive Removal
If it is not a requirement to clean up the expired keys as soon as they expire or at set intervals (i.e. a key does not need to be removed when the key expires or at some set interval), then PassiveExpiringMap from Apache Commons Collections is a good option. When attempting to access a key in this map, the Time to Live (TTL) of the key (all keys have the same TTL) is checked and if the key has expired, it is removed from the map and null is returned. This data structure does not have an active clean-up mechanism, so expired entries are only removed when they are accessed after the TTL corresponding to the key has expired.
Cache
If more cache-based functionality is needed (such as maximum cache capacity and add/remove listening), Google Guava provides the CacheBuilder class. This class is more complex than the Apache Commons alternative, but it also provides much more functionality. The trade-off may be worth it if this intended for more of a cache-based application.
Threaded Removal
If active removal of expired keys is needed, a separate thread can be spawn that is responsible for removing expired keys. Before looking at a possible implementation structure, it should be noted that this approach may be less performant than the above alternatives. Besides the overhead of starting a thread, the thread may cause contention with clients accessing the map. For example, if a client wants to access a key and the clean-up thread is currently removing expired keys, the client will either block (if synchronization is used) or have a different view of the map (which key-value pairs are contained in the map) if some concurrent mechanism is employed.
With that said, using this approach is complicated because it requires that the TTL be stored with the key. One approach is to create an ExpiringKey, such as (each key can have its own TTL; even if all of the keys will end up having the same TTL value, this technique removes the need to create a Map decorator or some other implementation of the Map interface):
public class ExpiringKey<T> {
private final T key;
private final long expirationTimestamp;
public ExpiringKey(T key, long ttlInMillis) {
this.key = key;
expirationTimestamp = System.currentTimeMillis() + ttlInMillis;
}
public T getKey() {
return key;
}
public boolean isExpired() {
return System.currentTimeMillis() > expirationTimestamp;
}
}
Now the type of the map would be Map<ExpiringKey<K>, V> with some specific K and V type values. The background thread can be represented using a Runnable that resembles the following:
public class ExpiredKeyRemover implements Runnable {
private final Map<ExpiringKey<?>, ?> map;
public ExpiredKeyRemover(Map<ExpiringKey<?>, ?> map) {
this.map = map;
}
#Override
public void run() {
Iterator<ExpiringKey<?>> it = map.keySet().iterator();
while (it.hasNext()) {
if (it.next().isExpired()) {
it.remove();
}
}
}
}
Then the Runnable can be started so that it executes at a fixed interval using a ScheduledExecutorService as follows (which will clean up the map every 5 seconds):
Map<ExpiringKey<K>, V> myMap = // ...
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(new ExpiredKeyRemover(myMap), 0, 5, TimeUnit.SECONDS);
It is important to note that the Map implementation used for myMap must be synchronized or allow for concurrent access. The challenge with a concurrent Map implementation is that the ExpiredKeyRemover may see a different view of the map than a client and an expired key may be returned to the client if the clean-up thread is not completed removing other keys (even if it has removed the desired/expired key since its changes may not have been committed yet). Additionally, the above key-removal code can be implemented using streams, but the above code has been used just to illustrate the logic rather than provide a performant implementation.
Hope that helps.
ExpiringMap
You can use ExpiringMap. This will remove element from map after specified time while initializing the Map . Here is the syntax
public static Map<String, Long> threatURLCacheMap = ExpiringMap.builder().expiration(5, TimeUnit.MINUTES).build();
This will create a Map in which each element will expire 5 minutes of insertion.
You can use this dependencies into your maven project net.jodah.expiringmap.
here is link to learn about it more
https://crunchify.com/how-to-use-expiringmap-maven-java-utility-to-remove-expired-objects-from-map-automatically-complete-java-tutorial/
Created a data structure. Called it DuplicateActionFilterByInsertTime.
The correct notion is filtering duplicate messages. The following class filters from insert time for some period (filterMillis).
Implementation:
public class DuplicateActionFilterByInsertTime<E extends Runnable> {
private static final Logger LOGGER = Logger.getLogger(DuplicateActionFilterByInsertTime.class.getName());
private final long filterMillis;
private final ConcurrentHashMap<E, SilenceInfoImpl> actionMap = new ConcurrentHashMap<>();
private final ConcurrentLinkedQueue<E> actionQueue = new ConcurrentLinkedQueue<>();
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
private final AtomicBoolean purgerRegistered = new AtomicBoolean(false);
private final Set<Listener<E>> listeners = ConcurrentHashMap.newKeySet();
public DuplicateActionFilterByInsertTime(int filterMillis) {
this.filterMillis = filterMillis;
}
public SilenceInfo get(E e) {
SilenceInfoImpl insertionData = actionMap.get(e);
if (insertionData == null || insertionData.isExpired(filterMillis)) {
return null;
}
return insertionData;
}
public boolean run(E e) {
actionMap.computeIfPresent(e, (e1, insertionData) -> {
int count = insertionData.incrementAndGet();
if (count == 2) {
notifyFilteringStarted(e1);
}
return insertionData;
});
boolean isNew = actionMap.computeIfAbsent(e, e1 -> {
SilenceInfoImpl insertionData = new SilenceInfoImpl();
actionQueue.add(e1);
return insertionData;
}).getCount() == 1;
tryRegisterPurger();
if (isNew) {
e.run();
}
return isNew;
}
private void tryRegisterPurger() {
if (actionMap.size() != 0 && purgerRegistered.compareAndSet(false, true)) {
scheduledExecutorService.schedule(() -> {
try {
for (Iterator<E> iterator = actionQueue.iterator(); iterator.hasNext(); ) {
E e = iterator.next();
SilenceInfoImpl insertionData = actionMap.get(e);
if (insertionData == null || insertionData.isExpired(filterMillis)) {
iterator.remove();
}
if (insertionData != null && insertionData.isExpired(filterMillis)) {
SilenceInfoImpl removed = actionMap.remove(e);
FilteredItem<E> filteredItem = new FilteredItem<>(e, removed);
notifySilenceFinished(filteredItem);
} else {
// All the elements that were left shouldn't be purged.
break;
}
}
} finally {
purgerRegistered.set(false);
tryRegisterPurger();
}
}, filterMillis, TimeUnit.MILLISECONDS);
}
}
private void notifySilenceFinished(FilteredItem<E> filteredItem) {
new Thread(() -> listeners.forEach(l -> {
try {
l.onFilteringFinished(filteredItem);
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Purge notification failed. Continuing to next one (if exists)", e);
}
})).start();
}
private void notifyFilteringStarted(final E e) {
new Thread(() -> listeners.forEach(l -> {
try {
l.onFilteringStarted(e);
} catch (Exception e1) {
LOGGER.log(Level.WARNING, "Silence started notification failed. Continuing to next one (if exists)", e1);
}
})).start();
}
public void addListener(Listener<E> listener) {
listeners.add(listener);
}
public void removeLister(Listener<E> listener) {
listeners.remove(listener);
}
public interface SilenceInfo {
long getInsertTimeMillis();
int getCount();
}
public interface Listener<E> {
void onFilteringStarted(E e);
void onFilteringFinished(FilteredItem<E> filteredItem);
}
private static class SilenceInfoImpl implements SilenceInfo {
private final long insertTimeMillis = System.currentTimeMillis();
private AtomicInteger count = new AtomicInteger(1);
int incrementAndGet() {
return count.incrementAndGet();
}
#Override
public long getInsertTimeMillis() {
return insertTimeMillis;
}
#Override
public int getCount() {
return count.get();
}
boolean isExpired(long expirationMillis) {
return insertTimeMillis + expirationMillis < System.currentTimeMillis();
}
}
public static class FilteredItem<E> {
private final E item;
private final SilenceInfo silenceInfo;
FilteredItem(E item, SilenceInfo silenceInfo) {
this.item = item;
this.silenceInfo = silenceInfo;
}
public E getItem() {
return item;
}
public SilenceInfo getSilenceInfo() {
return silenceInfo;
}
}
}
Test example: (More tests here)
#Test
public void testSimple() throws InterruptedException {
int filterMillis = 100;
DuplicateActionFilterByInsertTime<Runnable> expSet = new DuplicateActionFilterByInsertTime<>(filterMillis);
AtomicInteger purgeCount = new AtomicInteger(0);
expSet.addListener(new DuplicateActionFilterByInsertTime.Listener<Runnable>() {
#Override
public void onFilteringFinished(DuplicateActionFilterByInsertTime.FilteredItem<Runnable> filteredItem) {
purgeCount.incrementAndGet();
}
#Override
public void onFilteringStarted(Runnable runnable) {
}
});
Runnable key = () -> {
};
long beforeAddMillis = System.currentTimeMillis();
boolean added = expSet.run(key);
long afterAddMillis = System.currentTimeMillis();
Assert.assertTrue(added);
DuplicateActionFilterByInsertTime.SilenceInfo silenceInfo = expSet.get(key);
Assertions.assertThat(silenceInfo.getInsertTimeMillis()).isBetween(beforeAddMillis, afterAddMillis);
expSet.run(key);
DuplicateActionFilterByInsertTime.SilenceInfo silenceInfo2 = expSet.get(key);
Assert.assertEquals(silenceInfo.getInsertTimeMillis(), silenceInfo2.getInsertTimeMillis());
Assert.assertFalse(silenceInfo.getInsertTimeMillis() + filterMillis < System.currentTimeMillis());
Assert.assertEquals(silenceInfo.getCount(), 2);
Thread.sleep(filterMillis);
Assertions.assertThat(expSet.get(key)).isNull();
Assert.assertNull(expSet.get(key));
Thread.sleep(filterMillis * 2); // Give a chance to purge the items.
Assert.assertEquals(1, purgeCount.get());
System.out.println("Finished");
}
Source.
There are a couple of Listeners L1, L2, ... all similar:
interface L1 { void onL1(); }
interface L2 { void onL2(); }
...
All are used in class EventMaker like this:
class EventMaker {
...
List<L1> l1s = new LinkedList<>();
List<L2> l2s = new LinkedList<>();
...
void addL1(L1 l1) {...; l1s.add(l1); ...;}
void removeL1(L1 l1) {...; l1s.remove(l1); ...;}
void callL1() {...}
void addL2(L2 l2) {l2s.add(l2);}
void removeL2(L2 l2) {l2s.remove(l2);}
void callL2() {...}
...
}
What can I do, to reduce the repeating code? I tried to use generic methods, but it is no solution in many ways.
// ************************************************************************
My Solution:
abstract class Caller<Listener> {
List<Listener> listeners;
public Caller() {
listeners = new LinkedList<>();
}
public void add(Listener listener) {
listeners.add(listener);
}
public void remove(Listener listener) {
listeners.remove(listener);
}
public void call() {
for (Listener listener : listeners) {
onCall(listener);
}
}
public abstract void onCall(Listener listener);
}
Empty Listener-Interface:
interface Listener {
}
For Every-Listener:
class L1Caller extends Caller<L1> {
#Override
public void onCall(L1 listener) {
listener.l1(); // unique name
}
}
Finally I add for every listern-type a caller to my main-class.
...
L1Caller l1Caller;
L2Caller l2Caller;
...
And use it like:
l1Caller.add(...);
l2Caller.call();
I don't know if this is best practice, but it's certainly possible.
public class Caller {
public static final Token<L1> L1 = new Token<>();
public static final Token<L2> L2 = new Token<>();
public static class Token<T> {
// Making the constructor private means that no other Tokens can be made.
private Token() {}
}
private final Map<Token<?>, List<Object>> lists;
public Caller() {
lists = new HashMap<>();
Token<?>[] tokens = {L1, L2};
for (Token<?> token : tokens)
lists.put(token, new LinkedList<>());
}
public <T> void add(Token<T> token, T t) {
lists.get(token).add(t);
}
public <T> void remove(Token<T> token, T t) {
lists.get(token).remove(t);
}
}
Despite the use of wildcards and Object, it's completely type-safe and is easy to use:
caller.add(Caller.L1, () -> {
// do stuff
});
Use the existing ChangeListener with its ChangeEvent where the source is of interest. Alterative use generic types.
Then make a class to hold a list of listeners, say
public class ChangeManager {
private final List listeners = ...
public void addChangeListener(ChangeListener listener) { ... }
public void notifyChange(ChangeEvent event) { ... }
}
This can handle listeners in a garbage collected and concurrency safe way.
Now your class delegates to several ChangeManagers.
private final ChangeManager l1 = new ChangeManager();
private final ChangeManager l2 = new ChangeManager();
private final ChangeEvent L1_EVENT = new ChangeEvent(this);
...
l1.addChangeListener(changeEvent -> {
...
});
l1.notifyChange(L1_EVENT);
You should retain the individual add* methods to your API because they are meaningful and makes for a clearer API. One option which alters your API is to have a single add(type, listener) and route all invocations through it. However, then you must expose that type and the client must coordinate on adding the right listener to the right type.
One way to not alter your API but internally manage the listeners in aggregate is a pattern like this:
class EventMaker {
...
static String TYPE_L1 = "L1";
static String TYPE_L2 = "L2";
Map<String, List<Object>> listeners;
...
void addInternal(String t, Object listener) {
List<Object> list = listeners.get(t);
if (list == null) { list = new CopyOnWriteArrayList<>(); listeners.put(t, list); }
list.add(listener);
}
void removeInternal(String t, Object listener) {
List<Object> list = listeners.get(t);
if (list != null) { list.remove(listener; }
// optional
if (list != null && list.isEmpty) listeners.remove(t);
}
<ListenerType> List<ListenerType> getInternal(String t, Class<ListenerType> cls) {
List<Object> list = listeners.get(t);
if (list == null) return Collections.emptyList();
return (List<ListenerType>)list;
}
void removeInternal(String t, Object listener) {...}
void addL1(L1 l1) { addInternal(TYPE_L1, l1);}
void removeL1(L1 l1) { removeInternal(TYPE_L1, l1);}
void callL1() {
List<L1> list = getInternal(TYPE_L1, L1.class);
for (L1 ears : list) ears.onL1();
}
void addL2(L2 l2) {addInternal(TYPE_L2, l2);}
void removeL2(L2 l2) {removeInternal(TYPE_L2, l2);}
void callL2() {...}
...
}
The type is ignored in the map since you are protecting everything in and out, and safely cast when accessing one of the listener lists. The type is still necessary when notifying your listeners though since they have no common base. The concurrent-safe CopyOnWriteArrayList also has some performance implications worth looking into for listener lists.
I would also recommend returning a handle instead of requiring a removeListener call. This allows the caller to not have to look up the event source when cleaning up, but has an OO handle that does the work. java.lang.AutoCloseable (if using Java 7 or later, else java.lang.Runnable) is a good choice for this:
AutoCloseable addInternal(String t, final Object listener) {
List<Object> list = listeners.get(t);
if (list == null) { list = new ArrayList<>(); listeners.put(t, list); }
list.add(listener);
final List<Object> flist = list; // for final reference below
return new AutoCloseable() {
public void close() { flist.remove(listener); }
};
}
And now the caller operates by simply calling .close() on that returned handle to unregister.
And a simpler handle if you are using Java 8:
AutoCloseable addInternal(String t, final Object listener) {
List<Object> list = listeners.get(t);
if (list == null) { list = new ArrayList<>(); listeners.put(t, list); }
list.add(listener);
return () -> list.remove(listener);
}
You also should look into properly synchronizing to ensure thread-safety if it is a concern, making your fields private and final as appropriate, and other good-practice cleanup I did not address in those examples.
I am trying to write some general code to do the following. Given two kinds of "operations", (a) validation (eg. input: object & context -> output: boolean), and (b) transformation (eg. input: object_A, context -> output: object_B) -objects of any type-.
I want to be able to build chains of "operations", in which an input object and its context can be submitted through (eg. to validate and transform the object). Returning immediately if the object is "invalid" and being able to get the transformed object if it finished "valid".
Idea is that "validations" and "transformations" can be "plugable" functions that other people write and assemble in a chain (eg. they build chains and submit objects through them).
I managed to do the following code, which compiles and seems to work. However, I'm not an expert on generics and would like to hear feedback about possible pitfalls, enhancements, or even maybe some other better/easier approach to the problem. Thanks in advance.
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
interface Operation<T, U, V> {
U execute(T a, V context);
}
abstract class Validation<T, V> implements Operation<T, Boolean, V> {
#Override
public Boolean execute(T a, V context) {
return executeValidation(a, context);
}
public abstract Boolean executeValidation(T a, V context);
}
abstract class Transformation<T, U, V> implements Operation<T, U, V> {
#Override
public U execute(T a, V context) {
return executeTransformation(a, context);
}
public abstract U executeTransformation(T a, V context);
}
class OperationsChain {
List<Operation<Object, Object, Object>> operations = new ArrayList<Operation<Object, Object, Object>>();
Object currentObj;
public <T, V> Boolean run(T a, V context) {
Boolean valid = false;
currentObj = a;
for (Operation<Object, Object, Object> operation : operations) {
if (operation instanceof Validation) {
valid = (Boolean) operation.execute(currentObj, context);
} else if (operation instanceof Transformation) {
currentObj = operation.execute(currentObj, context);
}
if (!valid) {
break;
}
}
return valid;
}
#SuppressWarnings("unchecked")
public <T, U, V> void addOperation(Operation<T, U, V> operation) {
operations.add((Operation<Object, Object, Object>) operation);
}
public Object getCurrentObject() {
return currentObj;
}
}
class ValidationOne extends Validation<MapObject, Map<String, Object>> {
public Boolean executeValidation(MapObject a, Map<String, Object> context) {
if (context.containsKey("validation 1")) {
return (Boolean) context.get("validation 1");
} else {
return false;
}
}
}
class ValidationTwo extends Validation<MapObject, Map<String, Object>> {
public Boolean executeValidation(MapObject a, Map<String, Object> context) {
if (context.containsKey("validation 2")) {
return (Boolean) context.get("validation 2");
} else {
return false;
}
}
}
class TransformationOne extends Transformation<MapObject, MapObject, Map<String, Object>> {
public MapObject executeTransformation(MapObject a, Map<String, Object> context) {
if (context.containsKey("transformation 1")) {
a.addField("data", (String) context.get("transformation 1"));
}
return a;
}
}
class MapObject {
Map<String, String> fields = new HashMap<String, String>();
public void addField(String key, String value) {
fields.put(key, value);
}
public String getField(String key, String value) {
if (fields.containsKey(key)) {
return fields.get(key);
} else {
return null;
}
}
public String toString() {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : fields.entrySet()) {
sb.append(entry.getKey());
sb.append(": ");
sb.append(entry.getValue());
sb.append("\n");
}
return sb.toString();
}
}
class OperationsChainDriver {
public static void main(String[] args) {
OperationsChain oc = new OperationsChain();
oc.addOperation(new ValidationOne());
oc.addOperation(new TransformationOne());
oc.addOperation(new ValidationTwo());
oc.addOperation(new TransformationOne());
Map<String, Object> context = new HashMap<String, Object>();
context.put("validation 1", true);
context.put("validation 2", false);
context.put("transformation 1", "aloha");
MapObject mapObject = new MapObject();
mapObject.addField("field 1", "hello");
Boolean result = oc.run(mapObject, context);
if (result == true) {
System.out.println("valid\n"+oc.getCurrentObject().toString());
} else {
System.out.println("invalid\n"+oc.getCurrentObject().toString());
}
}
}
Generics are about type safety - not having to cast, because as you surely know casts are risks proved runtime. You have a very generic design yet get very concrete to and the like and have to cast a lot - this shouldn't happen since it defeats the reason to use generics at all.
As as side note: why not give an operation a method isValid that has always a return type of Boolean, a transformation can fail, too, so yo don't have to make a difference between validation and transformation. Or let it put a value in a context - the operation could know its context and could use it without casts. An operation chain could know its context and could get the results without casts.
Anyway - as long as you code has casts you are still not finished with it.
This kind of task is one that I think a functional language would be ideal for, e.g. Scala (which runs on the JVM and is perfect for interoperating with Java code), or Haskell (which doesn't run on the JVM, but has some other advantages).
OK, I understand if you don't want to learn a new programming language. But one of the key advantages would be that your code should be shorter and easier to read and reason about.
I have data that is organized in kind of a "key-key" format, rather than "key-value". It's like a HashMap, but I will need O(1) lookup in both directions. Is there a name for this type of data structure, and is anything like this included in Java's standard libraries? (or maybe Apache Commons?)
I could write my own class that basically uses two mirrored Maps, but I'd rather not reinvent the wheel (if this already exists but I'm just not searching for the right term).
There is no such class in the Java API. The Apache Commons class you want is going to be one of the implementations of BidiMap.
As a mathematician, I would call this kind of structure a bijection.
In addition to Apache Commons, Guava also has a BiMap.
Here is a simple class I used to get this done (I did not want to have yet another third party dependency). It does not offer all features available in Maps but it is a good start.
public class BidirectionalMap<KeyType, ValueType>{
private Map<KeyType, ValueType> keyToValueMap = new ConcurrentHashMap<KeyType, ValueType>();
private Map<ValueType, KeyType> valueToKeyMap = new ConcurrentHashMap<ValueType, KeyType>();
synchronized public void put(KeyType key, ValueType value){
keyToValueMap.put(key, value);
valueToKeyMap.put(value, key);
}
synchronized public ValueType removeByKey(KeyType key){
ValueType removedValue = keyToValueMap.remove(key);
valueToKeyMap.remove(removedValue);
return removedValue;
}
synchronized public KeyType removeByValue(ValueType value){
KeyType removedKey = valueToKeyMap.remove(value);
keyToValueMap.remove(removedKey);
return removedKey;
}
public boolean containsKey(KeyType key){
return keyToValueMap.containsKey(key);
}
public boolean containsValue(ValueType value){
return keyToValueMap.containsValue(value);
}
public KeyType getKey(ValueType value){
return valueToKeyMap.get(value);
}
public ValueType get(KeyType key){
return keyToValueMap.get(key);
}
}
If no collisions occur, you can always add both directions to the same HashMap :-)
Here my 2 cents.
Or you can use a simple method with generics. Piece of cake.
public static <K,V> Map<V, K> invertMap(Map<K, V> toInvert) {
Map<V, K> result = new HashMap<V, K>();
for(K k: toInvert.keySet()){
result.put(toInvert.get(k), k);
}
return result;
}
Of course you must have a map with unique values. Otherwise, one of them will be replaced.
Inspired by GETah's answer I decided to write something similar by myself with some improvements:
The class is implementing the Map<K,V>-Interface
The bidirectionality is really guaranteed by taking care of it when changing a value by a put (at least I hope to guarantee it hereby)
Usage is just like a normal map, to get a reverse view on the mapping call getReverseView(). The content is not copied, only a view is returned.
I'm not sure this is totally fool-proof (actually, it's probably not), so feel free to comment if you notice any flaws and I'll update the answer.
public class BidirectionalMap<Key, Value> implements Map<Key, Value> {
private final Map<Key, Value> map;
private final Map<Value, Key> revMap;
public BidirectionalMap() {
this(16, 0.75f);
}
public BidirectionalMap(int initialCapacity) {
this(initialCapacity, 0.75f);
}
public BidirectionalMap(int initialCapacity, float loadFactor) {
this.map = new HashMap<>(initialCapacity, loadFactor);
this.revMap = new HashMap<>(initialCapacity, loadFactor);
}
private BidirectionalMap(Map<Key, Value> map, Map<Value, Key> reverseMap) {
this.map = map;
this.revMap = reverseMap;
}
#Override
public void clear() {
map.clear();
revMap.clear();
}
#Override
public boolean containsKey(Object key) {
return map.containsKey(key);
}
#Override
public boolean containsValue(Object value) {
return revMap.containsKey(value);
}
#Override
public Set<java.util.Map.Entry<Key, Value>> entrySet() {
return Collections.unmodifiableSet(map.entrySet());
}
#Override
public boolean isEmpty() {
return map.isEmpty();
}
#Override
public Set<Key> keySet() {
return Collections.unmodifiableSet(map.keySet());
}
#Override
public void putAll(Map<? extends Key, ? extends Value> m) {
m.entrySet().forEach(e -> put(e.getKey(), e.getValue()));
}
#Override
public int size() {
return map.size();
}
#Override
public Collection<Value> values() {
return Collections.unmodifiableCollection(map.values());
}
#Override
public Value get(Object key) {
return map.get(key);
}
#Override
public Value put(Key key, Value value) {
Value v = remove(key);
getReverseView().remove(value);
map.put(key, value);
revMap.put(value, key);
return v;
}
public Map<Value, Key> getReverseView() {
return new BidirectionalMap<>(revMap, map);
}
#Override
public Value remove(Object key) {
if (containsKey(key)) {
Value v = map.remove(key);
revMap.remove(v);
return v;
} else {
return null;
}
}
}
Quite an old question here, but if someone else has brain block like I just did and stumbles on this, hopefully this will help.
I too was looking for a bi-directional HashMap, sometimes it is the simplest of answers that are the most useful.
If you do not wish to re-invent the wheel and prefer not to add other libraries or projects to your project, how about a simple implementation of parallel arrays (or ArrayLists if your design demands it).
SomeType[] keys1 = new SomeType[NUM_PAIRS];
OtherType[] keys2 = new OtherType[NUM_PAIRS];
As soon as you know the index of 1 of the two keys you can easily request the other. So your lookup methods could looks something like:
SomeType getKey1(OtherType ot);
SomeType getKey1ByIndex(int key2Idx);
OtherType getKey2(SomeType st);
OtherType getKey2ByIndex(int key2Idx);
This is assuming you are using proper object oriented structures, where only methods are modifying these arrays/ArrayLists, it would be very simple to keep them parallel. Even easier for an ArrayList since you would not have to rebuild if the size of the arrays change, so long as you add/remove in tandem.
I need to create a Custom Hashtable extends java.lang.Hashtable and i need to override the get method to achieve the following behavior :
if the key == null, it will return a new object of the type V
if the super.get(key) == null, it will also return a new object of type V.
Can anyone help me.
I try to do this but I know it's wrong.
import java.util.Hashtable;
public class CustomHashtable<K, V> extends Hashtable {
#Override
public synchronized V get(Object key) {
if(key == null) return new Object();
Object v = super.get(key);
if(v == null){
return new Object();
}
}
}
please see the line :
if(key == null) return new Object();
and the lines :
if(v == null){
return new Object();
}
to know where the error occurred..
You'd have to store the class related to V and create a new instance. For example:
public class CustomHashtable<K, V> extends Hashtable {
Class<V> clazz;
public CustomHashtable(Class<V> clazz) {
this.clazz = clazz;
}
#Override
public synchronized V get(Object key) {
if(key == null) return newValue();
Object v = super.get(key);
if(v == null){
return newValue();
}
}
private V newValue() {
try {
return clazz.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException (e);
} catch (IllegalAccessException e) {
throw new RuntimeException (e);
}
}
}
(You may want to change the exception handling of course.)
An alternative is to make the caller effectively provide a factory to create a new instance of V. You'd do this with an interface such as:
public interface Factory<T> {
T create();
}
You could then store the factory in the custom hashtable, and call create any time you needed to.
The primary issue here is what you are trying to achieve is fundamentally wrongheaded. Checkout the methods of your class. The majority of them will now be inconsistent with get. Worse, exactly how methods are implemented in terms of other public methods is not defined - such is the curse of inheritance.
Therefore, create a class that represents whatever abstraction you are trying to achieve. Have the contain not inherit from an appropriate map implementation.
The natural map in this case is probably not ye olde Hashtable but java.util.concurrent.ConcurrentHashMap. The important method here is [putIfAbsent][2]. Unfortunately the API docs suck. Here is how it should be used:
public V getOrCreate(K key) {
final V value = map.get(key);
if (value != null) {
return value;
}
V newValue = factory.create(key); // May discard.
V oldValue = map.putIfAbsent(key, value);
return oldValue==null ? newValue : oldValue;
}
(You can use a Future if you want to ensure that you never discard a value.)
To create I've assumed some kind of an abstract factory. In general methods don't have no-args public constructors that happen not to throw exceptions. Certainly avoid reflection like swine flu crossed with H5N1. Instead use an appropriate (abstraction-specific) abstract factory passed in at creation time.
public interface MySortOfFactory<
T /*extends SomeEntity*/,
A /*extends SomeInfo*/
> {
T create(A arg);
}
[2]: http://java.sun.com/javase/6/docs/api/java/util/concurrent/ConcurrentMap.html#putIfAbsent(K, V)
Do you need to create a new instance? or is it sufficient to return a default instance?
The latter could be implemented like:
public class CustomHashtable<K, V> extends Hashtable<K, V> {
/** Default instance. */
private final V defaultValue;
public CustomHashtable(V defaultValue) {
this.defaultValue= defaultValue;
}
#Override
public synchronized V get(Object key) {
if(key != null) {
V val = super.get(key);
if(val != null) {
return val;
}
}
return defaultValue;
}
}
(but I still prefer Jon's factory solution: more flexible and also covers the default instance solution)
I understand what you asked, but could I ask the following please:
Do you always want a new object when the key is null, or don't you just want to allow a null key?
Also, do you definitely need a new instance when you can't find the key, or will the same instance do in each case where you can't find the key?
Are you going to put the new instances into the Hashtable?
Does it have to be a Hashtable, or could a HashMap do?
I'm just wondering if you had considered using a LazyMap from Apache Commons Collections?