TreeSet remove and comparator issue

Here is the situation:

I have stockexchange "Quote" objects with 4 fields, overridden hashCode() and equals() method (that only take into account 3 fields: price, quantity, exchange). Testing objects using quoteX.equals(quoteY) and hashCode() function properly.

In my app, I need to maintain a SortedSet of Quote objects. That is done by creating a Treeset<Quote>(quoteComp) where quoteComp is an object of class QuoteComparator that implements the Comparator interface.

Ordering objective is to compare Quote objects FIRST by their "price", THEN by their "exchange" according to a preferred exchange, e.g. if there are 2 quotes with same price and quantity, but their exchanges are different, the one with preferred exchange should come first!

Now comes the part where I am stuck.

The TreeSet and comparator work fine; Quotes are nicely kept in the right sequence. However I seem to have a problemremoving a Quote object as soon as a preferred exchange is set to something other than null..

What I don't understand is that the TreeSet uses the Comparatorboth for ordering the objects (which works great) but also for removing them. How can make sure a Quote object's Exchange is not compared to the preferredExchange if I am removing it? Can't seem to figure it out.

Feedback much appreciated.

publicclass Quote{

// private String side;

privatedouble price;

private String exchange;

privatelong quantity;

public Quote(double px,long qty, String mkt){

this.price = px;

this.exchange = mkt;

this.quantity = qty;

}

public Quote(double px,long qty, String mkt, Date time){

this.price = px;

this.exchange = mkt;

this.quantity = qty;

}

public String getExchange(){

return exchange;

}

publicvoid setExchange(String market){

this.exchange = market;

}

publicdouble getPrice(){

return price;

}

publicvoid setPrice(Double price){

this.price = price;

}

publiclong getQuantity(){

return quantity;

}

publicvoid setQuantity(Long quantity){

this.quantity = quantity;

}

privatestaticfinal String SEPARATOR ="|";

public String toString(){

return"Px:" + Double.toString(price) + SEPARATOR +"Qty:" + Long.toString(quantity)

+ SEPARATOR +"Exch:" + exchange;

}

publicboolean equals(Object obj){

boolean result =false;

if (obj ==this){

result =true;

}

if (!(objinstanceof Quote)){

result =false;

}

else{

Quote quote = (Quote)obj;

result = (price == quote.price

&& quantity == quote.quantity

&& exchange == quote.exchange) ?true :false;

}

return result;

}

publicvolatileint hashCode = 0;

publicint hashCode(){

if (hashCode == 0){

int result = 17;

int factor = 37;

result = factor*result + (int)quantity;

result = factor*result + (int)price;

result = factor*result + exchange.hashCode();

hashCode = result;

}

return hashCode;

}

}

import java.util.Comparator;

import java.util.SortedSet;

import java.util.TreeSet;

publicclass TreesetTest{

publicstaticvoid main(String[] args){

TreesetTest tt =new TreesetTest();

}

private String preferredExchange ="YYY";

public TreesetTest(){

QuoteComparator qc =new QuoteComparator();

SortedSet<Quote> set =new TreeSet<Quote>(qc);

// demonstrate ordering

Quote q =new Quote(16800D,200,"YYY");

set.add(q);

Quote q2 =new Quote(15000D,400,"XXX");

set.add(q2);

Quote q3 =new Quote(16500D,50,"YYY");

set.add(q3);

Quote q1 =new Quote(15000D,100,"YYY");

set.add(q1);

Quote q4 =new Quote(16500D,150,"XXX");

set.add(q4);

// --

// gets removed when pref exch is set to XXX

Quote r =new Quote(16800D,200,"YYY");

set.remove(r);

// gets removed when preferred exchange is set to YYY

Quote rr =new Quote(15000,400,"XXX");

set.remove(rr);

// both get removed when pref exch is null

for (Quote quote : set){

System.out.println(quote.toString());

}

}

publicclass QuoteComparatorimplements Comparator

{

privateboolean ascending =true;

publicint compare(Object objX, Object objY)

{

// cast!

Quote qX = (Quote)objX;

Quote qY = (Quote)objY;

int result = 0;

result = compareDouble(qX.getPrice(),qY.getPrice());

if (result == 0){

//both prices identical

if (preferredExchange !=null){

if (qX.getExchange().equals(preferredExchange)){

result = -1;

}

elseif (qY.getExchange().equals(preferredExchange)){

result = 1;

}

}

else{

// no preferred set, just compare exchange strings

result = compareString(qX.getExchange(),qY.getExchange());

}

}

return result;

}

privateint compareString(String val1, String val2){

// initialize strings if null, in order to compare!

if (val1 ==null){

val1 ="";

}

if (val2 ==null){

val2 ="";

}

return this.ascending ? val1.compareTo(val2) :

val2.compareTo(val1);

}

privateint compareDouble(Double d1, Double d2){

if (d1 !=null && d2 !=null){

return this.ascending ? d1.compareTo(d2) :

d2.compareTo(d1);

}

else{

return 0;

}

}

}

}

[11748 byte] By [metropolitana] at [2007-10-2 20:31:00]
# 1
Also, ignore the second constructor in Quote.
metropolitana at 2007-7-13 23:14:08 > top of Java-index,Core,Core APIs...
# 2

If you change any of those mutable fields, then the object's hash code changes. This means that if you add a Quote to the TreeSet and then change one of those fields, you've screwed it up. Now it has a different hash code and can't be found in the TreeSet when you look for it. (Because it was filed under the old hash code.) I don't think the comparator has anything to do with this.

DrClapa at 2007-7-13 23:14:08 > top of Java-index,Core,Core APIs...
# 3

The hashCode() is completely irrelevant to a TreeSet. However, changing the fields makes the Comparator return different results, so the Set really gets completely screwed! NEVER DO CHANGE fields relevant to Comparator for objects stored in a TreeMap. And never do change fields relevant to hashCode() or equals() for objects stored in a HashMap.

Maaartina at 2007-7-13 23:14:08 > top of Java-index,Core,Core APIs...
# 4

> The hashCode() is completely irrelevant to a TreeSet.

> However, changing the fields makes the Comparator

> return different results, so the Set really gets

> completely screwed! NEVER DO CHANGE fields relevant

> to Comparator for objects stored in a TreeMap. And

> never do change fields relevant to hashCode() or

> equals() for objects stored in a HashMap.

Or, when you do, remove and re-add the object.

jverda at 2007-7-13 23:14:08 > top of Java-index,Core,Core APIs...