Issues with using objects as Map keys with Java - java

Given an object we will call loc that simply holds 2 int member values, I believe I need to come up with a mechanism to generate a hashcode for the object. What I tried below doesn't work as it uses an object reference, and the 2 references will be different despite having the same members variables.
Map<Loc,String> mapTest = new HashMap<Loc,String>();
mapTest.put(new Loc(1,2), "String 1");
mapTest.put(new Loc(0,1), "String 2");
mapTest.put(new Loc(2,2), "String 3");
System.out.println("Should be String 2 " + mapTest.get(new Loc(0,1)));
After some reading it seems I need to roll my own hashcode for this object, and use that hashcode as the key. Just wanted to confirm that I am on the right track here, and if someone could guide me to simple implementations to look at that would be excellent.
Thanks

Yes, you need to override equals() and hashCode() and they need to behave consistently (that is, equal objects have to have the same hash code). No you do not use the hash coe directly; Map uses it.

Yes, you're on the right track.
See articles like this for more details.
There are a lot of different ways to implement a hashcode, you'll probably just want to combine the hashcodes of each integer primitive.

Writing correct equals and hashcode methods can be tricky and the consequences of getting it wrong can be subtle and annoying. If you are able to, I would use the apache commons-lang library and take advantage of the HashCodeBuilder and EqualsBuilder classes. They will make it much easier to get the implementations right. The benefit of using these libraries is that it is much harder to get the boiler plate wrong, they hide the visual noise these methods tend to create and they make it harder for someone to come a long later and mess it up. Of course another alternative is to let your IDE generate those methods for you which works but just creates more of the noisy code vomit Java is known for.

If you want to use your type as a key type in a map, it's essential that it provides sane implementations of equals and hashCode. Fortunately, you don't have to write these implementations manually. Eclipse (and I guess other IDEs as well) can generate this boilerplate for you. Or you can even use Project Lombok for that.
Ideally the object to be used as a key in a map should be immutable. This can save you from many bugs led to by the equality issues in the context of mutation.

You need to implement both hashCode() and equals(). Joshua Bloch's Effective Java should be the definitive source on the "how" part of your question, and I'm not sure if it's okay to reproduce it here, so I'll just refer you to it.

Related

Should all classes have a .equals and .hashcode method?

I'm working on a unit testing project where the asserts call the .equals method. However the people on the project before didn't generate these methods.
Is it considered best practice to auto generate these methods as you code? Should all coders be doing this?
I was searching for more information on the .equals and .hashcode method and most of them seem to be geared towards how to implement or override them.
It's mostly a question of taste - if you don't expect to use the equals method (e.g., aren't using assertEquals, never mean to use this class as a key in a Map, etc), writing it means you may be writing dead code, and some conventions would advocate avoiding it.
Here, there doesn't seem to be a question - if you intend to use assertEquals, you need an the equals method implemented. If you're going to implement it, you should probably also implement hashCode in order to future proof your code against sneaky, hard to find, bugs.
Auto generating of these methods leads us to some standard implementation. One standard implementation is coded in Object: comparing links and a native hash code calculation.
Unless you can imagine some other standard implementation fitting for all entities in your project, you probably shoudn't auto generate equals and hash code: implement it manually, when you know all conditions of future comparation.

Is using Java Reflection Bad Practice?

I am building an application for a client and I am in the situation where I need to have the ability to reference a field value via a string, i.e the users uses a string to define which field they want to change the value of, this is part of an abstract framework so technically I don't know the name of the fields they desire to change. Of course I could do this using hash maps, but I am considering using java reflection as this allows the fields to stay as fields of the object rather than the values being coded into a hash map. I have used reflection for my own personal work, but I was wondering if using Java reflection is actually bad practice, and I should stick to the hashmap methodology.
(Any other suggestions for solving the design problem described are also appreciated)
Thanks
The question itself is opinion based, although I believe most will agree that you can't just say "reflection is bad". Sometimes it's the only way, which is why a lot of libraries use reflection. Sometimes it's not the only way, but a workaround would be even worse. Sometimes it's not the only way, and not the easiest way, but the developer is far too amazed at the power of reflection to think straight.
Except for that last one there are plenty of valid reasons to consider reflection as a solution.
Personally reflection makes me sad, and in my experience there is almost always a better way. In the problem you described, setting variables based on a string i'd consider going with your hashmap idea which would reference variables via a string key which seems like exactly what you are describing. If you need the ability to reference values that do not exist you could also include factory methods to create variables when no key exists and then add to the map, if you are wrapping the objects then they will be passed by reference to avoid the problem you describe but this depends on the implementation (eg using Integer class etc for auto boxing if you are referencing primitives) Together this would allow for a much tighter and well defined implementation rather than reflecting values here there and everywhere. Apologies for the anti-reflection bias! Hope this helps.

Using UUID as business key and equals/hashmethod

I am working on a new application and I need some help on how to implement the equals method and the hashCode method. I have been reading many questions already asked here on SO, and I have also read several blog posts that has lead me to this question.
A little technical information first: I am using JPA (EclipseLink) and the application is for Java EE.
After what I have read you should use immutable values for hashCode and equals, but since the fields in the class is usually modifiable you can't use them. Nor can you use the primary key (JPA) because you won't have one before you have persisted it. So what I am thinking about is to use UUID. Both for equals and hashCode, but I have never done that before so I wonder if somebody thinks this is bad (why?) and possible downsides (apart from the tiny tiny tiny chance of getting the same ID)? Using a UUID and asign it in the constructor will give all objects a business ID from the very start. And I will make it immutable and save it to the database.
Is this approach bad?
IMO the UUID will work just fine and i would recommend doing so.
I can't find any drawbacks to this approach since the possibility of hitting 2 same values is infinitely small.

JPA : not overriding equals() and hashCode() in the entities?

After reading this article , im bending toward not overriding equals() and hashCode() altogether.
In the summary of that article, concerning the no eq/hC at all column, the only consequence is that i couldnt do the comparison operations like :
contains() in a List for detached entities, or
compare the same entities from different sessions
and expect the correct result.
But im still in doubt and would like to ask your experiences about this whether it is a bad practice to skip equals and hashCode altogether and what other consequences that i still dont know for now.
Just another point of information, im bending towards using List Collections over Set. And my assumption is that i dont really need to override hashCode and equal when storing in a List.
Read this very nice article on the subject: Don't Let Hibernate Steal Your Identity.
The conclusion of the article goes like this:
Object identity is deceptively hard to implement correctly when
objects are persisted to a database. However, the problems stem
entirely from allowing objects to exist without an id before they are
saved. We can solve these problems by taking the responsibility of
assigning object IDs away from object-relational mapping frameworks
such as Hibernate. Instead, object IDs can be assigned as soon as the
object is instantiated. This makes object identity simple and
error-free, and reduces the amount of code needed in the domain model.
whether it is a bad practice to skip equals and hashCode altogether
Yes. You should always override your equals and hashCode. Period. The reason is that this method is present already in your class, implemented in Object. Turns out that this implementation is generic, and nearly 100% of the times it's a wrong implementation for your own objects. So, by skipping equals/hashCode you are in fact providing a wrong implementation and will (in the best case scenario) confuse whoever uses these classes. It may be your colleagues, or it may be some framework you are using (which can lead to unpredictable and hard-to-debug issues).
There's no reason to not implement these methods. Most IDEs provides a generator for equals/hashCode. You just need to inform the IDE about your business key.
You got the exact opposite conclusion from that article of what it was trying to convey.
Hibernate heavily relies on equals being implemented properly. It will malfunction if you don't.
In fact, almost everything does; including standard java collections.
The default implementation does not work when using persistence. You should always implement both equals and hashcode. There's a simple rule on how to do it, too:
For entities, use the key of the object.
For value objects, use the values
Always make sure the values you use in your equals/hashcode are immutable. If you pass these out (like in a getter), preferably pass them out in an immutable form.
This advice will improve your life :)

Why are variables declared with their interface name in Java? [duplicate]

This question already has answers here:
What does it mean to "program to an interface"?
(33 answers)
Closed 6 years ago.
This is a real beginner question (I'm still learning the Java basics).
I can (sort of) understand why methods would return a List<String> rather than an ArrayList<String>, or why they would accept a List parameter rather than an ArrayList. If it makes no difference to the method (i.e., if no special methods from ArrayList are required), this would make the method more flexible, and easier to use for callers. The same thing goes for other collection types, like Set or Map.
What I don't understand: it appears to be common practice to create local variables like this:
List<String> list = new ArrayList<String>();
While this form is less frequent:
ArrayList<String> list = new ArrayList<String>();
What's the advantage here?
All I can see is a minor disadvantage: a separate "import" line for java.util.List has to be added. Technically, "import java.util.*" could be used, but I don't see that very often either, probably because the "import" lines are added automatically by some IDE.
When you read
List<String> list = new ArrayList<String>();
you get the idea that all you care about is being a List<String> and you put less emphasis on the actual implementation. Also, you restrict yourself to members declared by List<String> and not the particular implementation. You don't care if your data is stored in a linear array or some fancy data structure, as long as it looks like a List<String>.
On the other hand, reading the second line gives you the idea that the code cares about the variable being ArrayList<String>. By writing this, you are implicitly saying (to future readers) that you shouldn't blindly change actual object type because the rest of the code relies on the fact that it is really an ArrayList<String>.
Using the interface allows you to quickly change the underlying implementation of the List/Map/Set/etc.
It's not about saving keystrokes, it's about changing implementation quickly. Ideally, you shouldn't be exposing the underlying specific methods of the implementation and just use the interface required.
I would suggest thinking about this from the other end around. Usually you want a List or a Set or any other Collection type - and you really do not care in your code how exactly this is implemented. Hence your code just works with a List and do whatever it needs to do (also phrased as "always code to interfaces").
When you create the List, you need to decide what actual implementation you want. For most purposes ArrayList is "good enough", but your code really doesn't care. By sticking to using the interface you convey this to the future reader.
For instance I have a habit of having debug code in my main method which dumps the system properties to System.out - it is usually much nicer to have them sorted. The easiest way is to simply let "Map map = new TreeMap(properties);" and THEN iterate through them, as TreeMap returns the keys sorted.
When you learn more about Java, you will also see that interfaces are very helpful in testing and mocking, since you can create objects with behaviour specified at runtime conforming to a given interface. An advanced (but simple) example can be seen at http://www.exampledepot.com/egs/java.lang.reflect/ProxyClass.html
if later you want to change implementation of the list and use for example LinkedList(maybe for better performance) you dont have to change the whole code(and API if its library). if order doesnt matter you should return Collection so later on you can easily change it to Set if you would need items to be sorted.
The best explanation I can come up with (because I don't program in Java as frequently as in other languages) is that it make it easier to change the "back-end" list type while maintaining the same code/interface everything else is relying on. If you declare it as a more specific type first, then later decide you want a different kind... if something happens to use an ArrayList-specific method, that's extra work.
Of course, if you actually need ArrayList-specific behavior, you'd go with the specific variable type instead.
The point is to identify the behavior you want/need and then use the interface that provides that behavior. The is the type for your variable. Then, use the implementation that meets your other needs - efficiency, etc. This is what you create with "new". This duality is one of the major ideas behind OOD. The issue is not particularly significant when you are dealing with local variables, but it rarely hurts to follow good coding practices all the time.
Basically this comes from people who have to run large projects, possibly other reasons - you hear it all the time. Why, I don't actually know. If you have need of an array list, or Hash Map or Hash Set or whatever else I see no point in eliminating methods by casting to an interface.
Let us say for example, recently I learned how to use and implemented HashSet as a principle data structure. Suppose, for whatever reason, I went to work on a team. Would not that person need to know that the data was keyed on hashing approaches rather than being ordered by some basis? The back-end approach noted by Twisol works in C/C++ where you can expose the headers and sell a library thus, if someone knows how to do that in Java I would imagine they would use JNI - at which point is seems simpler to me to use C/C++ where you can expose the headers and build libs using established tools for that purpose.
By the time you can get someone who can install a jar file in the extensions dir it would seem to me that entity could be jus short steps away - I dropped several crypto libs in the extensions directory, that was handy, but I would really like to see a clear, concise basis elucidated. I imagine they do that all the time.
At this point it sounds to me like classic obfuscation, but beware: You have some coding to do before the issue is of consequence.

Categories