Is there any way to declare hashMap or hashTable as static but not final?
I want to be able to update it and therefor I don't want it to be final..
If not, what other way can I create a static dictionary?
You can do this but most likely you don't need to make it non final.
When you make a reference final it is only that reference, not the object you reference to which cannot be changed.
e.g.
static final Map<String, String> map = ...
map.put("Hello", "world"); // is okay
map = new HashMap<>(); // not okay
BTW it is generally not good practice to have global/static collections. You should limit access to such a collection as much as possible and ensure it is thread safe unless you know this is not required. e.g. instead of making the collection public, you can do
private static final Map<String, String> map = ...
public static synchronized void put(String key, String value) {
map.put(key, value);
}
public static synchronized String get(String key) {
return map.get(key);
}
Related
I have this code that has a shared hash map initialized in static block. I don't expose the hashmap and it's used read-only (get and containKey).
I wanted to make sure if this is thread-safe.
public class MyClass {
private static final Map<String, MyObject> myMap;
static {
myMap = new MyLoader().load()
}
public MyClass() {
if (containsKey(someKey)) {
// do something
}
myMap.get(something)
}
static boolean containsKey(String key) {
// do some other stuff
return myMap.containsKey(key)
}
}
Assuming that new MyLoader().load() returns a map that is completely initialized with all data and which is never modified after that, then it is safe for all threads to retrieve data from this map concurrently. The Javadoc for HashMap says: "If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally." Therefore, if no thread is modifying the map, then it doesn't have to be synchronized.
As a safety measure, your load() method should enforce immutability:
public Map<String, MyObject> load() {
Map<String, MyObject> mymap = new HashMap<>();
mymap.put(...);
...
return Collections.unmodifiableMap(mymap);
}
This way, you don't have to worry that some thread in some code you're unfamiliar with might inadvertently modify the map. It won't be able to.
I have a piece of code below:
class Util {
private static final Map<String, String> MY_MAP;
static {
Map<String, String> tmpMap = new TreeMap<String, String>();
tmpMap.put("key1", "val1");
tmpMap.put("key2", "val2");
tmpMap.put("key3", "val3");
MY_MAP = Collections.unmodifiableMap(tmpMap);
}
public static String getVal(String key) {
return MY_MAP.get(key);
}
}
Can MY_MAP retain the tmpMap always? Or in other words, is it possible that the GC will recycle the tmpMap which makes the MY_MAP inaccessible?
The returned Map is just a "view" which wraps around the Map passed in.
So yes, tmpMap will be retained as long as MY_MAP is alive. Since MY_MAP is a static final field, tmpMap will be retained basically forever.
unmodifiableMap:
Returns an unmodifiable view of the specified map. [...] Query operations on the returned map "read through" to the specified map [...].
Or in other words, is it possible that the GC will recycle the tmpMap which makes the MY_MAP inaccessible?
No, never. MY_MAP has a (strong) reference to tmpMap, so it can't be collected.
In general, the GC will never do anything like this. You'll never see it working, except in special cases (WeakHashMap and similar).
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.
I want to do something like in this example. I can't figure out why it is not working.
myMap has no value in the main class. But if I put the value in the "putSomethingInTheMap" into the map it has the right value in the main class.
Can you give me a suggestion how to handle something like this?
public static void main(String[] args) {
Map<String, Integer> meineMap = new HashMap<>();
int wert = 1;
putSomethingInTheMap(meineMap, wert);
System.out.println(meineMap.get("A"));
}
private static void putSomethingInTheMap(Map<String, Integer> myMap, int value) {
myMap = insert(value);
}
private static Map<String, Integer> insert(int wert) {
Map<String, Integer> map = new HashMap<>();
map.put("A", wert);
return map;
}
private static void putSomethingInTheMap(Map<String, Integer> myMap, int value) {
myMap.put("A", wert);
}
Basically you are doing it method pass by refrence . In main class your creating a map and passing it to putSomethingInTheMap where it is assigned by the map returned by insert.
So if you have value in main class it is due to refrence passed to method.
Because meineMap reference is same as original. You declared a new reference with new value in insert method, and java method call is pass by value, but you are pass a reference that passed as value in parameter of putSomethingInTheMap!
private static Map<String, Integer> insert(int wert) {
Map<String, Integer> map = new HashMap<>();
map.put("A", wert);
return map;
}
This part is the mistake because what you are doing here is, for every insert operation in a map you are creating a new map ( that will be empty ofcourse) and adding a value in this map and returning this map.
Now
myMap = insert(value);
call will always get a map with only 1 value every time he makes an insert operation.
Fix:
You don't need to create a new map in insert( int wert ), you just need to call put() of java map. Code for solution is already posted by #Maurice Perry
For my Android app I've the need of defining some keys in a single constant, and I think the best way to do it is using a map. But not sure whether that's really the way to go, and how to do it correctly. As I'm targeting Android, a Bundle may also be an option.
I have a list of keys like:
"h" = "http"
"f" = "ftp"
Basically the program is to read a QR code (to keep that code from growing too big I'm using super-short keys), gets those keys, and has to translate them to something useful, in my case a protocol.
I'm trying to define a constant called KEY_PROTOCOLS, I think this should be a Map, so later I can call something like KEY_PROTOCOLS.get("f") to get the protocol that belongs to key "f".
Other classes should also be able to import this constant, and use it. So this map has to be populated in the class right away.
How can I do this?
If the constant is shared by several classes, and if you want to make sure this map is not cleared or modified by some code, you'd better make it unmodifiable :
public static final Map<String, String> KEY_PROTOCOLS;
static {
Map<String, String> map = new HashMap<String, String>();
map.put("f", "ftp");
// ...
KEY_PROTOCOLS = Collections.unmodifiableMap(map);
}
Something like this:
private static final Map<String, String> KEY_PROTOCOLS = new HashMap<String, String>();
static{
KEY_PROTOCOLS.put("f", "ftp");
// More
}
Static Initialisers:
http://www.glenmccl.com/tip_003.htm
This would work.
static Map<String, String> map = new HashMap<String, String>();
static {
map.add("ftp", "ftp");
...
}
On android:
#SuppressWarnings("unchecked")
Pair<String,String>[] pre_ips=new Pair[]{new Pair<String,String>("173.194", "0"), new Pair<String,String>("74.125", "96")};
String ip_1_2,ip_3;
for (Pair<String,String> pre_ip:pre_ips)
{ip_1_2=pre_ip.first;
ip_3=pre_ip.second;
}