• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 333
  • Last Modified:

equals() hashCode() compareTo(), comparator

one question in my mind in above TestTreeMapAlone.java, TestTreeMap5.java both using below Dog object with compareTo() method alone without equals() and hashCode() methods.
import java.util.ArrayList;
import java.util.Collections;


public class TestTreeMap5{
public static void main(String[] args) {
    //        TreeMap<Dog, Integer> treeMap = new TreeMap<Dog, Integer>();
        Dog d1 = new Dog("red");
	Dog d2 = new Dog("black");
	Dog d3 = new Dog("white");
	Dog d4 = new Dog("green");
	/*
	treeMap.put(d3, 20);
	treeMap.put(d1, 10);
	treeMap.put(d2, 15);	
	treeMap.put(d4, 20); 

	//print size
	System.out.println(treeMap.size());
		
	//loop treeMap
	for (Dog keyObj : treeMap.keySet()) {
	    System.out.println(keyObj.toString() );
	}
	*/
      ArrayList<Dog> list=new ArrayList<Dog>();
      list.add(d1);
      list.add(d2);
      list.add(d3);
      list.add(d4);
      Collections.sort(list);
      for (Dog keyObj : list ){
	  System.out.println(keyObj.color );
      }
}

}

Open in new window


import java.util.TreeMap;

public class TestTreeMapAlone{
    public static void main(String[] args) {
        TreeMap<Dog, Integer> treeMap = new TreeMap<Dog, Integer>();
        Dog d1 = new Dog("red");
        Dog d2 = new Dog("black");
        Dog d3 = new Dog("white");
        Dog d4 = new Dog("green");

        treeMap.put(d3, 20);
        treeMap.put(d1, 10);
        treeMap.put(d2, 15);
        treeMap.put(d4, 20);

        //print size
        System.out.println(treeMap.size());

        //loop treeMap
        for (Dog keyObj : treeMap.keySet()) {
            System.out.println(keyObj.toString() );
        }
    }
}

Open in new window


class Dog  implements Comparable<Dog> {

    String color;


    Dog(String c) {

        color = c;

    }

    public Dog(String string, int i) {
        // TODO Auto-generated constructor stub
    }

    public String toString(){

        return color + " dog22";

    }
    /*public int compareTo(Dog compareDog) {
        return this.color.compareTo(compareDog.color);
    }*/
    
    public int compareTo(Dog compareDog) {
        return -this.color.compareTo(compareDog.color);
}

};

Open in new window

why we were not forced to use equals() and hashCode() methods here. Sometimes we are forced to use equals() and hashCode() methods as seen in other examples. please advise on which scenarios compareTo() method is sufficient and which scenarios along with compareTo() we need to implement equals() and hashCode() and which scenarios we need to implement equals() and hashCode() without compareTo() method.  When we use comparator when we use comparable interfaces
0
gudii9
Asked:
gudii9
  • 20
  • 16
  • 10
  • +3
4 Solutions
 
dpearsonCommented:
why we were not forced to use equals() and hashCode() methods here

It all depends on the details of the collection you are using.

As a general rule of thumb, if you are putting an object as a key into a map you should implement equals() and hashCode().

Why do you do this?  So that code like this works as expected:

public class TestMap{
	public static void main(String[] args) {
		//TreeMap<Dog, Integer> treeMap = new TreeMap<Dog, Integer>();
		Map<Dog, Integer> treeMap = new HashMap<>() ;
		Dog d1 = new Dog("red");

		treeMap.put(d1, 10);

		Dog d5 = new Dog("red") ;
		Integer value1 = treeMap.get(d1) ;
		Integer value2 = treeMap.get(d5) ;

		System.out.println("value1=" + value1 + " value2=" + value2);
	}
}

Open in new window


In this example, we have d1 (a "red" Dog) and d5 (also a "red" Dog).

When you check to see if d1 is in the map, the answer is yes.
When you check to see if d5 is in the map, the answer is no...unless you implemented "equals" and "hashCode" in Dog.

This is not what a caller would expect because both are:
    Dog var = new Dog("red") ;

The reason is that the hashmap doesn't know that d1 and d5 should be treated as "equal".

So why does this work in a TreeMap without equals() and hashCode() and just implemented compareTo()?

That's because in a TreeMap the lookup is done by sorting the keys into order and then checking to see where in the list a given key appears.  If you have a way to sort things, then you essentially have a way to decide if two of them are equal (they sort to the same place).

But this is just a detail of how TreeMaps work.  It's not a good reason to implement your Dog object to only work inside a TreeMap.  Better to make it work inside any Map.

So the guidelines I'd suggest are:

a) If you want your objects to behave correctly when you put them into Maps then you should implement equals() and hashCode().

b) If you want a way to sort your objects into a specific order, then you should implement compareTo().

Does that make sense?

Doug
0
 
krakatoaCommented:
But Doug - you didn't even give d5 a chance to get in the Map . . . . ?
0
 
dpearsonCommented:
But Doug - you didn't even give d5 a chance to get in the Map . . . . ?

Yes that's the whole point.  If "equals" and "hashCode" are implemented in the Dog class then the lookup for d5 will succeed because it'll find a Dog with color "red" and return that.  Which is what a caller would expect I think.

Otherwise you have a map which is very hard to use.  You need to lookup the keys using the *exact same* instance of the object you had a the start - which isn't usually possible.
0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

 
krakatoaCommented:
What is going on then here ? :

import java.util.*;

public class TestMap{
	public static void main(String[] args) {
		//TreeMap<Dog, Integer> treeMap = new TreeMap<Dog, Integer>();
		Map<Dog, Integer> treeMap = new HashMap<>() ;
		Dog d1 = new Dog("red");

		treeMap.put(d1, 10);
		

		Dog d5 = new Dog("red") ;
		
		treeMap.put(d5, 10);
		Integer value1 = treeMap.get(d1) ;
		Integer value2 = treeMap.get(d5) ;

		System.out.println("value1=" + value1 + " value2=" + value2);
	}


static class Dog{

private String colour;

public Dog(String col){

this.colour = col;

}


}	
	
}

Open in new window

0
 
krakatoaCommented:
Oops, sorry - I didn't actually see until now that the methods are being implemented - prob because he didn't post the Dog class at all in a previous Q which used Dog instances).
0
 
zzynxSoftware engineerCommented:
As I said in another question where you asked the same:
When sorting is involved (TreeMap or calling sort()) => compareTo()
When hashing is involved (HashMap) => equals() and hashCode()
0
 
gudii9Author Commented:
calling sort())

what it mean by calling sort()

please advise
0
 
gudii9Author Commented:
When sorting is involved (TreeMap

i understand the Tree<Map which i used in this examples. But not clear on calling sort() part.

Please advise
0
 
dpearsonCommented:
He just means that if you have a list of objects and wish to sort them by calling something like:
            Collections.sort(list);
then you can control the order of the sorted items by implementing compareTo() on your objects.

E.g.

List<Dog> list = new ArrayList<Dog>() ;
Collections.sort(list) ;

If you implement compareTo() in Dog you can use it to customize the way Dog objects are sorted.

Doug
0
 
krakatoaCommented:
Doug :

Yes that's the whole point.  If "equals" and "hashCode" are implemented in the Dog class then the lookup for d5 will succeed because it'll find a Dog with color "red" and return that.  Which is what a caller would expect I think.

I'm not so sure that *I* personally would expect that . . . what happens when there are several 'red' dogs, but they have different weights. 'value1' and 'value2' would both return '10', but they would be different dogs, and moreover, one of them isn't in the Map?

Also, why should the user be expected to find something that isn't in the Map anyway - the size() method will return a number that does not agree with the perceived number of dogs?

Surely hashCode and equals are only meant to find things that are in the Map, not object that linger outside it?
0
 
CEHJCommented:
Yes that's the whole point.  If "equals" and "hashCode" are implemented in the Dog class then the lookup for d5 will succeed because it'll find a Dog with color "red" and return that.  Which is what a caller would expect I think.

There's a little confusion here. In fact Dog with variable name 'd5' is not being looked up and 'returned' - it's being used as a key

SInce Dog is not overriding hashCode, then any number of "red" Dog instances can be used as keys.
0
 
dpearsonCommented:
it's being used as a key

Exactly.  We're talking about how keys work in hashmap, not values.

I'm not sure there's much to discuss here.  If you wish to use an object as a key in a map you should implement equals() and hashCode() on the class, so you can define what "equals" means for your objects.

If you don't do this you will get a map that's basically useless.

Most of the time though, you use an existing class as the key (e.g. an Integer or a String) and store the custom object as the value.  In that case there's no need for you to write equals() or hashCode() because somebody else from Sun already wrote the equals() and hashCode() methods for you for your key.

Map<Dog, String> <-- Dog should implement equals, hashCode()
Map<String, Dog> <-- No need for Dog to implement anything

Clearer?

Doug
0
 
zzynxSoftware engineerCommented:
I'll rephrase that:
When sorting is involved (by using TreeMap or calling Collections.sort(...)) => compareTo() is needed
When hashing is involved (by using HashMap) => equals() and hashCode() are needed
0
 
dpearsonCommented:
Not sure that's the best advice zzynx.
While a TreeMap needs compareTo(), I think to be well behaved, it should also implement equals and hence hashCode as well:

From the docs:
http://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html

Note that the ordering maintained by a tree map, like any sorted map, and whether or not an explicit comparator is provided, must be consistent with equals if this sorted map is to correctly implement the Map interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Map interface is defined in terms of the equals operation, but a sorted map performs all key comparisons using its compareTo (or compare) method, so two keys that are deemed equal by this method are, from the standpoint of the sorted map, equal. The behavior of a sorted map is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Map interface.

So I think the rule is maybe:

Any key going into a Map should implement equals() and hashCode().
Keys going into TreeMap also need to implement compareTo().

If you skip equals() and hashCode() implementations and just implement compareTo() then I think the JDK is basically saying "you're on your own and if things break in weird ways, don't call us".

Doug

P.S. From having a look at the TreeMap source code it appears the implementation of Map.Entry for a TreeMap relies on the keys implementing equals.  There may be other places.
0
 
zzynxSoftware engineerCommented:
While a TreeMap needs compareTo(), I think to be well behaved, it should also implement equals and hence hashCode as well.
You're probably right.

Can we conclude that the answer to the initial question
please advise on which scenarios compareTo() method is sufficient and which scenarios along with compareTo() we need to implement equals() and hashCode() and which scenarios we need to implement equals() and hashCode() without compareTo() method.
is not that straightforward?
0
 
dpearsonCommented:
Can we conclude that the answer...is not that straightforward?

Indeed we can!
0
 
gudii9Author Commented:
I realized i have big holes in understanding of collection concepts. i am trying to fill them. will conclude.
0
 
gudii9Author Commented:
i was looking for more working examples on this concept to digest this concept completely. i found below link
http://java67.blogspot.com/2013/04/example-of-overriding-equals-hashcode-compareTo-java-method.html
reading through it and re reading above posts
0
 
krakatoaCommented:
I'm not sure there's much to discuss here.

Seems some areas of doubt can arise.
0
 
krakatoaCommented:
gudii -

here is a bit more code that you can play with - maybe it will be good to change some params, and see the effects.

import java.util.*;


class Atlas {

private HashMap<Dog,Integer> hashmap;
private SortedMap<Dog,Integer> sortedmap;
private TreeMap<Dog,Integer> treemap;

private HashMap<Dog2,Integer> hashmap2;
private SortedMap<Dog2,Integer> sortedmap2;
private TreeMap<Dog2,Integer> treemap2;

static Atlas atlas,atlas2;
static String[] colours = {"red","brown","yellow","green","black","red"};
static Integer staticValue = new Integer(10);

	public static void main(String[] args){

		atlas = new Atlas();
		atlas.hashmap = new HashMap<Dog,Integer>();
		atlas.sortedmap = new TreeMap<Dog,Integer>();
		atlas.treemap = new TreeMap<Dog,Integer>();

		for (int a=0;a<6;a++){
		
			Dog d = new Dog(colours[a],new Integer(a+6));
			atlas.hashmap.put(d,staticValue);
			
		}
		
		for (int a=0;a<6;a++){
		
			Dog d = new Dog(colours[a],new Integer(a+6));
			atlas.sortedmap.put(d,staticValue);
		}
		
		
		for (int a=0;a<6;a++){
		
			Dog d = new Dog(colours[a],new Integer(a+6));
			atlas.treemap.put(d,staticValue);
		}
		
		
		System.out.println("hashmap size is "+atlas.hashmap.size()+" sortedmap size is "+atlas.sortedmap.size()+" treemap size is "+atlas.treemap.size());
		
		Set set4hash = atlas.hashmap.keySet();
		for (int a=0;a<6;a++){
			System.out.println(((Dog)(set4hash.toArray()[a])).colour);
		}
		
		Set set4sorted = atlas.sortedmap.keySet();
		for (int a=0;a<set4sorted.size();a++){
			System.out.println(((Dog)(set4sorted.toArray()[a])).colour);
		}
		
		Set set4tree = atlas.treemap.keySet();
		for (int a=0;a<set4tree.size();a++){
			System.out.println(((Dog)(set4tree.toArray()[a])).colour);
		}
		
		
		atlas2 = new Atlas();
		atlas2.hashmap2 = new HashMap<Dog2,Integer>();
		atlas2.sortedmap2 = new TreeMap<Dog2,Integer>();
		atlas2.treemap2 = new TreeMap<Dog2,Integer>();

		for (int a=0;a<6;a++){
		
			Dog2 d = new Dog2(colours[a],new Integer(a+6));
			atlas2.hashmap2.put(d,staticValue);
		}
		
		for (int a=0;a<6;a++){
		
			Dog2 d = new Dog2(colours[a],new Integer(a+6));
			atlas2.sortedmap2.put(d,staticValue);
		}
		
		
		for (int a=0;a<6;a++){
		
			Dog2 d = new Dog2(colours[a],new Integer(a+6));
			atlas2.treemap2.put(d,staticValue);
		}
		
		
		System.out.println("hashmap size is "+atlas2.hashmap2.size()+" sortedmap size is "+atlas2.sortedmap2.size()+" treemap size is "+atlas2.treemap2.size());
		
		Set set4hash2 = atlas2.hashmap2.keySet();
		for (int a=0;a<set4hash2.size();a++){
			System.out.println("Unsorted the Dog2s hashmap keys : "+((Dog2)(set4hash2.toArray()[a])).colour);
		}
		
		Set set4sorted2 = atlas2.sortedmap2.keySet();
		for (int a=0;a<set4sorted2.size();a++){
			System.out.println("Sorted the Dog2s sortedmap keys : "+((Dog2)(set4sorted2.toArray()[a])).colour);
		}
		
		Set set4tree2 = atlas2.treemap2.keySet();
		for (int a=0;a<set4tree2.size();a++){
			System.out.println("Sorted the Dog2s treemap keys : "+((Dog2)(set4tree2.toArray()[a])).colour);
		}
		
}


	static class Dog implements Comparable{
	
		public String colour;
		public Integer weight;

		public Dog(String col, Integer weit){
		
			this.colour = col;
			this.weight = weit;
		
		}
		
		public int compareTo(Object o){return ((Dog)o).colour.compareTo(this.colour);}
	
	}
	
	
	
	
	static class Dog2 implements Comparable{
	
		public String colour;
		public Integer weight;

		public Dog2(String col, Integer weit){
		
			this.colour = col;
			this.weight = weit;
		
		}
		
		public boolean equals(Object o){
			return this.colour.equals(((Dog2)o).colour);
		}
		
		
		public int hashCode(){
			return this.colour.hashCode();
		}
		
		public int compareTo(Object o){int ret;return ret = ((Dog2)o).colour.compareTo(this.colour)>0?-1:((Dog2)o).colour.compareTo(this.colour)<0?1:0;}
	
	}
	
}

Open in new window

0
 
gudii9Author Commented:
Sure
0
 
krakatoaCommented:
As you seem to still be having difficulties with this, here is my synopsis of how these methods operate inside HashMap, TreeMap and SortedMap implementations :

//-----------
You will not be able to put Dog class objects into a Tree- (or Sorted-) Map, unless they implement the Comparable interface. (You can put Dog objects not implementing Comparable into a HashMap, but it won't make any difference). Once in the TreeMap, the compareTo method on the object instances can be moderated or not. If it is unmoderated, the elements will be unsorted. If it is moderated correctly, the elements are returned in sorted order, irrespective of whether equals() and hashCode() are overridden or not.

If you do not override hashCode() and equals(), then the HashMap will include the duplicates (key value pairs). However, the Tree and Sorted Maps without equals() and hashCode() being overridden, but implementing Comparable, will not permit duplicates, and will still sort on a correctly-implemented compareTo(). If hashCode() and equals() ARE overridden, it has no further effect on the Tree- or Sorted Maps, but it does cause the HashMap to reject the duplicates.
//----------
0
 
krakatoaCommented:
This is a copy of the system.out.printlns from running the code I posted above, under changing conditions of the implementation, or not, of equals(), hashCode() and compareTo(), described in my previous post.

//-----

Original, typed-in order of colours in array = "red","brown","yellow","green","black","red"


hashCode() and equals() not overridden and unmoderated compareTo :

HASHMAP
yellow
red
black
red
brown
green

SORTEDMAP
yellow
red
green
brown
black

TREEMAP
yellow
red
green
brown
black


hashCode() and equals() not overridden and moderated compareTo  :

HASHMAP
yellow
red
black
red
brown
green

SORTEDMAP
black
brown
green
red
yellow

TREEMAP
black
brown
green
red
yellow



hashCode() and equals() overridden and unmoderated compareTo :

HASHMAP
red
green
yellow
black
brown

SORTEDMAP
yellow
red
green
brown
black

TREEMAP
yellow
red
green
brown
black




hashCode() and equals() overridden and moderated compareTo :

HASHMAP
red
green
yellow
black
brown

SORTEDMAP
black
brown
green
red
yellow

TREEMAP
black
brown
green
red
yellow
//-----
0
 
gudii9Author Commented:
moderated or unmoderated compareTo means what?
please advise
0
 
krakatoaCommented:
I mean whether you override it or not.

You can't override anything for Strings, because they are final objects. You can override the methods in the Map implementations however.
0
 
krakatoaCommented:
You should be sure you see what is going on in my comment ID: 40768295 above, because other comments in this question are liable to send you in the wrong direction - the lookup for this famous "d5" Dog is a complete red herring. "d5" never gets anywhere near the Map.
0
 
gudii9Author Commented:
i am still in confused state

my orignial questions remain unanswered to me

on which scenarios compareTo() method is sufficient?
 and which scenarios along with compareTo() we need to implement equals() and hashCode() ?
and which scenarios we need to implement equals() and hashCode() without compareTo() method?
 When we use comparator when we use comparable interfaces?

HashMap is Map implementation right nothing ot do with Set and List in which we usually talk about ordering(which i think is natural order) sorting(which i think custom sorting using comparator whose comapreTo() in turn use comparable compare() method right?)
unmoderated means unoverridden
moderated means overridden right?

why we have 3 for loops and staticValue in the code below

for (int a=0;a<6;a++){
		
			Dog d = new Dog(colours[a],new Integer(a+6));
			atlas.hashmap.put(d,staticValue);
			
		}
		
		for (int a=0;a<6;a++){
		
			Dog d = new Dog(colours[a],new Integer(a+6));
			atlas.sortedmap.put(d,staticValue);
		}
		
		
		for (int a=0;a<6;a++){
		
			Dog d = new Dog(colours[a],new Integer(a+6));
			atlas.treemap.put(d,staticValue);
		}

Open in new window


why are we crreating two different sets of object instances as below

private HashMap<Dog,Integer> hashmap;
private SortedMap<Dog,Integer> sortedmap;
private TreeMap<Dog,Integer> treemap;

private HashMap<Dog2,Integer> hashmap2;
private SortedMap<Dog2,Integer> sortedmap2;
private TreeMap<Dog2,Integer> treemap2;

Open in new window


why some give size 6 and some as 5. Is it due to reason below?

Set implementation do not take duplicates so will not maintain order for obvious reason unlike the List implementation
0
 
krakatoaCommented:
gudii92015-05-26 at 16:24:27ID: 40796556

I have already explained these points though in previous comments. In particular in this comment : 2015-05-09 at 12:47:47ID: 40768295

If you do not override hashCode() and equals(), then the HashMap will include the duplicates (key value pairs). However, the Tree and Sorted Maps without equals() and hashCode() being overridden, but implementing Comparable, will not permit duplicates, and will still sort on a correctly-implemented compareTo(). If hashCode() and equals() ARE overridden, it has no further effect on the Tree- or Sorted Maps, but it does cause the HashMap to reject the duplicates.
0
 
krakatoaCommented:
*A* dog, "red", (used as a key), will be found in the Map, but if you had instantiated two dogs colour "red", each keying to a different value (for example the Integer "10" for one value, and say "23" for the other)), you'd be in real trouble, because the second dog would overwrite the first as a Map entry, and so when you query the Map based on a "red" dog key instance, such as d5, you would not necessarily obtain the correct entry. This is what's known as a "false positive" - it's a silent killer, to be avoided at all costs. d5 (which never gets anywhere near the Map anyway) always looks as though it's in the Map, but it *isn't*. Any individual "red" dog may have other fields set which the programme relies on for calculations (the "value" part of the Map entry, to name but one, but there could be other fields in the dog instance which are set separately, and have nothing to do with equals()). This leads to completely wrong results.

So you have to ensure that if you implement equals(), you do so for ALL the fields that you are going to use for comparing the objects.
0
 
dpearsonCommented:

on which scenarios compareTo() method is sufficient?
 and which scenarios along with compareTo() we need to implement equals() and hashCode() ?
and which scenarios we need to implement equals() and hashCode() without compareTo() method?

I'm going to propose my original advice again:

Any key going into a Map should implement equals() and hashCode().
Keys going into TreeMap also need to implement compareTo().

If you want to include Sets too - they are generally implemented as Maps.  So it's the same advice:

Any key going into a Map (or Set) should implement equals() and hashCode().
Keys going into TreeMap (or TreeSet) also need to implement compareTo().

If you follow those 2 simple rules you should be fine.

Doug
0
 
gudii9Author Commented:
Any key going into a Map should implement equals() and hashCode().
key could be String or custom object i am assuming.
since you have not talked about 'value' iam assuming
Any value going into a Map should implement equals() and hashCode().

Keys going into TreeMap also need to implement compareTo().

public class Customer {
	String firstName;
	String lastName;
	int ssn;
	
	
	public Customer(String firstName, String lastName, int ssn) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.ssn = ssn;
	}
	public String getFirstName() {
		return this.firstName;
	}
	public String getLastName() {

		return this.lastName;
	}
	public int getSsn() {
		return this.ssn;
	}
}

Open in new window



import java.util.*;
public class LastNameComparator implements Comparator {

public int compare(Object o1, Object o2) {
Customer c1 = (Customer) o1;
Customer c2 = (Customer) o2;
int index = c1.getLastName().compareTo(c2.getLastName());
return -index;
}
}

Open in new window

import java.util.*;
public class CustomerSortTest {
	public static void main(String args[]) {
		//TreeSet set = new TreeSet(new LastNameComparator());
		TreeSet set = new TreeSet(new SsnComparator());
		set.add(new Customer("John", "Smith", 12345));
		set.add(new Customer("Laura", "Jackson", 456546));
		set.add(new Customer("Thomas", "Edison", 78989));
		Iterator itr = set.iterator();
		while (itr.hasNext()) {
			Customer customer = (Customer) itr.next();
			System.out.println(customer.getLastName() + " "
					+ customer.getFirstName() + " " + customer.getSsn());
		}
	}
}

Open in new window




import java.util.*;
public class SsnComparator implements Comparator<Customer> {

      @Override
      public int compare(Customer o1, Customer o2) {
            int ssn2=o1.getSsn();
          int ssn1=o1.getSsn();
      // TODO Auto-generated method stub
      int index = o1.getSsn().compareTo(o2.getSsn());
      return index;
      }
}
}
in above example i did not implement compareTo() though? Does implement means using compareTo() inside compare() right.

Also my SsnComparator not working. please advise
0
 
CEHJCommented:
Also my SsnComparator not working. please advise
http://technojeeves.com/index.php/aliasjava1/77-doesntwork
0
 
dpearsonCommented:
since you have not talked about 'value' iam assuming
Any value going into a Map should implement equals() and hashCode().
Nope.  The keys in a map need to implement equals() and hashCode().  The values do not need to.  Since you always look things up by key it's the one that needs to behave well.

To go back to our analogy of a library.  The key is the author's name.  When you get to the right shelf, the book itself is just sitting them and can be returned.  The book doesn't need special properties, it's the thing you're using to look it up (the author's name) that matters.

Just so we're clear, in a Set - the things you are storing are still keys.  A set is basically implemented like this:
Set<Key>
same as
Map<Key, Boolean> where Boolean.TRUE means the value is in the set.

So stuff going into a Set needs to obey the rules for keys in maps.

Doug
0
 
mccarlIT Business Systems Analyst / Software DeveloperCommented:
in above example i did not implement compareTo() though? Does implement means using compareTo() inside compare() right.
No, implementing compareTo() does NOT mean using compareTo() inside compare. You are talking about 2 different things here and complicating matters a little bit. Though if you want to try and understand all this, I will add a little something to Doug's previous statement...

Keys going into TreeMap also need to implement compareTo(). OR you need to supply a valid Comparator implementation to the TreeMap/TreeSet when you create it

So, even though you DIDN'T implement compareTo() in your Customer class, since you provided the Comparator (either LastNameComparator or SsnComparator) to the constructor of the TreeSet, that is ok.


Also my SsnComparator not working. please advise

You've implemented your SsnComparator assuming that getSsn() method in your Customer class returns an Integer object but it actually return a primitive int. So the problem is that you are trying to call .compareTo() on an int and that just can't work (an int isn't an object and so it doesn't have any methods to call).

To solve this, either change your Customer class to use Integer rather than int or otherwise, implement your SsnComparator like the below...

public class SsnComparator implements Comparator<Customer> {

      @Override
      public int compare(Customer o1, Customer o2) {
          return o1.getSsn() - o2.getSsn();
      }
}

Open in new window

0
 
gudii9Author Commented:
Smith John 12345
Edison Thomas 78989
Jackson Laura 456546


i got above output now. Is it is doing ascending order of SSN. How is it doing ascending order how to make descending order of SSN.

when i wrote like below

import java.util.*;
public class SsnComparator implements Comparator<Customer> {

	@Override
	public int compare(Customer o1, Customer o2) {
		//int ssn2=o1.getSsn();
	   // int ssn1=o1.getSsn();
	// TODO Auto-generated method stub
	int index = o1.getSsn().compareTo(o2.getSsn());
	return index;
	}
}

Open in new window


i got compilation error where as your code works well. I do not understand the difference returning result as index or returning whole thing o1.getSsn().compareTo(o2.getSsn());
I was thinking both wasy should work and produce same results. please advise
0
 
gudii9Author Commented:
Keys going into TreeMap also need to implement compareTo(). OR you need to supply a valid Comparator implementation to the TreeMap/TreeSet when you create it

I think i got good understanding of second approach with this example(OR you need to supply a valid Comparator implementation to the TreeMap/TreeSet when you create it). can you please point me to good simple example on 1st approach (Keys going into TreeMap also need to implement compareTo())
0
 
gudii9Author Commented:
To my eyes both these two looks same

//my code having errors
import java.util.*;
public class SsnComparator implements Comparator<Customer> {

	@Override
	public int compare(Customer o1, Customer o2) {
	//	int ssn2=o1.getSsn();
	  //  int ssn1=o1.getSsn();
	// TODO Auto-generated method stub
	int index = o1.getSsn().compareTo(o2.getSsn());
	return index;
	}
}

//How below code different from above code? your code which prints SSN ascending. How to make it descending??
public class SsnComparator implements Comparator<Customer> {

    @Override
    public int compare(Customer o1, Customer o2) {
        return o1.getSsn() - o2.getSsn();
    }
}

Open in new window

please advise why my above code is giving compilation errors?
0
 
gudii9Author Commented:
I see now issue with compareTo method in my code which is expecting object not primitive. How to make Ssn primitive to Object using wrapper class in below code so that i can still use compareTo to keep consistent with LastNameComparator, FirstNameComparator etc
public class Customer {
	String firstName;
	String lastName;
	int ssn;
	
	
	public Customer(String firstName, String lastName, int ssn) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.ssn = ssn;
	}
	public String getFirstName() {
		return this.firstName;
	}
	public String getLastName() {

		return this.lastName;
	}
	public int getSsn() {
		return this.ssn;
	}
}

Open in new window

please advise
0
 
gudii9Author Commented:
you need to supply a valid Comparator implementation to the TreeMap/TreeSet when you create it

i have this example of valid comparator on TreeSet. can you please point me to good simple example of valid comparator with TreeMap as well.
0
 
CEHJCommented:
return Integer.compare(o1.getSsn(), o2.getSsn());

Open in new window

will also do it
0
 
gudii9Author Commented:
yes
public class Customer {
	String firstName;
	String lastName;
	int ssn;
	
	
	public Customer(String firstName, String lastName, int ssn) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.ssn = ssn;
	}
	public String getFirstName() {
		return this.firstName;
	}
	public String getLastName() {

		return this.lastName;
	}
	public int getSsn() {
		return this.ssn;
	}
	
	
}

Open in new window



import java.util.*;
public class CustomerSortTest {
	public static void main(String args[]) {
		//TreeSet set = new TreeSet(new LastNameComparator());
		TreeSet set = new TreeSet(new SsnComparator());
		set.add(new Customer("John", "Smith", 12345));
		set.add(new Customer("Laura", "Jackson", 456546));
		set.add(new Customer("Thomas", "Edison", 78989));
		Iterator itr = set.iterator();
		while (itr.hasNext()) {
			Customer customer = (Customer) itr.next();
			System.out.println(customer.getLastName() + " "
					+ customer.getFirstName() + " " + customer.getSsn());
		}
	}
}

Open in new window


import java.util.*;
/*public class SsnComparator implements Comparator<Customer> {

	@Override
	public int compare(Customer o1, Customer o2) {
	//	int ssn2=o1.getSsn();
	  //  int ssn1=o1.getSsn();
	// TODO Auto-generated method stub
	int index = o1.getSsn().compareTo(o2.getSsn());
	return index;
	}
}*/


public class SsnComparator implements Comparator<Customer> {

    @Override
    public int compare(Customer o1, Customer o2) {
       // return -(o1.getSsn() - o2.getSsn());
    	return Integer.compare(o1.getSsn(), o2.getSsn());
    }
}

Open in new window



Above code worked perfect.

Now only other question in my mind is i want to make Ssn as object in Customer class by using Integer wrapper class and then use below compareTo() code

public int compare(Customer o1, Customer o2) {
      //      int ssn2=o1.getSsn();
        //  int ssn1=o1.getSsn();
      // TODO Auto-generated method stub
      int index = o1.getSsn().compareTo(o2.getSsn());
      return index;
      }


I am  not able to do in above approach to be consitent . I tried as below that is also not working
public class SsnComparator implements Comparator<Customer> {

    @Override
    public int compare(Customer o1, Customer o2) {
       // return -(o1.getSsn() - o2.getSsn());
    	
    	Customer c1 = (Customer) o1;
    	Customer c2 = (Customer) o2;
    	int index = c1.getSsn().toString().compareTo(c2.getSsn().toString());
    	
    	
    	return Integer.compare(o1.getSsn(), o2.getSsn());
    }
}

Open in new window


 please advise
0
 
CEHJCommented:
Customer c1 = (Customer) o1;

Open in new window

that cast is redundant

int index = c1.getSsn().toString().compareTo(c2.getSsn().toString());

Open in new window

is also redundant

The only code you need is HERE
0
 
gudii9Author Commented:
i got it so if it is int type (Ssn) then deal as primitive only rather than trying to conert to Object(Similar to LastName, FirstName String objects) using wrapper object
0
 
CEHJCommented:
Yes, you can leave it as primitive
0
 
gudii9Author Commented:
I am kind of summarizing what i got from this post. Please correct me wherever i am wrong


If I use TreeMap then no need to implement equals(), HashCode() even though key i used was object(Dog etc).(Since TreeMap knows how to sort already we do not need to worry of writing equals() and HashCode())

Where as If I use HashMap then there is need to implement equals(), HashCode() when i use key as object(Dog etc) otherwise all inserted objects may not come back similar to
import java.util.HashMap;
import java.util.Map;

public class TestMap{
      public static void main(String[] args) {
            //TreeMap<Dog, Integer> treeMap = new TreeMap<Dog, Integer>();
            Map<Dog, Integer> treeMap = new HashMap<>() ;
            Dog d1 = new Dog("red");

            treeMap.put(d1, 10);

            Dog d5 = new Dog("red") ;
            Integer value1 = treeMap.get(d1) ;
            Integer value2 = treeMap.get(d5) ;

            System.out.println("value1=" + value1 + " value2=" + value2);
      }
}

gave
value1=10 value2=null(which is wrong)



http://www.tutorialspoint.com/java/java_treemap_class.htm

When i need  custom sorting on the object say age using TreeMap( or any Map except HashTable, LinkedHashMap, HashMap ??)then pass the class implementing Comparator and Comparable

     // Sorts the array list using comparator
      Collections.sort(list, new Dog());


//here implement both Comparator() and Comparable()
class Dog implements Comparator<Dog>, Comparable<Dog>{


http://www.tutorialspoint.com/java/java_using_comparator.htm
http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html
for natural sorting order implementing comparable is enough (since strings implement by default we do not need to implement it explicity right...where as for StringBuilder object and custom objects like Dog we have to implemt)
For custom sorting order we use comparator from java.util which has compare() which internally calls comparable from java.lang compareTo() method.

0
 
krakatoaCommented:
For the sake of common sanity, all *I* can do is to re-iterate, for better or for worse, the comment I made here.
0
 
dpearsonCommented:
If I use TreeMap then no need to implement equals(), HashCode() even though key i used was object(Dog etc).(Since TreeMap knows how to sort already we do not need to worry of writing equals() and HashCode())

I think I've said this is wrong at least twice already in this answer.  Shall we try a third time?

Any key going into a Map (or Set) should implement equals() and hashCode().   <-- TreeMaps are still Maps
Keys going into TreeMap (or TreeSet) also need to implement compareTo() [or a custom Comparator]

If you don't implement equals() and hashCode() for keys going into a TreeMap then the Map will do what you expect in some situations and not do what you expect in others.  That's bad.

Remember, your IDE knows how to write these functions so adding them should take less than 10 seconds.  Do not try to cut corners here...

Doug
0
 
gudii9Author Commented:
import java.util.*;


class Atlas {

private HashMap<Dog,Integer> hashmap;
private SortedMap<Dog,Integer> sortedmap;
private TreeMap<Dog,Integer> treemap;

private HashMap<Dog2,Integer> hashmap2;
private SortedMap<Dog2,Integer> sortedmap2;
private TreeMap<Dog2,Integer> treemap2;

static Atlas atlas,atlas2;
static String[] colours = {"red","brown","yellow","green","black","red"};
static Integer staticValue = new Integer(10);

	public static void main(String[] args){

		atlas = new Atlas();
		atlas.hashmap = new HashMap<Dog,Integer>();
		atlas.sortedmap = new TreeMap<Dog,Integer>();
		atlas.treemap = new TreeMap<Dog,Integer>();

		for (int a=0;a<6;a++){
		
			Dog d = new Dog(colours[a],new Integer(a+6));
			atlas.hashmap.put(d,staticValue);
			
		}
		
		for (int a=0;a<6;a++){
		
			Dog d = new Dog(colours[a],new Integer(a+6));
			atlas.sortedmap.put(d,staticValue);
		}
		
		
		for (int a=0;a<6;a++){
		
			Dog d = new Dog(colours[a],new Integer(a+6));
			atlas.treemap.put(d,staticValue);
		}
		
		
		System.out.println("hashmap size is "+atlas.hashmap.size()+" sortedmap size is "+atlas.sortedmap.size()+" treemap size is "+atlas.treemap.size());
		
		Set set4hash = atlas.hashmap.keySet();
		for (int a=0;a<6;a++){
			System.out.println(((Dog)(set4hash.toArray()[a])).colour);
		}
		
		Set set4sorted = atlas.sortedmap.keySet();
		for (int a=0;a<set4sorted.size();a++){
			System.out.println(((Dog)(set4sorted.toArray()[a])).colour);
		}
		
		Set set4tree = atlas.treemap.keySet();
		for (int a=0;a<set4tree.size();a++){
			System.out.println(((Dog)(set4tree.toArray()[a])).colour);
		}
		
		
		atlas2 = new Atlas();
		atlas2.hashmap2 = new HashMap<Dog2,Integer>();
		atlas2.sortedmap2 = new TreeMap<Dog2,Integer>();
		atlas2.treemap2 = new TreeMap<Dog2,Integer>();

		for (int a=0;a<6;a++){
		
			Dog2 d = new Dog2(colours[a],new Integer(a+6));
			atlas2.hashmap2.put(d,staticValue);
		}
		
		for (int a=0;a<6;a++){
		
			Dog2 d = new Dog2(colours[a],new Integer(a+6));
			atlas2.sortedmap2.put(d,staticValue);
		}
		
		
		for (int a=0;a<6;a++){
		
			Dog2 d = new Dog2(colours[a],new Integer(a+6));
			atlas2.treemap2.put(d,staticValue);
		}
		
		
		System.out.println("hashmap size is "+atlas2.hashmap2.size()+" sortedmap size is "+atlas2.sortedmap2.size()+" treemap size is "+atlas2.treemap2.size());
		
		Set set4hash2 = atlas2.hashmap2.keySet();
		for (int a=0;a<set4hash2.size();a++){
			System.out.println("Unsorted the Dog2s hashmap keys : "+((Dog2)(set4hash2.toArray()[a])).colour);
		}
		
		Set set4sorted2 = atlas2.sortedmap2.keySet();
		for (int a=0;a<set4sorted2.size();a++){
			System.out.println("Sorted the Dog2s sortedmap keys : "+((Dog2)(set4sorted2.toArray()[a])).colour);
		}
		
		Set set4tree2 = atlas2.treemap2.keySet();
		for (int a=0;a<set4tree2.size();a++){
			System.out.println("Sorted the Dog2s treemap keys : "+((Dog2)(set4tree2.toArray()[a])).colour);
		}
		
}


	static class Dog implements Comparable{
	
		public String colour;
		public Integer weight;

		public Dog(String col, Integer weit){
		
			this.colour = col;
			this.weight = weit;
		
		}
		
		public int compareTo(Object o){return ((Dog)o).colour.compareTo(this.colour);}
	
	}
	
	
	
	
	static class Dog2 implements Comparable{
	
		public String colour;
		public Integer weight;

		public Dog2(String col, Integer weit){
		
			this.colour = col;
			this.weight = weit;
		
		}
		
		public boolean equals(Object o){
			return this.colour.equals(((Dog2)o).colour);
		}
		
		
		public int hashCode(){
			return this.colour.hashCode();
		}
		
		public int compareTo(Object o){int ret;return ret = ((Dog2)o).colour.compareTo(this.colour)>0?-1:((Dog2)o).colour.compareTo(this.colour)<0?1:0;}
	
	}
	
}

Open in new window


when i ran above code


i got below output

hashmap size is 6 sortedmap size is 5 treemap size is 5
black
green
brown
red
yellow
red
yellow
red
green
brown
black
yellow
red
green
brown
black
hashmap size is 5 sortedmap size is 5 treemap size is 5
Unsorted the Dog2s hashmap keys : red
Unsorted the Dog2s hashmap keys : green
Unsorted the Dog2s hashmap keys : brown
Unsorted the Dog2s hashmap keys : yellow
Unsorted the Dog2s hashmap keys : black
Sorted the Dog2s sortedmap keys : black
Sorted the Dog2s sortedmap keys : brown
Sorted the Dog2s sortedmap keys : green
Sorted the Dog2s sortedmap keys : red
Sorted the Dog2s sortedmap keys : yellow
Sorted the Dog2s treemap keys : black
Sorted the Dog2s treemap keys : brown
Sorted the Dog2s treemap keys : green
Sorted the Dog2s treemap keys : red
Sorted the Dog2s treemap keys : yellow



i have not got beloe output

hashCode() and equals() not overridden and unmoderated compareTo :

HASHMAP
yellow
red
black
red
brown
green

SORTEDMAP
yellow
red
green
brown
black

TREEMAP
yellow
red
green
brown
black


hashCode() and equals() not overridden and moderated compareTo  :

HASHMAP
yellow
red
black
red
brown
green

SORTEDMAP
black
brown
green
red
yellow

TREEMAP
black
brown
green
red
yellow



hashCode() and equals() overridden and unmoderated compareTo :

HASHMAP
red
green
yellow
black
brown

SORTEDMAP
yellow
red
green
brown
black

TREEMAP
yellow
red
green
brown
black




hashCode() and equals() overridden and moderated compareTo :

HASHMAP
red
green
yellow
black
brown

SORTEDMAP
black
brown
green
red
yellow

TREEMAP
black
brown
green
red
yellow
//-----

am i missing latest code?

please advise.
0
 
krakatoaCommented:
i have not got beloe output

. . .  when you say you have 'not got it', I assume you mean that you have not understood it, rather than you did not get the output that comes below it - since you have, by the looks of it, obtained the same output as the code intended.

What exactly do you not understand about the results the code produces?
0
 
krakatoaCommented:
Doug is right.

The fact that you not compelled to override them is potentially bad.
0
 
gudii9Author Commented:
i agree no matter what just use eclipse option and override equals() and hashCode() to be safe side
0
 
gudii9Author Commented:
my set and List concepts are fine now but Map related concepts  needs to be improved. I am closing this now. will ask any specific questions later
0
 
dpearsonCommented:
i agree no matter what just use eclipse option and override equals() and hashCode() to be safe side

Exactly!

Doug
0
 
krakatoaCommented:
I think you can see the effects of what comes out of overriding these methods or not, and maybe you need to keep re-running the code, and comparing the output with the source instructions. Here is a quick sketch I made of the scenario I described earlier, and how the methods hang together in the Maps.

Quick diagram of equals and hashcode effects
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 20
  • 16
  • 10
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now