Skip to content

Instantly share code, notes, and snippets.

@UnquietCode
Created September 6, 2012 11:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save UnquietCode/3654940 to your computer and use it in GitHub Desktop.
Save UnquietCode/3654940 to your computer and use it in GitHub Desktop.
Map with simplified CRUD semantics for Java
/**
* Copyright 2012 Benjamin Fagin
* http://www.unquietcode.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import java.util.HashMap;
import java.util.Map;
/**
* Map which has more concrete semantics for basic CRUD operations.
* Internally, a {@link HashMap} is used to store the data.
* For clarity, {@code null} values are not allowed.
*
* The class is thread safe, but every call is synchronized to block
* other threads. Concurrent use will therefore be slower.
*
* @author Benjamin Fagin
* @version 09-06-2012
*/
public class CRUDMap<K, V> {
private final Map<K,V> map = new HashMap<K, V>();
/**
* Adds a new value to the map. If the map already contains a value
* at the given key, an exception is raised. If your intent
* is to update the value regardless of whether it is present or not,
* consider using the {@link #addOrUpdate(Object, Object)} method instead.
*
* @param key the lookup key
* @param value the value to store
* @throws IllegalStateException if the map already contains a value at the given key
*/
public synchronized void add(K key, V value) {
if (map.containsKey(key)) {
throw new IllegalStateException("A value for '"+key+"' is already present.");
}
if (value == null) {
throw new IllegalArgumentException("Value cannot be null.");
}
map.put(key, value);
}
/**
* Updates an existing value in the map. The previous value is returned.
* If no value was present, then an exception is raised. If your intent
* is to store the value regardless of whether it is present or not,
* consider using the {@link #addOrUpdate(Object, Object)} method instead.
*
* @param key the lookup key
* @param value the value to store
* @return the previous value
* @throws IllegalStateException if there was no previous value
*/
public synchronized V update(K key, V value) {
if (!map.containsKey(key)) {
throw new IllegalStateException("There is no value to update for key '"+key+"'.");
}
if (value == null) {
throw new IllegalArgumentException("Value cannot be null.");
}
return map.put(key, value);
}
/**
* Adds a new value, or updates an existing value in the map. The previous
* value is returned. If no value was present, then {@code null} will be
* the returned value.
*
* @param key the lookup key
* @param value the value to store
* @return the previous value or {@code null}
*/
public synchronized V addOrUpdate(K key, V value) {
if (value == null) {
throw new IllegalArgumentException("Value cannot be null.");
}
return map.put(key, value);
}
/**
* Removes a value from the map. Returns true if a value was removed, or
* false if the operation had no effect.
*
* @param key the lookup key
* @return true if a value was removed, false otherwise
*/
public synchronized boolean remove(K key) {
return map.remove(key) != null;
}
/**
* Returns true if the map contains the given key.
*
* @param key the lookup key
* @return true if the map contains the key, false otherwise
*/
public synchronized boolean contains(K key) {
return map.containsKey(key);
}
/**
* Retrieve an element from the map. Because {@code null} values are not allowed,
* a returned value of {@code null} will always mean that the map did not contain
* the value. Therefore, a call to {@link #contains(Object)} which returns true
* will guarantee that a call to get(key) will always return a non-null value.
*
* @param key the lookup key
* @return the value stored under the given key, or null
*/
public synchronized V get(K key) {
return map.get(key);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment