Does code in methods always get executed? - java

I have created the implementation of a abstract method of the super class. Does the code in the method always get executed or is there some kind of cache that knows the code will never change?
I want to know if there are performance issues with my code. Is it better to create the map as a member variable and then return it in the method?
#Override
protected Map<String, Function<Information, String>> getDefinitionMap() {
final Map<String, Function<Information, String>> map = new LinkedHashMap<>();
map.put("Name", t -> t.getName());
map.put("ID", t -> t.getId());
return map;
}

Each time the method getDefinitionMap() is called, a new LinkedHashMap instance is created. There is no "implicit caching".
You can avoid that, if you create the map once, store it in a member variable and return this. You may want to make it unmodifiable so that it cannot be changed by callers. (see java.util.Collections.unmodifiableMap)

Related

Inconsistent responses when using ConcurrentHashMap in multi-threaded environment

We have a single thread that regularly updates a Map. And then we have multiple other threads that read this map.
This is how the update thread executes
private Map<String, SecondMap> firstMap = new ConcurrentHashMap<>();
private void refresh() //This method is called every X seconds by one thread only
{
List<SecondMap> newData = getLatestData();
final List<String> newEntries = new ArrayList<>();
for(SecondMap map : newData) {
newEntries.add(map.getName());
firstMap.put(map.getName(), map);
}
final Set<String> cachedEntries = firstMap.keySet();
for (final String cachedEntry : cachedEntries) {
if (!newEntries.contains(cachedEntry)) {
firstMap.remove(cachedEntry);
}
}
}
public Map<String, SecondMap> getFirstMap()//Other threads call this
{
return firstMap;
}
The SecondMap class looks like this
class SecondMap {
Map<String, SomeClass> data; //Not necessarily a concurrent hashmap
public Map<String, SomeClass> getData() {
return data;
}
}
Below is the simplified version of how reader threads access
public void getValue() {
Map<String, SecondMap> firstMap = getFirstMap();
SecondMap secondMap = firstMap.get("SomeKey");
secondMap.getData().get("AnotherKey");// This returns null
}
We are seeing that in other threads, when they iterate over the received
firstMap, sometimes they get null values for some keys in the SecondMap. We don't see any null values for keys in the firstMap, but we see null values for keys in second value. One thing that we can rule out is that the method getLatestData will never return such data. It reads from a database and returns these entries. There can never be null values in the database in the first place. Also we see that this happens occasionally. We are probably missing something here in handling multi-threaded situation in a proper way, but I am looking for an explanation why this can happen.
Assuming the Map<String, SomeClass> data; inside the SecondMap class is a HashMap, you can get a null value for a key in two scenarios.
1. If the key maps to a null value. Example "Something" -> null.
2. If the key is not in the map in the first place.
So without knowing much about where the data is coming from. If one of maps returned by getLatestData(); doesn't have the key "SomeKey" in the map at all, it will return null.
Also since there's not enough information about how that Map<String, SomeClass> data; is updated, and if it's mutable or immutable, you may have issues there. If that map is immutable and the SecondMap is immutable then it's more probably ok. But if you are modifying if from multiple threads you should make it a ConcurrentHashMap and if you update the reference to a new Map<String, SomeClass> data from different threads, inside the SecondMap you should also make that reference volatile.
class SecondMap {
volatile Map<String, SomeClass> data; //Not necessarily a concurrent hashmap
public Map<String, SomeClass> getData() {
return data;
}
}
If you'd like to understand in depth on when to use the volatile keyword and all the intricacies of data races, there's a section in this online course https://www.udemy.com/java-multithreading-concurrency-performance-optimization/?couponCode=CONCURRENCY
about it. I have not seen any resource that explains and demonstrates it better. And unfortunately there are so many articles online that just explain it WRONG, which is sad.
I hope from the little information in the question I was able to point you to some directions that might help. Please share more information if nothing of that works, or if something does work, please let me know, I'm curious to know what it was :)

Extend HashMap and LinkedHashMap at the Same Time?

I want to extend HashMap to add the method putIfGreaterThan which basically retrieves the value for a given key and if the new value is greater than the old value we update the old value with the new value. Like this:
public void putIfGreaterThan(String key, Double value )
{
if (containsKey(key ) != true) {
put( key , value );
} else {
if (get(key ) < value) {
System. out .println("Adding new value: " + value + " to map" );
put( key , value );
} else {
System. out .println("Did not add value: " + value + " to map" );
}
}
}
The program above works fine - however I would like to add this method to both HashMap and LinkedHashMap. In other words, if someone instantiates:
HashMap hashmap = new HashMap();
They should be able to access the method:
hashmap.putIfGreaterThan();
And if someone instantiates:
LinkedHashMap linkedhashmap = new LinkedHashMap();
They should be able to access the method:
linkedhashmap .putIfGreaterThan();
If I create a new class as follows:
MyHashMap extends HashMap<String, Double> and add the previously mentioned method - I am only extending HashMap not LinkedHashMap. This would not allow me to access the method if I instantiate a LinkedHashMap.
I was thinking of modifying the source code in the original HashMap class (by adding the method putIfGreaterThan) however I am unable to modify the source code unless I de-compile the entire class (and when I try doing this I get a bunch of other errors so I figured it would be easier just to extend the HashMap class but doing this means I cannot use the method putIfGreaterThan on both HashMap and LinkedHashMap).
Further, if I had added the method to the original class one would be able to call this method on any HashMap (even if the map contains two Strings) but the method is only applicable on a HashMap that contains String and Double or String and Int. Hence, I think it makes more sense to extend the original class and customize the current class with methods related to a HashMap of String and Double.
Any suggestions?
Thanks
Let your custom map implement the Map interface instead and wrap a concrete map with it that is provided by the user of the class via the constructor:
public class MyMap implements Map<String, Double>{
private final Map<String, Double> map;
public MyMap(Map<String, Double> map){
this.map = map;
}
public void putIfGreaterThan(String key, Double value ){...}
#Override
public int size() {
return map.size();
}
//inherited methods
}
This class can be used like this:
MyMap map = new MyMap(new LinkedHashMap<>());
or:
MyMap map = new MyMap(new HashMap<>());
Java don't support multi inheritance, but you can be done using Interfaces.
Java Multiple Inheritance
You cannot add your method to the existing HashMap or LinkedHashMap class.
Only way is to create a custom class MyHashMap<K,V> which implements the Map interface and put your logic there and compose that class with HashMap and(or) LinkedHashMap and let your clients operate on MyHashMap.

How to pass in initialized HashMap as param?

How can I pass in a new HashMap in the most canonical (simplest, shortest hand) form?
// 1. ? (of course this doesn't work)
passMyHashMap(new HashMap<String, String>().put("key", "val"));
// 2. ? (of course this doesn't work)
passMyHashMap(new HashMap<String, String>(){"key", "val"});
void passMyHashMap(HashMap<?, ?> hm) {
// do stuff witih my hashMap
}
Create it, initialize it, then pass it:
Map<String,String> myMap = new HashMap<String,String>();
myMap.put("key", "val");
passMyHashMap(myMap);
You could use the "double curly" style that David Wallace mentions in a comment, I suppose:
passMyHashMap(new HashMap<String,String>(){{
put("x", "y");
put("a", "b");
}});
This essentially derives a new class from HashMap and sets up values in the initializer block. I don't particularly care for it (hence originally not mentioning it), but it doesn't really cause any problems per se, it's more of a style preference (it does spit out an extra .class file, although in most cases that's not a big deal). You could compress it all to one line if you'd like, but readability will suffer.
You can't call put and pass the HashMap into the method at the same time, because the put method doesn't return the HashMap. It returns the old value from the old mapping, if it existed.
You must create the map, populate it separately, then pass it in. It's more readable that way anyway.
HashMap<String, String> map = new HashMap<>();
map.put("key", "val");
passMyHashMap(map);
HashMap< K,V>.put
public **V** put(K key,V value)
Associates the specified value with the specified key in this map. If
the map previously contained a mapping for the key, the old value is
replaced.
Returns the previous value associated with key, or null if there was
no mapping for key. (A null return can also indicate that the map
previously associated null with key.)
As you can see, it does not return the type HashMap<?, ?>
You can't do that. What you can do is create a factory that allow you to do so.
public class MapFactory{
public static Map<String, String> put(final Map<String, String> map, final String key, final String valeu){
map.put(key, value);
return map;
}
}
passMyHashMap(MapFactory.put(new HashMap<String, String>(),"key", "value"));
Although I can't image a approach that would need such implementation, also I kinda don't like it. I would recommend you to create your map, pass the values and just then send to your method.
Map<String, String> map = new HashMap<String, String>();
map.put("key","value");
passMyHashMap(map);

Converting ConcurrentHashMap to HashMap

Is it possible to convert ConcurrentHashMap to HashMap in java ?
This is my sample program where i was converting from ConcurrentHashMap to HashMap but i was getting the following exception:
Exception in thread "main" java.lang.ClassCastException:
java.util.concurrent.ConcurrentHashMap cannot be cast to java.util.HashMap
at com.Hi.main(Hi.java:18)
My code:
package com;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class Hi {
public static void main(String args[]) {
Map<String, String> conpage = new ConcurrentHashMap<String, String>();
conpage.put("1", "A");
conpage.put("2", "B");
conpage.put("3", "C");
HashMap hm = (HashMap) conpage;
System.out.println(hm.get("1"));
}
}
Map<String, String> hashMap = new HashMap<String, String>(conpage);
A ConcurrentMap (like ConcurrentHashMap) has no relationship with any AbstractMap, such has HashMap, so the solution is to create a new HashMap adding all values from ConcurrentHashMap during object creation.
Hope this helps.
A ConcurrentHashMap is not a HashMap , so you cannot perform this cast. Treat them as Map regardless of implementation.
Nevertheless , you can use Map#putAll() .
Suggested Reading:
Java - HashMap vs Map objects
What does it mean to “program to an interface”?
Use putAll() method istead of type casting like this:
HashMap hm=new HashMap<String, String>();
hm.putAll(conpage);
ConcurrentHashMap and HashMap are siblings and not Parent-Child related. Hence the cast fails.
To be more explicit in the explanation of the previous comments: consider you have three classes :
class Position {
}
class One extends Position {
String gold = "the best";
}
class Two extends Position {
String silver = "just wait next year!";
}
You cannot do the following cast (note that a cast is not a conversion: it's only a redeclaration of the type)
void showPosition() {
Position one = new One(); // this is regular since One extends Position
Two two = (Two)one; // this is impossible because one is not a two
}
If ever this cast was possible, how would you like the compiler to handle the following promblem? : there is no field called silver in one: so calling
((Two)one).silver
is impossible: returning null would be unsafe, since you wouldn't understand what's happening : since you know that the field 'silver' is initialized to the value "just wait next year!"
Java being a safe language, it doesn't allow this type of errors (actually it's a help from Java that it throws the exception since you think the type is something else that is it is).
The behvior you expect is rather a behavior proper to scripts.
A ConcurrentHashMap is still a Map. So you can create a new TreeMap like this:
ConcurrentHashMap myMap;
...
TreeMap myTreeMap = new TreeMap( myMap );
You can do so in the following way -
HashMap<String, String> map = new HashMap<String, String>(conpage);
JavaDoc.
Typically each concrete type in the Java Collection API (like HashMap, ArrayList etc.) has a constructor which takes a reference of its parent (like Map, List) and constructs a new object from it.
About the exception you are getting, it's because ConcurrentHashMap is not a subtype/supertype of HashMap, thus you are getting a ClassCastException. However, this would have worked fine -
Map<String, String> hm = (Map<String, String> ) conpage;
Actually There is no inheritance relation between HashMap and ConcurrentHashMap that's why while casting the concurrenthashmap object to hashmap its giving the ClassCastException.

passing a map into another method to be modified in java

So I came across some code that I thought looked kind of strange. Wanted to see what some of your opinions are of this
public class Test {
public static void main(String[] args) {
HashMap m = new HashMap();
Test2 t2 = new Test2();
t2.fill(m);
}
}
public class Test2 {
public void fill(HashMap m) {
m.put(new Integer(0), new Integer(0));
}
}
So is this code OK or should it be done another way?
Thanks
This is perfectly fine since objects in java are passed by reference. If you try to assign to m directly within a method, it is wrong:
m = new HashMap();
But you can use the passed reference to modify the object passed as an argument as is the case with your sample code.
Think of it as passing the location of the object into the function. You can use this location information to fiddle with it. But since the location is just a value, assigning to the location (m) does not have an effect on m from where you call the function. That's why the article says the argument is passed by value.
Is it OK to pass a map to a method for that method to manipulate the map? Sure.
The map is untyped; should be Map<Integer,Integer>. Use the compiler to help you get things right. Using generic types will also allow auto-boxing to be used so you can do the more succinct put(0,0).
The map should be passed as a Map, not a HashMap unless HashMap is explicitly needed (which for the case of HashMap is not going to be the case). As much as possible, use the interface, not the implementation.
The name fill looks like it's a bad name to me - it doesn't seem to "fill" anything.
As an aside, I would recommend against the magic anonymous class initialize, done so:
Map<Integer, Integer> m = new HashMap<Integer, Integer>() {{
put(0, 0);
}};
in favor of a simple initializer block:
Map<Integer, Integer> m = new HashMap<Integer, Integer>(); {
m.put(0, 0);
}
which avoids creating a redundant anonymous inner class file of the form SomeClass$n.class.
I would do this:
Map<Integer, Integer> m = new HashMap<Integer, Integer>() {{
put(0, 0);
}};
Here's a breakdown of the java kung fu being used here:
The map is typed <Integer, Integer>
This is an anonymous class with an instance block to initialize the map
Note the use of put(0, 0) rather than m.put(new Integer(0), new Integer(0)), making use of auto-boxing

Categories

Resources