Which is better implementation? <id, <xid, object>> or <id, object> - java

I am trying to store 3 values. The last value is an object which can be accessed by XID. The main ID can be used to get the object.
I can think of two ways to implement this. Which would be a better approach? Also, which is better in terms of thread-safe and faster lookups?
Create a class and add it to the HashMap.
public class TestMap {
private int xid;
private XObject xobject;
public TestMap(int xid, XObject xobject) {
this.xid = xid;
this.object = object;
}
public int getXid() { return xid; }
public XObject getXOBject { return xobject; }
}
map.put(ID, new TestMap(xid, xobject));
Create a nested HashMap
HashMap<id, HashMap<xid, XObject>> map = new HashMap<>();
map.put(id, new HashMap() {{ put(xid, xobject); }} );

When you access it by the main ID, do you first need to specify the XID?
I'm assuming that you do not. In this case, I would make two Maps.
One is a Map<id,object> which you use when looking up by id. The second is a Map<xid,object> which you use when looking up by xid.

Related

How do i add individual values to list within a hashmap?

I've looked at so many examples but can't quite grasp this.
I need to create a method that inserts new values into already populated lists within my hashmap. I can't for the life of me figure out how to do. Can anyone help as well as explain how it works?
I've already created methods that populate the maps etc. I just can't figure out how to create a method that inserts just values for particular keys.
import java.util.*;
public class Singles
{
// instance variables - replace the example below with your own
private Map<String, List<String>> interests;
/**
* Constructor for objects of class Singles
*/
public Singles()
{
// initialise instance variables
super();
this.interests = new HashMap<>();
}
}
This is a multi-map.
public class MultiMap {
private Map<String, List<String>> multiMap = new HashMap<>();
public void put(String key, String value) {
List<String> values = (this.multiMap.containsKey(key) ? this.multiMap.get(key) : new ArrayList<>());
values.add(value);
this.multiMap.put(key, values);
}
}

Java Methods Container

I'm trying to implement an action/reaction system in Java.
For that, I need to have all my methods stock in a container so I can easily call the response I need with the return of the action I want.
Being a C ++ developer and new to Java my first intuition was to create an array of function pointers (or at least reproduce it) so I tried to used anonymous subclasses. But didn't get the result I was looking for.
So I tried with lambdas, here is a sample of what I'm trying to do.
public class Test {
public Map<Integer, Vector<String>> actions = new HashMap<>();
public Map<Integer, Integer> responses = new HashMap<>();
public Test() {
Vector<String> v= new Vector<String>();
actions.put(0, action0());
actions.put(1, action1());
responses.put(0, response0(Vector<String>)); // How can I leave aside this argument which I don't know at this point ?
responses.put(1, response1(Vector<String>));
}
public Vector<String> action0() {...}
public Vector<String> action1() {...}
// This methods takes actions return as argument
public Integer response0 (Vector<String>) {...}
public Integer response1 (Vector<String>) {...}
public void run() {
// When I run, I want to be able to launch any of my responses with any of my actions return
responses.get(0)
}
}
Am I at least trying a good way to solve this problem ?
Thanks a lot
Your code has a few flaws, so I'll assume that getHashtag() and action1() were supposed to be the same, and similar for the other three.
Also, I'll assume that the second responses.put() should have been key 1, not 0. Also, the parameter to your responseX() methods need a name.
Anyway, you need a functional interface, so you can give the responseX() methods as Method References.
In your case, the responseX() methods take a Vector<String> as parameter, and returns an Integer, so the functional interface would be Function<Vector<String>, Integer>.
You can then build a map of those methods, to be executed later.
public Test() {
// Here we can build map of response methods first, if we like, even though Vectors don't exist yet
Map<Integer, Function<Vector<String>, Integer>> responseMethods = new HashMap<>();
responseMethods.put(0, this::response0);
responseMethods.put(1, this::response1);
// Now we build the action map of Vectors
Map<Integer, Vector<String>> actions = new HashMap<>();
actions.put(0, action0());
actions.put(1, action1());
// At this time, we can now execute the referenced methods to get the actual responses
Map<Integer, Integer> responses = new HashMap<>();
for (Integer key : actions.keySet()) {
Vector<String> v = actions.get(key);
Function<Vector<String>, Integer> responseMethod = responseMethods.get(key);
Integer response = responseMethod.apply(v);
responses.put(key, response);
}
}
public Vector<String> action0() {...}
public Vector<String> action1() {...}
public Integer response0(Vector<String> v) {...}
public Integer response1(Vector<String> v) {...}
You can even defer the execution of the action methods if you want:
public Test() {
// Here we can build map of response methods first, if we like, even though Vectors don't exist yet
Map<Integer, Function<Vector<String>, Integer>> responseMethods = new HashMap<>();
responseMethods.put(0, this::response0);
responseMethods.put(1, this::response1);
// Now we build the action map of Vectors
Map<Integer, Supplier<Vector<String>>> actionMethods = new HashMap<>();
actionMethods.put(0, this::action0);
actionMethods.put(1, this::action1);
// At this time, we can now execute the referenced methods to get the actual responses
Map<Integer, Integer> responses = new HashMap<>();
for (Integer key : actionMethods.keySet()) {
Supplier<Vector<String>> actionMethod = actionMethods.get(key);
Function<Vector<String>, Integer> responseMethod = responseMethods.get(key);
Vector<String> v = actionMethod.get();
Integer response = responseMethod.apply(v);
responses.put(key, response);
}
}

Create an Object instance from a Map

I have a map with keys and string values.
This Map has been built reading a resource bundle where the data is organised in the following way:
height=160
weight=80
name=bob
And I have a class Person which has the fields: height, weight and name.
class Person{
int height;
int weight;
String name;
//..getter and setter..
}
I would like to create an instance of the class Person from the Map: height:160, weight:80, name:bob
The best would be a generic solution, or something that uses some utilities.
Do you have any idea? how can I do that in Java? or using the framework Spring?
Have a look at the Spring BeanWrapper interface and its implementations if you'd like to use something from Spring. You can use it to wrap your bean and dynamically populate your bean from a map like this:
Map<String, String> properties = new HashMap<>();
properties.put("height", "160");
properties.put("weight", "80");
properties.put("name", "bob");
BeanWrapper person = new BeanWrapperImpl(new Person());
for (Map.Entry<String, String> property : properties.entrySet()) {
person.setPropertyValue(property.getKey(), property.getValue());
}
System.out.println(person.getWrappedInstance().toString());
This will print:
-> Person [height=160, weight=80, name=bob]
The easiest way to achieve this is to use jackson's ObjectMapper class.
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> fields = ...;
Person o = mapper.convertValue (fields, Person.class);
The classic Java way is to pass the value Map as an argument to the constructor of Person and let person read the properties from the map.
This way you can have multiple ways for constructing a Person object. Either by passing arguments directly, or passing the map.
I would like to bring forward another benefit of this approach. If you do it this way, the cohesion is very high. This means that the knowledge of how to construct a Person object from a Map of values is coded within the class itself. If you would do this outside of the class and you want to construct Person objects in different locations of you program, then you would need to replicate the code for getting values from the map or abstract it into a utility method. Now you don't, and if you every would need to change the way how to construct a Person object you simply change it in one place.
import java.util.Map;
public class Person {
private static final String WEIGHT_PROPERTY = "weight";
private static final String HEIGHT_PROPERTY = "height";
private final int height;
private final int weight;
public Person(Map<String, String> map){
height = Integer.parseInt(map.get(HEIGHT_PROPERTY));
weight = Integer.parseInt(map.get(WEIGHT_PROPERTY));
}
public int getHeight() {
return height;
}
public int getWeight() {
return weight;
}
}
Map<String, String> map = ...;
int height = Integer.parseInt(map.get("height"));
int weight = Integer.parseInt(map.get("weight"));
Person p = new Person(height, weight);
Note that ResourceBundle is normally used to deal with internationalization. If you just need to read properties, then use the java.util.Properties class.
Simplifying #Jeroen Peeters post
public class Person {
Map<String, String> prop;
public Person(Map<String, String> map){
prop = map
}
public int getHeight() {
return Integer.parseInt(prop.get("height"))
}
public int getWeight() {
return Integer.parseInt(prop.get("weight"));
}
}

Create method get by name for list

I have the following class and that provide entity name with key and val of HashMap:
import java.util.LinkedHashMap;
public class ObjectStructure {
private String entityName;
private LinkedHashMap<String, String> keyVal;
public String getEntityName() {
return entityName;
}
public void setEntityName(String entityName) {
this.entityName = entityName;
}
public LinkedHashMap<String, String> getKeyVal() {
return keyVal;
}
public void setKeyVal(LinkedHashMap<String, String> keyVal) {
this.keyVal = keyVal;
}
}
I have also list as follows
private static List<ObjectStructure> JsonObj = new ArrayList<ObjectStructure>();
Since I'm getting the JSON object which list I need method that provide list by name
(i.e. entityName can have many entries and I want for specific entity get
the list of the respective data). I guess I need to build new class for it but I'm not sure how to design it, any ideas?
You could work with a different map:
Map<String, Map<String,String>> entities;
The key of the outer map would be the entityName, the inner Map is the collection of key/value pairs. To get the key/value pairs for a named entity, simply do:
Map<String, String> keyValueMap = entities.get("MyEntity");
I'm not quite sure what you are asking,
but if your asking how to return a certain ObjectStructure by entityName from the arraylist,
then just loop through the ArrayList and compare your searchString with each ObjectStructure's entityName.
If your looking for a value inside of the ObjectStructure inside of the ArrayList then
search the ArrayList for the right ObjectStructure. Once found, search the ObjectStructure for the key you are looking for.

Need help with java map and javabean

I have a nested map:
Map<Integer, Map<Integer, Double>> areaPrices = new HashMap<Integer, Map<Integer, Double>>();
and this map is populated using the code:
while(oResult.next())
{
Integer areaCode = new Integer(oResult.getString("AREA_CODE"));
Map<Integer, Double> zonePrices = areaPrices.get(areaCode);
if(zonePrices==null)
{
zonePrices = new HashMap<Integer, Double>();
areaPrices.put(areaCode, zonePrices);
}
Integer zoneCode = new Integer(oResult.getString("ZONE_CODE"));
Double value = new Double(oResult.getString("ZONE_VALUE"));
zonePrices.put(zoneCode, value);
myBean.setZoneValues(areaPrices);
}
I want to use the value of this Map in another method of the same class. For that I have a bean.
How do I populate it on the bean, so that I can get the ZONE_VALUE in this other method
In my bean I added one new field as:
private Map<Integer, Map<Integer, Double>> zoneValues;
with getter and setter as:
public Map<Integer, Map<Integer, Double>> getZoneValues() {
return zoneValues;
}
public void setZoneValues(Map<Integer, Map<Integer, Double>> areaPrices) {
this.zoneValues = areaPrices;
}
What I am looking for to do in the other method is something like this:
Double value = myBean.get(areaCode).get(zoneCode);
How do I make it happen :(
I would like to suggest a different, hopefully more readable solution:
public class PriceMap {
private Map<Integer, Map<Integer, Double>> priceMap =
new HashMap<Integer, Map<Integer, Double>>();
// You'd use this method in your init
public Double setPrice(Integer areaCode, Integer zoneCode, Double price) {
if (!priceMap.containsKey(zoneCode)) {
priceMap.put(zoneCode, new HashMap<Integer, Double>());
}
Map<Integer, Double> areaMap = priceMap.get(zoneCode);
areaMap.put(areaCode, price);
}
public void getPrice(Integer areaCode, Integer zoneCode) {
if (!priceMap.containsKey(zoneCode)) {
// Eek! Exception or return null?
}
Map<Integer, Double> areaMap = priceMap.get(zoneCode);
return areaMap.get(areaCode);
}
}
I think this is a better, more readable abstraction which, very importantly, makes it easier for you or someone else to read after a few months.
EDIT Added get get
If you're stuck with a get(areaCode).get(zoneCode) (order reversed), but myBean is entirely yours, you could do something like:
public class MyBean {
// I suppose you have this already
private final Map<Integer, Map<Integer, Double>> priceMap =
new HashMap<Integer, Map<Integer, Double>>();
private class LooksLikeAMap implements Map<Integer, Double> {
private Integer areaCode = areaCode;
public LooksLikeAMap(Integer areaCode) {
this.areaCode = areaCode;
}
public Double get(Object zoneCode) {
if (!priceMap.containsKey(zoneCode)) {
// Eek! Exception or return null?
}
Map<Integer, Double> areaMap = priceMap.get(zoneCode);
return areaMap.get(areaCode);
}
// Implement other methods similarly
}
public Map<Integer, Double> get(Integer areaCode) {
return new LooksLikeAMap(areaCode);
}
}
OK, programming in a HTML textarea is not my strong suit, but the idea is clear.
Make some Map like structure backed by the complete data set, and initialize that
Map structure with the required AreaCode.
If the idea is not clear, post a comment fast as it's late here:)
EDIT
I am an idiot. I thought the data was zone first, then area while the get should be area first, then zone. In this case the Map already has the right structure, first area then zone, so this is not necessary. The get-get is by default if you make
public MyBean {
public Map<Integer, Double> get(Integer areaCode) {
return data.get(areaCode);
}
}
To start with, all you need is
myBean.getZoneValues(areaCode).get(zoneCode);
the while loop has an annoyance, you need to call myBean.setZoneValues(areaPrices);
out side the while loop
You can't directly control the second get() call because you have a nested Map, you'll need to return the appropriate nested Map to be able to do what you want. A getter like this should do it:
public Map<Integer, Double> get(Integer areaCode) {
return zoneValues.get(areaCode);
}
So when the client code calls get(areaCode) a map will be returned that they can then call get(zoneCode) on.
I'd suggest that you refactor to eliminate the nested Maps though, because you can't stop client code from changing the returned Map, the code is tough to read and you'll have problems if you want to add any more functionality - imagine that you want to provide a String description of an area code in future.
Something like a Map<Integer, AreaCode> where AreaCode is an object that contains what you currently have as a nested Map might be a good place to start.

Categories