How to verify Map size using Hamcrest - java

Map<Integer, Map<String, String>> mapMap = new HashMap<Integer,Map<String, String>>();
Currently asserting like this
assertThat(mapMap.size(), is(equalTo(1)));
Or
assertThat(mapMap.values(), hasSize(1));
Are there any other methods like one used with Lists.
assertThat(someListReferenceVariable, hasSize(1));

The good news
There is a matcher that does exactly what you want in the current master branch of the JavaHamcrest project.
You can call it like so:
assertThat(mapMap, aMapWithSize(1));
And the bad news
Unfortunately this matcher is not in the latest release of Hamcrest (1.3).
[Update] And finally the very good news
The aforementioned matcher is included in the newly released version 2.1.

There is none in Hamcrest 1.3, but you can very easily create your own:
public class IsMapWithSize<K, V> extends FeatureMatcher<Map<? extends K, ? extends V>, Integer> {
public IsMapWithSize(Matcher<? super Integer> sizeMatcher) {
super(sizeMatcher, "a map with size", "map size");
}
#Override
protected Integer featureValueOf(Map<? extends K, ? extends V> actual) {
return actual.size();
}
/**
* Creates a matcher for {#link java.util.Map}s that matches when the
* <code>size()</code> method returns a value that satisfies the specified
* matcher.
* <p/>
* For example:
*
* <pre>
* Map<String, Integer> map = new HashMap<>();
* map.put("key", 1);
* assertThat(map, isMapWithSize(equalTo(1)));
* </pre>
*
* #param sizeMatcher
* a matcher for the size of an examined {#link java.util.Map}
*/
#Factory
public static <K, V> Matcher<Map<? extends K, ? extends V>> isMapWithSize(Matcher<? super Integer> sizeMatcher) {
return new IsMapWithSize<K, V>(sizeMatcher);
}
/**
* Creates a matcher for {#link java.util.Map}s that matches when the
* <code>size()</code> method returns a value equal to the specified
* <code>size</code>.
* <p/>
* For example:
*
* <pre>
* Map<String, Integer> map = new HashMap<>();
* map.put("key", 1);
* assertThat(map, isMapWithSize(1));
* </pre>
*
* #param size
* the expected size of an examined {#link java.util.Map}
*/
#Factory
public static <K, V> Matcher<Map<? extends K, ? extends V>> isMapWithSize(int size) {
Matcher<? super Integer> matcher = equalTo(size);
return IsMapWithSize.<K, V> isMapWithSize(matcher);
}
}
Testing:
Map<String, Integer> map = new HashMap<>();
map.put("key", 1);
assertThat(map, isMapWithSize(1));
assertThat(map, isMapWithSize(equalTo(1)));

You can check this using not and any
import static org.hamcrest.Matchers.any;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.not;
not(hasEntry(any(Object.class), any(Object.class)))

Related

Optimize insertion from ArrayList to HashMap

I'm trying to insert data from ArrayList to HashMap<String, Language> optimally.
Many items may have the same languge_name (code below), so I need to group items having the same language in Language class and store languages in a HashMap with the name of the language as a Key.
Item
String name;
String language_name;
Language
String language_name;
int numberItems;
LinkedList<String> Items;
I solved this as follows:
ArrayList<Item> items; // given array of items
HashMap<String, Language> languages = new HashMap<String, Language>();
items.forEach(item -> {
/** case 1: language isn't specified */
if (item.getLanguageName() == null) {
item.setLanguageName("unknown");
}
/** case 2: language already added */
if (languages.containsKey(item.getLanguageName())) {
languages.get(item.getLanguageName()).getItems().add(item.getName());
languages.get(item.getLanguageName())
.setNumberItems(languages.get(item.getLanguageName()).getNumberItems() + 1);
} else {
/** case 3: language isn't added yet */
LinkedList<String> languageItems = new LinkedList<String>();
languageItems.add(item.getName());
Language language = new Language(item.getLanguageName(), 1, languageItems);
languages.put(item.getLanguageName(), language);
}
});
Any help would be appreciated!
Assuming you're using Java 8 or later, this can be accomplished nicely with built-in stream functions.
HashMap<String, List<Items>> itemsGroupedByLanguage =
items.stream().collect(Collectors.groupingBy(Items::getLanguage));
tl;dr
It's not possible to achieve what you desire using Java (8+) inbuilt collector, but you can write your own custom collector and write code like below to collect into a map as -
Map<String, Language> languages = items.stream().collect(LanguageCollector.toLanguage());
Let's first look at Collector<T, A, R> interface
public interface Collector<T, A, R> {
/**
* A function that creates and returns a new mutable result container.
*/
Supplier<A> supplier();
/**
* A function that folds a value into a mutable result container.
*/
BiConsumer<A, T> accumulator();
/**
* A function that accepts two partial results and merges them. The
* combiner function may fold state from one argument into the other and
* return that, or may return a new result container.
*/
BinaryOperator<A> combiner();
/**
* Perform the final transformation from the intermediate accumulation type
*/
Function<A, R> finisher();
/**
* Returns a Set of Collector.Characteristics indicating
* the characteristics of this Collector. This set should be immutable.
*/
Set<Characteristics> characteristics();
}
Where T is the generic type of the items in the stream to be collected.
A is the type of the accumulator, the object on which the partial result will be accumulated during the collection process.
R is the type of the object (typically, but not always, the collection) resulting
from the collect operation
Now let's look at the custom LanguageCollector
public class LanguageCollector
implements Collector<Item, Map<String, Language>, Map<String, Language>> {
/**
* The supplier method has to return a Supplier of an empty accumulator - a parameterless
* function that when invoked creates an instance of an empty accumulator used during the
* collection process.
*/
#Override
public Supplier<Map<String, Language>> supplier() {
return HashMap::new;
}
/**
* The accumulator method returns the function that performs the reduction operation. When
* traversing the nth element in the stream, this function is applied with two arguments, the
* accumulator being the result of the reduction (after having collected the first n–1 items of
* the stream) and the nth element itself. The function returns void because the accumulator is
* modified in place, meaning that its internal state is changed by the function application to
* reflect the effect of the traversed element
*/
#Override
public BiConsumer<Map<String, Language>, Item> accumulator() {
return (map, item) -> {
if (item.getLanguageName() == null) {
item.setLanguageName("unknown");
} else if (map.containsKey(item.getLanguageName())) {
map.get(item.getLanguageName()).getItems().add(item.getName());
map.get(item.getLanguageName())
.setNumberItems(map.get(item.getLanguageName()).getNumberItems() + 1);
} else {
Language language = new Language(item.getLanguageName(), 1);
language.add(item.getName());
map.put(item.getLanguageName(), language);
}
};
}
/**
* The combiner method, return a function used by the reduction operation, defines how the
* accumulators resulting from the reduction of different subparts of the stream are combined
* when the subparts are processed in parallel
*/
#Override
public BinaryOperator<Map<String, Language>> combiner() {
return (map1, map2) -> {
map1.putAll(map2);
return map1;
};
}
/**
* The finisher() method needs to return a function which transforms the accumulator to the
* final result. In this case, the accumulator is the final result as well. Therefore it is
* possible to return the identity function
*/
#Override
public Function<Map<String, Language>, Map<String, Language>> finisher() {
return Function.identity();
}
/**
* The characteristics, returns an immutable set of Characteristics, defining the behavior of
* the collector—in particular providing hints about whether the stream can be reduced in
* parallel and which optimizations are valid when doing so
*/
#Override
public Set<Characteristics> characteristics() {
return Collections.unmodifiableSet(
EnumSet.of(Characteristics.IDENTITY_FINISH));
}
/**
* Static method to create LanguageCollector
*/
public static LanguageCollector toLanguage() {
return new LanguageCollector();
}
}
I have modified your classes at little bit to (to follow the naming convention and more for readable accumulator operation).
Class Item
public class Item {
private String name;
private String languageName;
public Item(String name, String languageName) {
this.name = name;
this.languageName = languageName;
}
//Getter and Setter
}
Class Language
public class Language {
private String languageName;
private int numberItems;
private LinkedList<String> items;
public Language(String languageName, int numberItems) {
this.languageName = languageName;
this.numberItems = numberItems;
items = new LinkedList<>();
}
public void add(String item) {
items.add(item);
}
// Getter and Setter
public String toString() {
return "Language(languageName=" + this.getLanguageName() + ", numberItems=" + this.getNumberItems() + ", items=" + this.getItems() + ")";
}
}
Running code
public static void main(String[] args) {
List<Item> items =
Arrays.asList(
new Item("ItemA", "Java"),
new Item("ItemB", "Python"),
new Item("ItemC", "Java"),
new Item("ItemD", "Ruby"),
new Item("ItemE", "Python"));
Map<String, Language> languages = items.stream().collect(LanguageCollector.toLanguage());
System.out.println(languages);
}
prints
{Java=Language(languageName=Java, numberItems=2, items=[ItemA, ItemC]), Ruby=Language(languageName=Ruby, numberItems=1, items=[ItemD]), Python=Language(languageName=Python, numberItems=2, items=[ItemB, ItemE])}
For more information please read book 'Modern Java in Action: Lambdas, streams, functional and reactive programming' chapter 6.5 or check this link

Java collection like c# KeyedColllection<TKey,TItem>

Is there a Java collection that has the same behavior as the c# abstract KeyedCollection class (that is items can be retrieved by both key and index)? I have looked around but can't find anything similar.
Thanks,
Nick
Here is a full implementation using a "KeyedItem" interface. I've included comments as best I could.
/**
* An interface that must be implemented by an item inserted into a KeyedItemHashMap.
*/
public interface KeyedItem {
/**
* Returns an ID for this item to be used in a KeyedItemHashMap.
* #return An ID for this item to be used in a KeyedItemHashMap.
*/
public String getId();
}
And then the implementation of the HashMap class...
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Hash table based implementation of the {#code Map} interface. This
* implementation provides all of the optional map operations, and permits
* {#code null} values and the {#code null} key. (The {#code HashMap}
* class is roughly equivalent to {#code Hashtable}, except that it is
* unsynchronized and permits nulls.) This class makes no guarantees as to
* the order of the map; in particular, it does not guarantee that the order
* will remain constant over time.
*
* Unlike a typical hash map, this implementation uses KeyedItem's as the
* value. A KeyedItem must implement the {#code KeyedItem} interface and
* provide a unique ID to avoid collisions within the map.
*
* For more details see the {#code HashMap} class.
*/
public final class KeyedItemHashMap implements Map<String,KeyedItem>{
private HashMap<String,KeyedItem> m_map;
/**
* Constructs an empty HashMap with the default initial capacity (16) and
* the default load factor (0.75).
*/
public KeyedItemHashMap() {
m_map = new HashMap<>();
}
/**
* Returns the number of key-value mappings in this map.
* #return The number of key-value mappings in this map.
*/
public int size() {
return m_map.size();
}
/**
* Returns {#code true} if this map contains no key-value mappings.
* #return {#code true} if this map contains no key-value mappings.
*/
public boolean isEmpty() {
return m_map.isEmpty();
}
/**
* Returns {#code true} if this map contains a mapping for the specified key.
* #param key The key whose presence in this map is to be tested.
* #return {#code true} if this map contains a mapping for the specified key.
*/
public boolean containsKey(Object key) {
return m_map.containsKey(key);
}
public boolean containsValue(Object keyedItem) {
return m_map.containsValue(keyedItem);
}
/**
* Returns the string representation of the {#code Object} argument.
*
* #param obj an {#code Object}.
* #return if the argument is {#code null}, then a string equal to
* {#code "null"}; otherwise, the value of
* {#code obj.toString()} is returned.
* #see java.lang.Object#toString()
*/
public KeyedItem get(Object obj) {
return m_map.get(String.valueOf(obj));
}
/**
* Associates the specified value with the keyedItem's ID in this map.
* If the map previously contained a mapping for the keyedItem's ID, the old
* value is replaced.
*
* #param key UNUSED here but necessary for override.
* #param keyedItem Value that implements the KeyedItem interface. The getId() function will
* be used to determine the key for the map.
* #return the previous value associated with {#code keyedItem.getId()}, or
* {#code null} if there was no mapping for {#code keyedItem.getId()}.
* (A {#code null} return can also indicate that the map
* previously associated {#code null} with {#code keyedItem.getId()}.)
*/
public KeyedItem put(String key, KeyedItem keyedItem) {
return m_map.put(keyedItem.getId(), keyedItem);
}
/**
* Associates the specified value with the keyedItem's ID in this map.
* If the map previously contained a mapping for the keyedItem's ID, the old
* value is replaced.
*
* #param keyedItem Value that implements the KeyedItem interface. The getId() function will
* be used to determine the key for the map.
* #return the previous value associated with {#code keyedItem.getId()}, or
* {#code null} if there was no mapping for {#code keyedItem.getId()}.
* (A {#code null} return can also indicate that the map
* previously associated {#code null} with {#code keyedItem.getId()}.)
*/
public KeyedItem put(KeyedItem keyedItem) {
return m_map.put(keyedItem.getId(), keyedItem);
}
/**
* Removes the mapping for the specified keyedItem's ID from this map if present.
*
* #param keyedItem KeyedItem whose mapping is to be removed from the map.
* #return the previous value associated with {#code keyedItem.getId()}, or
* {#code null} if there was no mapping for {#code keyedItem.getId()}.
* (A {#code null} return can also indicate that the map
* previously associated {#code null} with {#code keyedItem.getId()}.)
* #throws ClassCastException if the keyedItem does not implement the KeyedItem interface.
*/
public KeyedItem remove(Object keyedItem) {
return m_map.remove(((KeyedItem)keyedItem).getId());
}
/**
* Copies all of the mappings from the specified map to this map.
* These mappings will replace any mappings that this map had for
* any of the keys currently in the specified map.
*
* #param map mappings to be stored in this map
* #throws NullPointerException if the specified map is null
*/
public void putAll(Map<? extends String, ? extends KeyedItem> map) {
m_map.putAll(map);
}
/**
* Removes all of the mappings from this map.
* The map will be empty after this call returns.
*/
public void clear() {
m_map.clear();
}
/**
* Returns a {#link Set} view of the keys contained in this map.
* The set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa. If the map is modified
* while an iteration over the set is in progress (except through
* the iterator's own {#code remove} operation), the results of
* the iteration are undefined. The set supports element removal,
* which removes the corresponding mapping from the map, via the
* {#code Iterator.remove}, {#code Set.remove},
* {#code removeAll}, {#code retainAll}, and {#code clear}
* operations. It does not support the {#code add} or {#code addAll}
* operations.
*
* #return a set view of the keys contained in this map
*/
public Set<String> keySet() {
return m_map.keySet();
}
/**
* Returns a {#link Collection} view of the values contained in this map.
* The collection is backed by the map, so changes to the map are
* reflected in the collection, and vice-versa. If the map is
* modified while an iteration over the collection is in progress
* (except through the iterator's own {#code remove} operation),
* the results of the iteration are undefined. The collection
* supports element removal, which removes the corresponding
* mapping from the map, via the {#code Iterator.remove},
* {#code Collection.remove}, {#code removeAll},
* {#code retainAll} and {#code clear} operations. It does not
* support the {#code add} or {#code addAll} operations.
*
* #return a view of the values contained in this map
*/
public Collection<KeyedItem> values() {
return m_map.values();
}
/**
* Returns a {#link Set} view of the mappings contained in this map.
* The set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa. If the map is modified
* while an iteration over the set is in progress (except through
* the iterator's own {#code remove} operation, or through the
* {#code setValue} operation on a map entry returned by the
* iterator) the results of the iteration are undefined. The set
* supports element removal, which removes the corresponding
* mapping from the map, via the {#code Iterator.remove},
* {#code Set.remove}, {#code removeAll}, {#code retainAll} and
* {#code clear} operations. It does not support the
* {#code add} or {#code addAll} operations.
*
* #return a set view of the mappings contained in this map
*/
public Set<Entry<String, KeyedItem>> entrySet() {
return m_map.entrySet();
}
}
This should be flexible enough for you to just add the interface to any class you want to store.
You want to implement the map interface so that your new hashmap can be used in any capacity that a generic hashmap could be used, unfortunately this means you have a put function that takes in a key that isn't used. I've noted that in the comments.
Edit: fixed some syntax errors and included imports
I think you can develop Your own class by extending a HashMap
I think the closest thing I can think of to what you want is a treemap (http://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html), however you cannot get items by index only by key.
Given an Entity class:
#Data // lombok.Data, to have getters and setters
public class Entity {
private String myIndexingProperty;
// Other fields here
}
An attempt to implement something like the KeyedCollection<T> of C# is (Java 8+):
import com.my.application.model.Entity;
import java.util.*;
import java.util.stream.Collectors;
public final class EntityMap implements Map<String, Entity> {
private TreeSet<Entity> set;
public EntityMap() {
set = new TreeSet<>();
}
#Override
public int size() {
return set.size();
}
#Override
public boolean isEmpty() {
return set.isEmpty();
}
#Override
public boolean containsKey(Object o) {
return set.stream()
.anyMatch(e -> String.valueOf(o).equalsIgnoreCase(e.getMyIndexingProperty()));
}
#Override
public boolean containsValue(Object o) {
return set.stream()
.anyMatch(e -> String.valueOf(o).equalsIgnoreCase(e.getMyIndexingProperty()));
}
#Override
public Entity get(Object o) {
return set.stream()
.filter(e -> String.valueOf(o).equalsIgnoreCase(e.getMyIndexingProperty()))
.findFirst()
.orElse(null);
}
#Override
public Entity put(String s, Entity entity) {
set.add(entity);
return set.stream()
.filter(e -> String.valueOf(entity.getMyIndexingProperty()).equalsIgnoreCase(e.getMyIndexingProperty()))
.findFirst()
.orElse(null);
}
#Override
public Verb remove(Object o) {
boolean removed = set.removeIf(e -> e.equals(o));
if (!removed) {
return null;
}
return get(o);
}
#Override
public void putAll(Map<? extends String, ? extends Entity> map) {
map.forEach(this::put);
}
#Override
public void clear() {
set.clear();
}
#Override
public Set<String> keySet() {
return set.stream()
.map(Entity::getMyIndexingProperty)
.collect(Collectors.toSet());
}
#Override
public Collection<Entity> values() {
return set;
}
#Override
public Set<Entry<String, Entity>> entrySet() {
return set.stream()
.map(e -> new AbstractMap.SimpleEntry<>(e.getMyIndexingProperty(), e))
.collect(Collectors.toSet());
}
}

Java Concurrency

I'm trying to implement some kind of accumulation logic in a multi threaded environment; I’m wondering is there any better/faster way to do it without the lock and synchronized keyword? The following is my current code:
public class ConcurrentHashMapTest {
private static final int NB_THREADS = 1_000;
private final Map<String, Integer> cnts = new HashMap<>();
private static final Lock RWLOCK = new ReentrantLock(true);
private static final String[] NAMES = {
"A", "B"
};
public void testIt() {
ExecutorService executor =
Executors.newFixedThreadPool(NB_THREADS);
for (int i = 0; i < NB_THREADS; i++) {
Runnable task = new WorkerThread();
executor.submit(task);
}
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(cnts);
}
private void accumulate(String name) {
RWLOCK.lock();
try {
Integer cnt = cnts.get(name);
if (cnt == null) {
cnts.put(name, 1);
} else {
cnts.put(name, cnt + 1);
}
} finally {
RWLOCK.unlock();
}
}
private class WorkerThread implements Runnable {
#Override
public void run() {
accumulate(NAMES[ThreadLocalRandom.current().nextInt(0, NAMES.length)]);
}
}
}
Java 8:
private final Map<String, AtomicInteger> cnts =
new ConcurrentHashMap<>();
private void accumulate(String name) {
cnts.computeIfAbsent(name, k -> new AtomicInteger()).incrementAndGet();
}
The ConcurrentHashMap can be freely accessed from multiple threads. The computeIfAbsent method takes a lambda to evaluate to get a value for the key if the key is not present in the map, and adds it if and only if there is no such mapping, and then returns that value. It's effectively putIfAbsent followed by get. The value is a new AtomicInteger with the value 0. Whether there was an existing value, or whether a new one with value 0 was just added, in either case increment it.
Java 7:
private final ConcurrentMap<String, AtomicInteger> cnts =
new ConcurrentHashMap<>();
private void accumulate(String name) {
cnts.putIfAbsent(name, new AtomicInteger());
cnts.get(name).incrementAndGet();
}
For Java 7, there is no computeIfAbsent method, but that effectively just does a putIfAbsent followed by a get, so the same effect is achieved by calling those methods. There is no concern that the value already existed in the map; a new, zero AtomicInteger is added if and only if the map had no value for that key. Even if another thread got in there before us and added a zero, both threads would then see and increment that same AtomicInteger instance.
use a concurrent hash map with String and AtomicInteger. Both are thread safe and thus can be used freely.
I'd be wary of using fairness on your ReentrantLock in this case, as there's no benefit to your accumulator if longer waiting threads get access first. Take a look at Brian Goetz's 'Java Concurrency in Practice'
Why wouldn't we want to make all locks fair? After all, fairness is good and unfairness is bad, right? (It's not accidental that whenever kids want to appeal a decision, "that's not fair" almost certainly comes up. We think fairness is pretty important, and they know it.) In reality, the fairness guarantee for locks is a very strong one, and comes at a significant performance cost. The bookkeeping and synchronization required to ensure fairness mean that contended fair locks will have much lower throughput than unfair locks. As a default, you should set fair to false unless it is critical to the correctness of your algorithm that threads be serviced in exactly the order they queued up.
You could use a Map of name to AtomicInteger and use double-check locking when there is no counter in the map at all. Be aware that you need to use the volatile keyword for effective double-check locking.
This way you will only lock the whole map for actually adding brand new entries, the rest of the processing can happen in parallel.
You risk massively over-complicating your program here though and possibly even reducing performance in real-world cases. Is contention on this map really a performance bottle-neck?
According to Oracle Java 7 API : implementation of HashMap is not synchronized.
You can use Hashtable implementation or declare : private final Map<String, Integer> cnts = Collections.synchronizedMap(new HashMap<String, Integer>());
I think what you are looking for is a Multiton:
/**
* Holds a thread-safe map of unique create-once items.
*
* Contract:
*
* Only one object will be made for each key presented.
*
* Thread safe.
*
* #author OldCurmudgeon
* #param <K>
* #param <V>
*/
public class Multiton<K, V> {
// Map from the key to the futures of the items.
private final ConcurrentMap<K, Future<V>> multitons = new ConcurrentHashMap<>();
// The creator can create an item of type V.
private final Creator<K, V> creator;
public Multiton(Creator<K, V> creator) {
this.creator = creator;
}
/**
* There can be only one.
*
* Use a FutureTask to do the creation to ensure only one construction.
*
* #param key
* #return
* #throws InterruptedException
* #throws ExecutionException
*/
public V get(final K key) throws InterruptedException, ExecutionException {
// Already made?
Future<V> f = multitons.get(key);
if (f == null) {
// Plan the future but do not create as yet.
FutureTask<V> ft = new FutureTask<>(() -> creator.create(key));
// Store it.
f = multitons.putIfAbsent(key, ft);
if (f == null) {
// It was successfully stored - it is the first (and only)
f = ft;
// Make it happen.
ft.run();
}
}
// Wait for it to finish construction and return the constructed.
return f.get();
}
/**
* Returns a Map indicating the current state.
*
* #return a Map which should reflect the current state.
*
* #throws java.lang.InterruptedException
* #throws java.util.concurrent.ExecutionException
*/
public Map<K, V> getMap() throws InterruptedException, ExecutionException {
Map<K, V> map = new HashMap<>();
for (Map.Entry<K, Future<V>> e : multitons.entrySet()) {
map.put(e.getKey(), e.getValue().get());
}
return map;
}
/**
* User provides one of these to do the construction.
*
* #param <K>
* #param <V>
*/
public abstract static class Creator<K, V> {
// Return a new item under the key.
abstract V create(K key) throws ExecutionException;
}
}
Usage - for demonstration - adds up all integers up to 999, keying on their first digit:
Multiton<String, AtomicInteger> counts = new Multiton<>(
new Creator<String, AtomicInteger>() {
#Override
AtomicInteger create(String key) throws ExecutionException {
return new AtomicInteger();
}
}
);
public void test() throws InterruptedException, ExecutionException {
for (int i = 0; i < 1000; i++) {
counts.get(Integer.toString(i).substring(0, 1)).addAndGet(i);
}
System.out.println(counts.getMap());
}
Prints:
{0=0, 1=15096, 2=25197, 3=35298, 4=45399, 5=55500, 6=65601, 7=75702, 8=85803, 9=95904}
Java < 8 version:
/**
* Holds a thread-safe map of unique create-once items.
*
* Contract:
*
* Only one object will be made for each key presented.
*
* Thread safe.
*
* #author OldCurmudgeon
* #param <K>
* #param <V>
*/
public class Multiton<K, V> {
// Map from the key to the futures of the items.
private final ConcurrentMap<K, Future<V>> multitons = new ConcurrentHashMap<>();
// The creator can create an item of type V.
private final Creator<K, V> creator;
public Multiton(Creator<K, V> creator) {
this.creator = creator;
}
/**
* There can be only one.
*
* Use a FutureTask to do the creation to ensure only one construction.
*
* #param key
* #return
* #throws InterruptedException
* #throws ExecutionException
*/
public V get(final K key) throws InterruptedException, ExecutionException {
// Already made?
Future<V> f = multitons.get(key);
if (f == null) {
// Plan the future but do not create as yet.
FutureTask<V> ft = new FutureTask<>(new Callable<V>() {
#Override
public V call() throws Exception {
// Doing this inline may be a little contrived but it maintains the linkage with the Java-8 version.
return creator.create(key);
}
}
);
// Store it.
f = multitons.putIfAbsent(key, ft);
if (f == null) {
// It was successfully stored - it is the first (and only)
f = ft;
// Make it happen.
ft.run();
}
}
// Wait for it to finish construction and return the constructed.
return f.get();
}
/**
* Returns a Map indicating the current state.
*
* #return a Map which should reflect the current state.
*
* #throws java.lang.InterruptedException
* #throws java.util.concurrent.ExecutionException
*/
public Map<K, V> getMap() throws InterruptedException, ExecutionException {
Map<K, V> map = new HashMap<>();
for (Map.Entry<K, Future<V>> e : multitons.entrySet()) {
map.put(e.getKey(), e.getValue().get());
}
return map;
}
/**
* User provides one of these to do the construction.
*
* #param <K>
* #param <V>
*/
public abstract static class Creator<K, V> {
// Return a new item under the key.
abstract V create(K key) throws ExecutionException;
}
}

Dictionary-like data structure. Is this a good practice?

I need a data structure to store different type of objects.E.g. String, Boolean and other classes.
Is using a Map<String, Object> where using the key you get the according object which assumes that you know how to cast it a good practice?
Is there a better solution?
That's a perfect use case for a PropretyHolder I wrote a while ago. You can read in length about it on my blog. I developed it with immutability in mind, feel free to adapt it to your needs.
In general I'd say if you want to profit from type safety in Java you need to know your keys. What I mean by that - it will be hardly possible to develop type safe solution where keys come from external source.
Here's a special key that knows type of its value (it's not complete please download the source for complete version):
public class PropertyKey<T> {
private final Class<T> clazz;
private final String name;
public PropertyKey(Class<T> valueType, String name) {
this.clazz = valueType;
this.name = name;
}
public boolean checkType(Object value) {
if (null == value) {
return true;
}
return this.clazz.isAssignableFrom(value.getClass());
}
... rest of the class
}
Then you develop a data structure that utilizes it:
public class PropertyHolder {
private final ImmutableMap<PropertyKey<?>, ?> storage;
/**
* Returns value for the key of the type extending-the-one-declared-in-the {#link PropertyKey}.
*
* #param key {#link PropertyKey} instance.
* #return Value of the type declared in the key.
*/
#SuppressWarnings("unchecked")
public <T extends Serializable> T get(PropertyKey<T> key) {
return (T) storage.get(key);
}
/**
* Adds key/value pair to the state and returns new
* {#link PropertyHolder} with this state.
*
* #param key {#link PropertyKey} instance.
* #param value Value of type specified in {#link PropertyKey}.
* #return New {#link PropertyHolder} with updated state.
*/
public <T> PropertyHolder put(PropertyKey<T> key, T value) {
Preconditions.checkNotNull(key, "PropertyKey cannot be null");
Preconditions.checkNotNull(value, "Value for key %s is null",
key);
Preconditions.checkArgument(key.checkType(value),
"Property \"%s\" was given "
+ "value of a wrong type \"%s\"", key, value);
// Creates ImmutableMap.Builder with new key/value pair.
return new PropertyHolder(filterOutKey(key)
.put(key, value).build());
}
/**
* Returns {#link Builder} with all the elements from the state except for the given ket.
*
* #param key The key to remove.
* #return {#link Builder} for further processing.
*/
private <T> Builder<PropertyKey<? extends Serializable>, Serializable> filterOutKey(PropertyKey<T> key) {
Builder<PropertyKey<? extends Serializable>, Serializable> builder = ImmutableMap
.<PropertyKey<? extends Serializable>, Serializable> builder();
for (Entry<PropertyKey<? extends Serializable>, Serializable> entry : this.storage.entrySet()) {
if (!entry.getKey().equals(key)) {
builder.put(entry);
}
}
return builder;
}
... rest of the class
}
I omit here a lot of unnecessary details please let me know if something is not clear.
A typesafe heterogeneous container can be used for this purpose:
import java.util.HashMap;
import java.util.Map;
public class Container {
private Map<Class<?>, Object> container = new HashMap<Class<?>, Object>();
public <T> void putElement(Class<T> type, T instance) {
if (type == null) {
throw new NullPointerException("Type is null");
}
//container.put(type, instance); // 'v1'
container.put(type, type.cast(instance)); // 'v2' runtime type safety!
}
public <T> T getElement(Class<T> type) {
return type.cast(container.get(type));
}
public static void main(String[] args) {
Container myCont = new Container();
myCont.putElement(String.class, "aaa");
myCont.putElement(Boolean.class, true);
myCont.putElement(String[].class, new String[] {"one", "two"});
System.out.println(myCont.getElement(String.class));
System.out.println(myCont.getElement(String[].class)[1]);
}
}
Limitation: this container in its form is capable only to store one instance/object type.
In putElement() you can achieve runtime type safety by using a dynamic cast. This will hoewever add an extra overhead.
E.g: Try to pass a raw class object to the container. Note where the exception occurs:
Class raw = Class.forName("MyClass");
myCont.putElement(raw, "aaa"); //ClassCastException if using 'v2'
System.out.println(myCont.getElement(raw)); //ClassCastException if using 'v1'

Is there a best practice for writing maps literal style in Java?

In short, if you want to write a map of e.g. constants in Java, which in e.g. Python and Javascript you would write as a literal,
T<String,String> CONSTANTS =
{
"CONSTANT_NAME_0": CONSTANT_VALUE_0 ,
"CONSTANT_NAME_1": CONSTANT_VALUE_1 ,
"CONSTANT_NAME_2": CONSTANT_VALUE_2 ,
//...
} ;
is there a Class or any preset Object that you can use for writing a data structure like that?
I like to do it this way:
Map map = new HashMap() {{
put("foo", "bar");
put(123, 456);
}};
The double {{ }} are an instance initialization block. They are a bit unusual but they are useful. No need for libraries or helpers.
No, Java doesn't have a map literal. The closest you'll come to this is using Google Collections' ImmutableMap:
Map<K,V> CONSTANTS = ImmutableMap.of(
NAME_1, VALUE_1,
NAME_2, VALUE_2
//etc.
);
Constants? I'd use an enum.
public enum Constants {
NAME_1("Value1"),
NAME_2("Value2"),
NAME_3("Value3");
private String value;
Constants(String value) {
this.value = value;
}
public String value() {
return value;
}
}
Value for e.g. NAME_2 can be obtained as follows:
String name2value = Constants.NAME_2.value();
Only give the enum a bit more sensible name, e.g. Settings, Defaults, etc, whatever those name/value pairs actually represent.
Sorry, I'm a tinkerer :-) Here's a somewhat cleaner way.
public class MapTest {
private static Map<String, String> map;
static {
Map<String, String> tmpMap = new HashMap<String, String>();
tmpMap.put("A", "Apple");
tmpMap.put("B", "Banana");
// etc
map = Collections.unmodifiableMap(tmpMap);
}
public Map<String, String> getMap() {
return map;
}
}
You can write yourself a quick helper function:
#SuppressWarnings("unchecked")
public static <K,V> Map<K,V> ImmutableMap(Object... keyValPair){
Map<K,V> map = new HashMap<K,V>();
if(keyValPair.length % 2 != 0){
throw new IllegalArgumentException("Keys and values must be pairs.");
}
for(int i = 0; i < keyValPair.length; i += 2){
map.put((K) keyValPair[i], (V) keyValPair[i+1]);
}
return Collections.unmodifiableMap(map);
}
Note the code above isn't going to stop you from overwriting constants of the same name, using CONST_1 multiple places in your list will result in the final CONST_1's value appearing.
Usage is something like:
Map<String,Double> constants = ImmutableMap(
"CONST_0", 1.0,
"CONST_1", 2.0
);
Here's another way, best suited for maps that won't be changing:
public class Whatever {
private static Map<String,String> map = new HashMap<String,String>();
static {
map.put("A", "Apple");
map.put("B", "Banana");
// etc
}
}
Java7 suppose to implement following syntax:
Map<String, String> = {
"key1": "value",
"key2": "value",
"key3": "value",
"key4": "value"
};
However now you're forced to use solutions proposed by Jorn or Tony Ennis.
Ok, with Jorn's improvement I can't seem to change the map at all, internally or externally. Perhaps not quite as readable, but if you need the map to be unmodifiable I think this is better.
public class MapTest {
private static Map<String, String> map = initMap();
private static Map<String, String> initMap() {
Map<String, String> map = new HashMap<String, String>();
map.put("A", "Apple");
map.put("B", "Banana");
// etc
return Collections.unmodifiableMap(map);
}
public Map<String, String> getMap() {
return map;
}
public static void main(String[] args) {
MapTest m = new MapTest();
System.out.println(m.getMap().get("A"));
m.getMap().put("this", "that");
}
}
I like to do the declaration and initialization on the same line. I've used this handy little utility for so long it basically is my "map literal" and until they're done "right" in the languange, I'm gonna continue on using it like that :)
Happy to share it here.
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* A handy utility for creating and initializing Maps in a single statement.
* #author Jonathan Cobb. This source code is in the Public Domain.
*/
public class MapBuilder {
/**
* Most common create/init case. Usage:
*
* Map<String, Boolean> myPremadeMap = MapBuilder.build(new Object[][]{
* { "a", true }, { "b", false }, { "c", true }, { "d", true },
* { "e", "yes, still dangerous but at least it's not an anonymous class" }
* });
*
* If your keys and values are of the same type, it will even be typesafe:
* Map<String, String> someProperties = MapBuilder.build(new String[][]{
* {"propA", "valueA" }, { "propB", "valueB" }
* });
*
* #param values [x][2] array. items at [x][0] are keys and [x][1] are values.
* #return a LinkedHashMap (to preserve order of declaration) with the "values" mappings
*/
public static <K,V> Map<K,V> build(Object[][] values) {
return build(new LinkedHashMap<K,V>(), values);
}
/**
* Usage:
* Map<K,V> myMap = MapBuilder.build(new MyMapClass(options),
* new Object[][]{ {k,v}, {k,v}, ... });
* #param map add key/value pairs to this map
* #return the map passed in, now containing new "values" mappings
*/
public static <K,V> Map<K,V> build(Map<K,V> map, Object[][] values) {
for (Object[] value : values) {
map.put((K) value[0], (V) value[1]);
}
return map;
}
/** Same as above, for single-value maps */
public static <K,V> Map<K,V> build(Map<K,V> map, K key, V value) {
return build(map, new Object[][]{{key,value}});
}
/**
* Usage:
* Map<K,V> myMap = MapBuilder.build(MyMapClass.class, new Object[][]{ {k,v}, {k,v}, ... });
* #param mapClass a Class that implements Map
* #return the map passed in, now containing new "values" mappings
*/
public static <K,V> Map<K,V> build(Class<? extends Map<K,V>> mapClass, Object[][] values) {
final Map<K,V> map;
try { map = mapClass.newInstance(); } catch (Exception e) {
throw new IllegalStateException("Couldn't create new instance of class: "+mapClass.getName(), e);
}
return build(map, values);
}
/** Usage: Map<K,V> myMap = MapBuilder.build(key, value); */
public static <K,V> Map build(K key, V value) {
Map<K,V> map = new HashMap<>();
map.put(key, value);
return map;
}
}
Since Java 9, you can create unmodifiable maps out of the box -
Map<String, String> emptymap = Map.of();
Map<String, String> map = Map.of("key1", "val1");
there are variants supporting upto 10 keypairs.
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Map.html#of()
This is also supported https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Map.html#ofEntries(java.util.Map.Entry...)
import static java.util.Map.entry;
Map<Integer,String> map = Map.ofEntries(
entry(1, "a"),
entry(2, "b"),
entry(3, "c"),
...
entry(26, "z"));

Categories