Java Map anti-pattern? - java

Edit: I've gotten a couple of answers that say what I already said in the question. What I am really interested in is finding corroborating reference material.
I am looking at a code sample that more or less follows this pattern:
Map<String, List> getListsFromTheDB() {
Map<String, List> lists = new HashMap<String, List>();
//each list contains a different type of object
lists.put("xList", queryForListOfXItems());
lists.put("yList", queryForListOfYItems());
return lists;
}
void updateLists() {
Map<String, List> lists = getListsFromTheDB();
doSomethingWith(lists.get("xList"));
doSomethingWith(lists.get("yList"));
}
My feeling is that this is an anti-pattern. What the coder should have done is create a class which can be returned, like this:
class Result {
private final List<X> xList;
private final List<Y> yList;
public Result(xList, yList) {
this.xList = xList;
this.yList = yList;
}
public List<X> getXList() { xList; }
public List<Y> getYList() { return yList; }
}
This would be more type-safe, avoid over-generalizing a very specific problem, and be less prone to errors at runtime.
Can anyone point me to any authoritative reference material which specifies that you should avoid this kind of pattern? Or, alternately, if it's actually a good pattern, please give justification.

I think the point is the number of Lists is fixed. Since you ensure the code uses 2 lists, the map is a little bit over-generalizing.
So 'class Result' is better I think.

I say it depends on the context.
If you return a map, the caller has to know the 'magic' keys "xList" and "yList" to get the actual data out of the map. I mean magic as magic constants. (You could iterate over the map to find the magic keys, but that's just a trick.) By using the map you have actually hidden the data, making it harder to get what one wants (x- and yLists).
The magic constants do not have to be so magically. If "xList" and "yList" would be the table names in the database (or whatever external strings), then I would expect to get a mapping from table names to object lists. Someone might add/rename/delete tables. (Or, maybe prettier, I would like to be able to query per table like getListFromTheDB("xList");. )
In your code you got this method
queryForListOfXItems();
That does smell like hard coded xList and yList. That would thus (IMO) make a map a bad choice.

I agree with you.
Obviously the guy was lazy and used a Map to avoid creating a new class.
The side effect is that the code that need to use getListsFromTheDB() will be less readable, and, as you mentionned, more error-prone.
Of course, there is the alternative in which the caller creates the lists:
void fillFromTheDB(List<X> xList, List<Y> yList) {
//each list contains a different type of object
xList.addAll(queryForListOfXItems());
yList.addAll(queryForListOfYItems());
}
void updateLists() {
List<X> xList = new ArrayList<X>();
List<Y> yList = new ArrayList<Y>();
fillFromTheDB(xList, yList);
doSomethingWith(xList);
doSomethingWith(yList);
}

I don't have any authoritative material, but my gut feeling is that, unless there's something more complex going on in the real code, using a Map this way doesn't bother me. The Result class feels a bit like overkill, actually.

Related

Java Hash Map Performance

protected static final Map<String, Integer> m = new HashMap();
I have a question in regards to performance of using the above. I am creating a 2D Tile Engine for a simple RPG game. I am using the hash map above to store the name of a tile along with its respected color code (Ex: 0xff00ff21). Since this is a game, the code m.get("name");is called an enormous amount of times to check if a tile is updated or not. (Ex: The render method with my computer runs at about 850 times per second). Please also note, I made sure to declare the HashMap outside of any loops and that it is initialized via a method call(also static) through the constructor that m.put("name", value) inputs all the information.
1) Is using a HashMap in this way a good idea? Is there perhaps another way to go about this more efficiently.
2) Is using a static final implementation of a hashMap good practice? The values will never change and the values used will be needed within the super class and its sub classes (Hence the "protected"). Can I set the key and value variables to final as well?
3) I understand that HashMap doesn't allow for duplicate keys, but from tinkering around with the HashMap, by inputting two of the same keys it simply replaces the older key and value with the newest .put("name", value);Is there to a way to throw an error perhaps if you try to .put("water", 0xff00ff21) and .put("water", 0xff221133) and/or .put("water",0xff00ff21)
Thank you for your time. New to this community and looking forward to helping/getting helped.
Please note that it is bad to ask three questions in one post.
1) IMO, yes. I usually use a HashMap for this kind of things. This can clarify things a lot better and enhance the readability of your code. Just imagine if you you only use hex color values for these kinda things, I think a lot of people would ask you what is 0xff221133 and what is 0xff00ff21.
2) Yes it is! static final is used when you want to declare some kind of constant. However, declaring a hash map as static final doesn't mean that its content cannot be changed. To prevent this, encapsulate the map in a class and only provide get methods:
final class TileColorMap {
private static final HashMap<String, Integer> tileColorMap = //blah blah blah
static {
//Add things to your map here
}
public static int get(String key) {
return tileColorMap.get(key);
}
}
3) If you look at the docs, specifically, Hashmap<>.put, you will see that:
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.)
So you can add a method that put something into the map and will throw an exception if the key is a duplicate by checking whether the returned value is null.
private static void putStuffInMap (String key, int value) {
Integer returnedValue = tileColorMap.put(key, value);
if (returnedValue != null) {
throw new RuntimeException("Duplicate Keys!");
}
}
1) I'm not sure I understand what you're doing here, but how many different kinds of tiles could you be using here? You might be better off just defining a Tile object with a few constant Tiles that you can just reuse again and again by referring to Tile.WATER, etc instead of doing a hashtable lookup. If water has multiple colors just put them all in the water Tile object and pick from amongst them.
public class Tile
{
public static final Tile WATER = new Tile(...);
public static final Tile ROCK = new Tile(...);
}
2) Making a hashmap instance static and final doesn't make it immutable. The contents can still be updated. There's no performance benefit anyway. A read only hashmap wouldn't be any faster than a writable one. If you don't want it updated, just don't update it. It's your code, it's not like it's going to write to the hashmap when you aren't looking.
3) You could subclass hashmap and make it not accept duplicate keys, but again, I'm not sure what the purpose of this is- why aren't you sure what colors your tiles will be at run time? This strikes me as the kind of thing decided before compile time.
Using HashMap should be efficient enough. Is there more efficient way? Of course there will always be but whether it is appropriate depends on your design. For example, if tiles are statically defined, you may use enum/integer constants to represent a tile (instead of using "name"), and your tile-to-XXX mapping can be easily expressed as ArrayList or even array. (Again, it may not be appropriate to your design).
Again it depends on the design. Are the class containing the map something that is going to instantiate multiple times but you really want each instance to share same mapping? Are you going to give flexibility to the child class to set up the mapping? It is only meaningful to make it static if first answer is YES and second is NO.
To avoid change of content for the map, you can wrap it in a unmodifiable map:
// Access your data through this, so you won't mistakenly modify it
protected final Map<...> tileColorMap = Collections.unmodifiableMap(getTileColorMap());
// your super class or sub-class is providing the actual map
protected Map<...> getTileColorMap() {
Map<...> tileColorMap = new HashMap<>();
// do your setup
return tileColorMap;
}
If you are using Java 8+, it may be better to use Map#merge() method, and have the remapping function throw an exception you desire. Compared with the approach given by other answers, using merge() is safer as original value won't be mistakenly replaced. You may also selectively throw the exception if the new value is different from existing value.

List usage without specifying the Type

I see a code in the new environment. It is as follows:
List results;
if (<Some Condition>) {
results = List<XYZ> results;
} else {
results = List<ABC> results;
}
XYZ and ABC are Hibernate Entities.
Though this works, I guess this is not a proper way to do this.
I would like to know whats the better way to do it. I know there is no "perfect" way to do it. But this can be better.
Remember these are non-similar Entities. So I think wrapping these Entities with an Interface might not be a good idea.
Generics are a compile-time mechanism, so, if you don't know the type of object you are pulling, generics are not appropriate.
I understand that the entities are different and not correlated, but I don't understand why an interface is not a good idea. Basically, you know that you want to collect some data, according to some condition. So, just for the fact that XYZ and ABC are candidates to be type of the collected data, you do have some commonalities. In that case, you may have a
List<? extends CommonInterface>
and CommonInterface is used just here.
However, assuming XYZ and ABC are completely distinct, one more option could be to split the method in two parts and use a generic method receiving also the type of data you want to collect:
public void methodForTheCondition() {
if (<some condition>) {
List<XYZ> l = genericMethod(XYZ.class);
// do something
} else {
List<ABC> l = genericMethod(ABC.class);
// do something else, which I assume is different, otherwise opt for
// a common interface
}
}
public <T> List<T> genericMethod(Class<T> clazz) {
List<T> result = new ArrayList<T>();
return result;
}
But this can be better.
What makes you believe this? Without knowing the exact condition, this looks simply like a mass-loading of items in a generic EntityManager and therefore returning a List<X> whatever X might be.
From the code point of view, there is nothing wrong, because you are creating a untypted List and assigning a List of a certain type to that variable later...
As long as you use List as a raw-type, you are able to assign any List to it. This is what interfaces are designed for (Assigning a type without knowing the exact type...)
Remember these are non-similar Entities. So I think wrapping these Entities with an Interface might not be a good idea.
There are a lot of Interfaces out there that makes perfect sence for non-similar Items. Starting with anything that Aggregates elements (List, Map), ending with Interfaces that simply describe one thing that is in common, I.E: Serializable, Comparable, etc..
An Interface does not mean that the objects are related in some way (that is what parent/abstract classes are used for) An Interface simply say that a certain functionality is implemented. (hence, you can inherit multiple interfaces in one class)

Should return statements use generics in Java?

I have a basic question about using the "Best Practices" in coding. (I'm using Java, but the question is general to OOP.) When writing method's for a class that are intended to be used in the long run, is it best to leave the return object with or without generics?
To be specific in my case, I'm returning a Map<String, Integer> with the method. Should I specify this in the return statement, or should I simply return a Map?
It is best to use generics whenever possible. It will help avoid runtime exceptions, and it won't force the people using your code to do a bunch of ugly type casting. For example, if you use the following signature:
Map<String, Integer> getMap();
... then the consuming code might look like this:
Map<String, Integer> map = getMap();
Integer val = map.get(key);
... but if you use a signature like this:
Map getMap();
... the consuming code might look like this:
Map<String, Integer> map = (Map<String, Integer)getMap();
Integer val = map.get(key);
By using generics, not only do you save that (Map<String, Integer>) cast, but in the event that you change getMap to actually return a Map<String, Object>, you will get a compile-time error (which is easy to catch and fix), rather than possibly getting an exception when you call map.get(key) and the JRE tries to do an automatic cast of some random Object into an Integer.
You should definitely return a Map<String, Integer> instead of a plain Map if it makes sense in your method, as this will make it easier for others to use said method - after getting the Map<String, Integer> they will be able to retrieve String keys and Integer values without having to cast them from a generic Object every time (this also makes it a little more typesafe as this way they will know what the keys and values are without even reading the javadoc for your method).
So in short, definitely, return generics.
If you are returning a collection, you should include the generic type that is contained by the collection. For example:
public Map<String, Blammo> getBlammoMap(...)
is (IMHO) preferred to
public Map getBlammoMap(...)
Because it
Limits the options of a bad cast (i.e. kapowMap = (Map<String, Kapow> getBlammoMap()).
Tells the consumer what the method is actually returning.
If the method is clearly intended to work with a certain type (i.e. only String), then it's ok to return a List<String>. If the method is generic taking a type parameter T, you can return List<T>.
I would not simply return a Map, because usually it causes confusion and more boiler-plate code to convert to the desired type.
In general, your type parameters, both input and output, should capture the level of specificity of the precise function. In functional programming, they go so far as to say "the types are the documentation." If I were to see Map foo(Arg args) I would think that foo is in no way concerned with the types in the Map it returns, but somehow relies on Args for something." If I were to see Map<T,String> foo(T t, Arg arg) or Map<T, U> foo(T t, U u) I would think "OK, foo produces a Map based on the type of its t and with a String produced by Arg (or by the U from u)."
In terms of preference, clearly you want to be as clear as possible to the future programmer (yourself or others). Just as returning Map without type-params is obscure, so too would returning Map<String, Integer> might be overly restrictive (and thus misleading) if your foo would work equally well with, say, Map<String, Long>
I believe that more specific, the better. If your method is return a map that always has Strings as the key, and Integers as the value, then definitely use the Map has the return type. That way, any calling code knows exactly what they're getting. If the return type was just Map, then the calling code would have no idea what the class the keys and values are (Other than Object).
In general, you should probably always specify paramerize Maps, Lists, etc., so it's known exactly what it contains. This is very helpful when iterating over them and you can use a java foreach.
for (String currKey : myMap.keySet())
{
System.out.println("curr Key: " + currKey + " curr Value: " + myMap.get(currKey));
}
This eliminates any extra iterators or casting.
Ho-ho-ho! A pretty New Year question.
You generally must (MUST) return a proper generic Map<Whatever, YouNeed>. It may sound crazy, but as soon as you use any generic type without type parameters, you're getting into trouble.
The trouble will be as follows: raw types, being used in the code, change the way methods (even seemingly non-related ones) are resolved. Find a presentation by Joshua Bloch and Bill Pugh called "Java Puzzlers: Scraping the Bottom of the Barrel" for details whle I'm preparing an example :) The video with details is at http://www.parleys.com/#id=2168&st=5 (you may want to scroll to slide 44, 5. "Glommer Pile")
So here's an example:
/**
* (c) (as far as I know) Joshua Bloch and Bill Pugh, 2010
*/
public class Glommer<T> {
String glom(Collection<?> objs) {
String result = "";
for (Object o : objs) result += o;
return result;
}
int glom(List<Integer> ints) {
int result = 0;
for (int i : ints) result += i;
return result;
}
public static void main(String args[]) {
List<String> strings = Arrays.asList("1", "2", "3");
System.out.println(new Glommer().glom(strings));
}
}
Question is, whether it
prints 6
prints 123
throws an exception,
or does something else.
Try to guess. Then compile (yes it compiles) and see what happens.
Now that does not apply to your case. But having a habit of always specifying the type, even if it will be just Map<?,?>, is extremely helpful. You won't lose.
The obligatory Java Generics FAQ link

How to create new variable in java dynamically

Is it possible to create new variables in java dynamically.
class A {
methodA(String variableName) {
}
}
So if new method is called twice, 2 new variables should be newly added to this class?
Is it possible?
No. Have you considered storing a Map<String, Object> in the class instead? The keys in the map would be the "variable names" and the values in the map would be the logical variable names.
If you could give more information about what you're trying to achieve (from a high-level perspective) that would help.
No, this is not possible to do in Java.
The fields in a class is determined at compile time and can't be changed during runtime (except though sophisticated techniques such as class reloading though for instance JRebel). I would however not recommend doing this, unless you're writing some IDE for instance.
A class and its members are defined and then compiled to bytecode, so they cannot be readily modified at run-time. That said, there are a number of libraries out there, such as cglib, which provide runtime modification functionality. This page can tell you more: http://java-source.net/open-source/bytecode-libraries
(This is not to say that runtime modification is the right thing to do!)
In a good design, a class must represent something, semantically speaking. You design it to represent an object in your system.
If you want to add more things to a design in run-time, well, something's not quite right -- unless, of course, the design needs adding information in run-time, and there are tons of data structures just ready for the job!
Check out Maps in Java, for example.
Following is the way that i have implemented and helped me to fix my solution easily without much hurdles.
// Creating the array List
List accountList = new ArrayList();
for(int k=0;k < counter;k++){
accountList.add(k, (String)flowCtx.getValueAt("transitId"+m));
}
Iterating the loop and adding the objects into the arraylist with the index.
//Retrieving the object at run time with the help of the index
String a = accountList.get(i));
Using a HashMap could be a solution. For example, if we have the following class:
class Staff {
private HashMap<String, Object> mylist = new HashMap<String, Object>() ;
void setNewVar(String s, Object o) {
mylist .put(s, o);
}
HashMap<String, Object> getVar() {
return mylist;
}
}
I can use it as:
staff.setNewVar("NumVars",11);
staff.setNewVar("NumBatches",300);
...
and then:
staff.getVar()
wherever you need. I use it to convert some variables (the number can change) to JSON, successfully.

Vectors in Java, how to return multiple vectors in an object

I'm working on a java program, and I have several vectors defined and filled (from a file) inside a method. I need to return the contents of all the vectors from the method. I have heard you can put them all in one object to return them. Is that possible, and if so, how? If not, do you have any possible solutions for me? Thanks in advance for your help!
Here is a code snippet:
Object getInventory()
{
Vector<String> itemID=new Vector<String>();
Vector<String> itemName=new Vector<String>();
Vector<Integer> pOrdered=new Vector<Integer>();
Vector<Integer> pInStore=new Vector<Integer>();
Vector<Integer> pSold=new Vector<Integer>();
Vector<Double> manufPrice=new Vector<Double>();
Vector<Double> sellingPrice=new Vector<Double>();
Object inventoryItem=new Object(); //object to store vectors in
try
{
Scanner infile= new Scanner(new FileReader("Ch10Ex16Data.txt"));
int i=0;
while (infile.hasNext())
{
itemID.addElement(infile.next());
itemName.addElement(infile.next()+infile.nextLine());
pOrdered.addElement(infile.nextInt());
pInStore.addElement(pOrdered.elementAt(i));
pSold.addElement(0);
manufPrice.addElement(infile.nextDouble());
sellingPrice.addElement(infile.nextDouble());
i++;
}
infile.close();
System.out.println(itemID);
System.out.println(itemName);
System.out.println(pOrdered);
System.out.println(pInStore);
System.out.println(pSold);
System.out.println(manufPrice);
System.out.println(sellingPrice);
}
catch (Exception f)
{
System.out.print(f);
}
return inventoryItem;
}
Personnally, I'd scrap that approach completely. It seems like you need a Product class:
public class Product {
private String itemName;
private int itemID;
// etc etc
public Product(String itemName, int itemID) {
this.itemName = itemName;
this.itemID = itemID;
// etc etc
}
public String getItemName() {
return itemName;
}
public int getItemID() {
return itemID;
}
// etc etc
}
Then something like this :
public class Invertory {
private List<Product> products = new ArrayList<Product>
// etc etc
public Inventory(String fileName) throws IOException {
// Load file,
// Read each product,
products.add(new Product(...product arguments); //add to array
}
public Product[] getProducts() {
return products.toArray(new Product[]{});
}
}
First of all, use ArrayList instead of Vector. Then use a Map as your return object, with each value of the entry is one of your Lists.
Second of all, a much better approach is to create an object that actually holds each of your fields and return a java.util.List of these objects.
public class Item
{
String id;
String name
Integer pOrdered;
Integer inStore;
:
:
You're doing a few things wrong.
Firstly, don't use Vector. Like, ever. If ordering is important to you, you want List on the API (and possibly ArrayList or LinkedList as an implementation).
Secondly, you're trying to have a large number of arrays have values that happen to line up. That's going to be nearly impossible to use. Just create a class that represents one record, and return the List of those.
Thirdly: do not catch that exception. You don't know what to do with it, and you're just going to confuse yourself. Only catch an exception if you have a really good idea what to do in the error case (printing out an error message without a stack is just about never the right thing).
The signature of your method is the most important part. If you get that right, the implementation doesn't matter nearly as much. Aim for something that looks like this:
List<Item> getInventory(File input) throws IOException {
}
You really should reconsider your design here. You have multiple vectors, each with properties of the same type of thing — an item in your inventory. You should probably turn this into a single class, perhaps InventoryItem, with members for the name, price, etc. Then, when reading in each item, you construct an InventoryItem with the given properties, and return a single Vector<InventoryItem>.
If you're really attached to keeping track of all those individual Vectors, you could just return a Vector[] with all the vectors you have:
return new Vector[] { itemID, itemName, pOrdered, pInStore, pSold, manufPrice, sellingPrice };
Also, as Robin says, you should use the ArrayList container instead of Vector. The only thing that will change is that you need to change all calls to someVector.AddElement to someList.add.
Sounds like this should be tagged "Homework".
Okay, first of all, are you required to use all these Vectors, or is that your own decision? Though some may point out that using ArrayLists is better, I'd do away with them and create your own Item class.
This way, instead of having a conceptual item's properties distributed across multiple Vectors (the way you're doing now) you have 1 Item instance per item, with fields for all the data relevant to that item. Now, you only need one data structure (Vector or ArrayList) for all your item objects, and you can return that structure from getInventory().
The easiest way to declare the object would be something like
List<Vector<? extends Object>> inventoryItem = new ArrayList<Vector<? extends Object>>
but this has several problems, namely that Java's generics aren't reified, so you have to test and cast the contents of each vector that you get back. A better solution would be to define a container object that has each of the Vectors as fields and add to those.
However, this looks like it is really missing the point. Instead, you should define an InventoryItem who has each of your seven fields. Each time you read an object from the file, instantiate a new InventoryItem and populate its fields. Then, you add this to a single Vector.
Also, it is generally recommended that you do not use the Vector class. Instead, you should use ArrayList. Vector should really only be used if you need its synchronization properties, and even then you should consider wrapping some other list in a Collections.synchronizedList().
Finally, the places where you would want to catch just an Exception can be counted on one hand. You should really be catching an IOException and even that you might want to consider just rethrowing. Also, you should call printStackTrace() on the exception rather than System.out.println().
I find that a good rule of thumb is that it's never really a good idea to pass collections around outside your objects. They are obviously useful inside your object, but outside you lose control and they are not obvious.
Consider the principle of making your code readable instead of documenting it. If you take a collection, how does that tell the caller what to pass in? Even if you use generics, there is no way to assert control over what happens to the collection--someone could be adding to it and deleting from it in another thread after it's passed to you.
There is no reason not to create a business class that contains your collections along with the business logic to manipulate them (yeah, there is always business logic--it's the copy and paste code you'll find around the locations that you access the collection).
I used to find it frustrating that the JDK always seems to take arrays of built-in types rather than collections, but it makes a lot more sense after coming to terms with the idea that passing collections (like passing around any basic type) is just not a very good idea.
While in general I heartily agree with the advice to use List/ArrayList instead of Vector, it is important to know why. Indeed, I have to vehemently disagree with Dustin who says not to use Vector "ever".
A Vector is in essence a synchronized ArrayList. If you truly need synchronization, by all means then, ignore Dustin's admonition, and use Vector.
There is another instance in which Vector is justified. And that is when you need to maintain compatibility with a pre-Java2 code base.

Categories