Is Collections.unmodifiableMap performance critical? - java

I have a hashmap<String, String> which contains around one thousand entries.
Now I have to expose it in such way that it cannot be modified outside class. So I wrote like
public static Map<String, String> getResponseCodeSource()
{
return Collections.unmodifiableMap(codeMsgMap);
}
This method is called very frequently. My questions are 1. Will this cause performance issue? 2.Is method (unmodifiableMap) iterating over Map or this will perform its activity in O(constant) complexity ?

It's a very thin implementation:
public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) {
return new UnmodifiableMap<>(m);
}
and constructor code:
UnmodifiableMap(Map<? extends K, ? extends V> m) {
if (m==null)
throw new NullPointerException();
this.m = m;
}
So as you see complexity is O(1).

The Map returned from Collections.unmodifiableMap(Map) will be a thin proxy to the real underlying map with some methods disabled (put etc.). There is no reason to expect it to take a copy of the underlying map.
Returns: an unmodifiable view of the specified map.
Remember however that the unmodifiable map is only a view of the underlying map so changes in the underlying map will be reflected in the unmodifiable one. It would therefore be safe to do:
static final Map<String,String> codeMsgMap = new HashMap<>();
// Changes in the above map will be reflected here.
static final Map<String,String> unmodifiableCodeMsgMap = Collections.unmodifiableMap(codeMsgMap);
public static Map<String, String> getResponseCodeSource() {
return unmodifiableCodeMsgMap;
}
On the complexity question Sergey Pauk covers that nicely.

Related

A collection/Data Structure which prevents deletion and allows insertion and read only functionality

I want your help for creating a data structure/ Collection which supports read and insert functionality and prevents deletion/removal of records.
One way i could think of is , to create a customized collection ( like myHashMap ) and override all the delete/remove methods and thus prevent removal/deletion of records? But this approach will not work if the Object is having removal method as Final.
Please suggest any better way ..!!!!
You can create your own arraylist by overriding the methods like remove() with unsupported operation exception. If you want you can also declare arraylist like this.
ArrayList<String> myList = new ArrayList<String>() {
#Override
public boolean remove(String str) {
//If you want, you can throw Unsupported operation exception also.
return false;
}
};
There may be some other good approaches, you can check answers from others also.
You can create your Map wrapper and provide only the methods you want to :
class MyHashMap<K, V> {
Map<K, V> map;
public MyHashMap(Map<K, V> map) {
this.map = map;
}
public V put(K key, V value) {
return map.put(key, value);
}
public V get(K key) {
return map.get(key);
}
// other methods you want
}
example:
MyHashMap<String, String> myMap = new MyHashMap<>(new HashMap<>());

Java HashMap in methods

Is it possible to have a method requiring a HashMap and be able to provide any HashMap with Strings as keys? Some kind of generic data Type to put instead of 'Value'?
public void example(HashMap<String, Value> hashMap) {
//Stuff
}
example(new HashMap<String, Integer>);
HashMap<String, String> exampleMap = new HashMap<>();
example(exampleMap);
Alternatively, is it possible to check the key/value type of the map, other than looping through all the keys/value and check instanceof (without stopping it with return)?
public Boolean example(HashMap<String, Value> hashMap) {
for (Value value : hashMap.values())) {
if (value instanceof String) {
return true; //<- Unwanted
}
}
}
EDIT:
Let me explain my problem a bit further. I have a method:
public static Object getEIC(HashMap<String, Object> map, String key) {
for (String keys : map.keySet()) {
if (keys.equalsIgnoreCase(key)) {
return map.get(keys);
}
}
return null;
}
EIC stands for equalsIgnoreCase. So I need some generic return Type as well. Thanks for the answers so far, and thanks on forehand for the answers on this!
You could do:
HashMap<String, Object>
But that's terrible though because then you end up doing instanceof all the time. What you really need to do is understand what the key problem is and then think of inheritance. Can you define an interface that all your value objects would implement? For instance GeometricShape which could be implemented by Rectangle and Circle.
Also, you can define a HashMap as follows:
HashMap<String, ? extends SomeClass>
And as others pointed out, it's best to use the interface Map rather than a specific implementation e.g. HashMap.
Lastly, as I pointed out in a comment, it seems you are just trying to implement a Map<key, value> where you want to have case-insensitive keys. If so have a look at www.stackoverflow.com/questions/8236945/
The answer is to use a CaseInsensitiveMap. Thanks, everyone, for helping me and especially David Brossard for suggesting this.
You can implement the static method you are looking for using generics:
public static <V> V getEIC(Map<String, V> map, String key) {
for (String k : map.keySet()) {
if (k.equalsIgnoreCase(key)) {
return map.get(key);
}
}
return null;
}
however, you may wish to consider an enhanced Map Is there a good way to have a Map<String, ?> get and put ignoring case?
Note, however, that there is a subtle difference between this solution and using case-less equals - an ordinary Map<String,V> could hold a value for "Key" and "key" while a case-less Map would not. This method would arbitrarily choose one of them while a case-less Map would choose the most recent addition.
Yes, but requiring Map<String, Value> is better. If you don't care what value is ask for Map<String, ?>. If you do but don't yet know what it will be, use Map<String, ? extends T>
Requiring HashMap is programing to an implementation rather than an interface. There is rarely a good reason to do that.
And no. If you don't trust whoever built the map and want to be sure the map contains only the types it's supposed to contain you have to loop and check each one. However, you can abstract that away in a method that will check for you so you don't have to look at it.
public class CheckedCast
{
public static <K,V> Map<K,V> mapOf(Class<? extends K> classK,
Class<? extends V> classV,
Map<?,?> m)
{
for (Map.Entry<?, ?> e: m.entrySet())
{
classK.cast( e.getKey() );
classV.cast( e.getValue() );
}
#SuppressWarnings("unchecked")
Map<K,V> result = (Map<K,V>) m;
return result;
}
}

Java: Stacked (layered) maps behind a Map interface?

I need a Map impl which would consist of stacked maps, which I could push() and pop(), and the values would be "added" or "removed" if they belong to the map being pushed/popped. And the values would be searched top/bottom (or optionally bottom/top).
Is there an existing impl in JDK or elsewhere?
Example:
Stack
map4
foo => aaa
bar => 45
map3
bar => 22
map2
foo => ccc
baz => uuu
map1
For this, get("baz") would return "uuu", get("foo") would return "aaa", size() would return 3 etc.
It's something like JavaScript's prototypal inheritance.
There's one impl
I'm wishing for some more sophisticated impl, which wouldn't really go through all layers every time I call any method. Read methods are going to be more often than push()/pop(), so there could be some pre-computation during that.
You can have Stack as a wrapper. Have a Map<'String, Map> ( String here is for the name of the map). Expose push and pop as API. Interesting part of your question is, defining push and pop? How would the signature of these method actually look like? Actually, not very clear is to what you are trying to achieve?
So, there is no such builtin structure in the JDK, but it can be implemented using a LinkedList containing Maps.
LinkedList implements all three of List, Queue and Deque, maybe it's a little overkill, but ohwell...
A sample code would be as follows; however, the Map interface is not really obeyed (curious how you'd do .equals() and .hashCode() here? Not even talking about .clear()):
public final class StackedMap<K, V>
implements Map<K, V>
{
private final Map<K, V> NO_MAP = new HashMap<K, V>();
private final LinkedList<Map<K, V>> maps = new LinkedList<>();
private Map<K, V> currentMap = NO_MAP;
public void push(Map<K, V> map)
{
maps.push(map);
currentMap = map;
}
public Map<K, V> pop()
{
return currentMap = maps.pop();
}
#Override
public V get(K key)
{
V ret;
for (final Map<K, V> map: maps)
if ((ret = map.get(key)) != null)
break;
return ret;
}
// etc
}
Untested etc.

How to get class with generics types in Java

I am trying to make a method call like this,
public class GenericsTest<T> {
public static <T> Map<String, T> createMap(Class<? extends Map<String, T>> clazz) {
return null;
}
public static void main(String[] argv) {
Map<String, Integer> result = createMap(TreeMap.class);
}
}
But I am getting this error,
<T>createMap(java.lang.Class<? extends java.util.Map<java.lang.String,T>>) in test.GenericsTest<T> cannot be applied to (java.lang.Class<java.util.TreeMap>)
How to fix this problem?
Map<String, Integer> instance = new TreeMap<String, Integer>();
#SuppressWarnings("unchecked")
Map<String, Integer> map =
createMap((Class<? extends Map<String, Integer>>)instance.getClass());
map.put("x", 1);
System.out.println("THIS IS x: " + map.get("x"));
This will appropriately print out 1. The implementation of the method is most likely
try
{
return clazz.newInstance();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
A better implementation of their API would be for them to ask you for the type, T, and for them to give back a Map of their choosing instead of asking you for all of the details. Otherwise, as long as they are not filling in the Map with any data, you can instantiate a Map with the generic type argument yourself like so:
public static <T> Map<String, T> getMap()
{
return new TreeMap<String, T>();
}
You can then access that without a warning:
// note the lack of type arguments, which are inferred
Map<String, Integer> instance = getMap();
// alternatively, you could do it more explicitly:
// Map<String, Integer> instance = ClassName.<Integer>getMap();
There's really no reason for them to ask you for the Class type of your Map except to give you back an exact match to the implementation (e.g., if you stick in a HashMap, then you will get back a HashMap, and if you stick in a TreeMap, then you will get back a TreeMap). However, I suspect that the TreeMap will lose any Comparator that it was constructed with, and since that is an immutable (final) field of TreeMap, then you cannot fix that; that means that the Map is not the same in that case, nor is it likely to be what you want.
If they are filling in the Map with data, then it makes even less sense. You could always pass in an instance of a Map to fill, or have them return a Map that you can simply wrap (e.g., new TreeMap<String, Integer>(instance);), and they should know which Map offers the most utility to the data.

Using 'or' in Java Generics declaration

I have a method that returns an instance of
Map<String, List<Foo>> x();
and another method that returns an instance of
Map<String, Collection<Foo>> y();
Now if I want to dynamically add one of this Maps in my field, how can I write the generics for it to work?
ie:
public class Bar {
private Map<String, ? extends Collection<Foo>> myMap;
public void initializer() {
if(notImportant) myMap = x(); //OK
else myMap = y(); // !OK (Need cast to (Map<String, ? extends Collection<Foo>>)
}
}
Now is it ok that I cast to the signature even though the y() is declared as being Collection?
If it is not ok to cast, can I somehow write this (Collection OR List)
I mean, List is a Collection, so it should somehow be possible.
private Map<String, Collection<Foo> | List<Foo>>> myMap;
The way you did it with ? extends Collection is fine. You can't have something like OR since if you did you wouldn't know what it is you're getting back if you do myMap.get("someString"); you can't do List|Collection someVariable = myMap.get("someString"), you have to choose one, and if you choose Collection it's the same as using ? extends, if you choose List, you'll end up in all sort of trouble if the object in the map is actually a Set (which is also a collection), not a list, and you try calling methods that only List has (like indexOf). As for the reason you need to use ? extends is because Map<String, List> does not extend Map<String, Collection> even though List extends Collection.
You should take note though, that using ? extends Collection will only let you get values from the map, since then it's sure that what you get is a Collection (or child of Collection), but if you try to put something in the map, you won't be able to (since myMap may be Map<String, Set>, but since you only see it as Map<String, ? extends Collection> you might try to put a List in it which wouldn't be ok)
I'm not sure what your problem is. This code (essentially your code) compiles just fine.
import java.util.*;
public class Generic {
static class Foo {};
static Map<String, List<Foo>> x() {
return null;
}
static Map<String, Collection<Foo>> y() {
return null;
}
static Map<String, ? extends Collection<Foo>> myMap;
public static void main(String[] args) {
myMap = x();
myMap = y();
myMap = new HashMap<String,SortedSet<Foo>>();
for (Collection<Foo> value : myMap.values());
}
}
You can NOT, however, do something like List<Integer|String>. Java generics type bounds just doesn't work like that.

Categories

Resources