How to implement Comparable so it is consistent with identity-equalityHow do I efficiently iterate over each entry in a Java Map?How do I read / convert an InputStream into a String in Java?How do I generate random integers within a specific range in Java?“implements Runnable” vs “extends Thread” in JavaComparing Java enum members: == or equals()?How does a ArrayList's contains() method evaluate objects?How do I convert a String to an int in Java?equals() vs compareTo() in Comparator/able (Theoretical)What does comparison being consistent with equals mean ? What can possibly happen if my class doesn't follow this principle?consequence of compare() method of Comparator interface not consistent with equals() method
Why was Sir Cadogan fired?
What is the opposite of "eschatology"?
How dangerous is XSS
Can a virus destroy the BIOS of a modern computer?
How to install cross-compiler on Ubuntu 18.04?
How seriously should I take size and weight limits of hand luggage?
Is it "common practice in Fourier transform spectroscopy to multiply the measured interferogram by an apodizing function"? If so, why?
What Exploit Are These User Agents Trying to Use?
How obscure is the use of 令 in 令和?
Can compressed videos be decoded back to their uncompresed original format?
Was the Stack Exchange "Happy April Fools" page fitting with the '90's code?
Can I hook these wires up to find the connection to a dead outlet?
How to travel to Japan while expressing milk?
Do Iron Man suits sport waste management systems?
Could the museum Saturn V's be refitted for one more flight?
Should I tell management that I intend to leave due to bad software development practices?
Ambiguity in the definition of entropy
What's the meaning of "Sollensaussagen"?
GFCI outlets - can they be repaired? Are they really needed at the end of a circuit?
Car headlights in a world without electricity
Why were 5.25" floppy drives cheaper than 8"?
One verb to replace 'be a member of' a club
Is this draw by repetition?
Did 'Cinema Songs' exist during Hiranyakshipu's time?
How to implement Comparable so it is consistent with identity-equality
How do I efficiently iterate over each entry in a Java Map?How do I read / convert an InputStream into a String in Java?How do I generate random integers within a specific range in Java?“implements Runnable” vs “extends Thread” in JavaComparing Java enum members: == or equals()?How does a ArrayList's contains() method evaluate objects?How do I convert a String to an int in Java?equals() vs compareTo() in Comparator/able (Theoretical)What does comparison being consistent with equals mean ? What can possibly happen if my class doesn't follow this principle?consequence of compare() method of Comparator interface not consistent with equals() method
I have a class for which equality (as per equals()
) must be defined by the object identity, i.e. this == other
.
I want to implement Comparable
to order such objects (say by some getName()
property). To be consistent with equals()
, compareTo()
must not return 0
, even if two objects have the same name.
Is there a way to compare object identities in the sense of compareTo
? I could compare System.identityHashCode(o)
, but that would still return 0
in case of hash collisions.
java equals comparator comparable
|
show 3 more comments
I have a class for which equality (as per equals()
) must be defined by the object identity, i.e. this == other
.
I want to implement Comparable
to order such objects (say by some getName()
property). To be consistent with equals()
, compareTo()
must not return 0
, even if two objects have the same name.
Is there a way to compare object identities in the sense of compareTo
? I could compare System.identityHashCode(o)
, but that would still return 0
in case of hash collisions.
java equals comparator comparable
compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such acompareTo
would be unusable
– Lino
yesterday
3
Which clause of the contract would be broken exactly?
– Balz Guenat
yesterday
Did you mean you want whenA
andB
havegetName()
equal, you don't care whetherA > B
orB > A
, but you want consistent result i.e. if for onceA > B
is true, thenA > B
is always true throughout the whole process lifetime?
– Ricky Mo
yesterday
@RickyMo right.
– Balz Guenat
yesterday
3
@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))
– Haem
yesterday
|
show 3 more comments
I have a class for which equality (as per equals()
) must be defined by the object identity, i.e. this == other
.
I want to implement Comparable
to order such objects (say by some getName()
property). To be consistent with equals()
, compareTo()
must not return 0
, even if two objects have the same name.
Is there a way to compare object identities in the sense of compareTo
? I could compare System.identityHashCode(o)
, but that would still return 0
in case of hash collisions.
java equals comparator comparable
I have a class for which equality (as per equals()
) must be defined by the object identity, i.e. this == other
.
I want to implement Comparable
to order such objects (say by some getName()
property). To be consistent with equals()
, compareTo()
must not return 0
, even if two objects have the same name.
Is there a way to compare object identities in the sense of compareTo
? I could compare System.identityHashCode(o)
, but that would still return 0
in case of hash collisions.
java equals comparator comparable
java equals comparator comparable
edited yesterday
Peter Mortensen
13.9k1987113
13.9k1987113
asked yesterday
Balz GuenatBalz Guenat
4472419
4472419
compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such acompareTo
would be unusable
– Lino
yesterday
3
Which clause of the contract would be broken exactly?
– Balz Guenat
yesterday
Did you mean you want whenA
andB
havegetName()
equal, you don't care whetherA > B
orB > A
, but you want consistent result i.e. if for onceA > B
is true, thenA > B
is always true throughout the whole process lifetime?
– Ricky Mo
yesterday
@RickyMo right.
– Balz Guenat
yesterday
3
@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))
– Haem
yesterday
|
show 3 more comments
compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such acompareTo
would be unusable
– Lino
yesterday
3
Which clause of the contract would be broken exactly?
– Balz Guenat
yesterday
Did you mean you want whenA
andB
havegetName()
equal, you don't care whetherA > B
orB > A
, but you want consistent result i.e. if for onceA > B
is true, thenA > B
is always true throughout the whole process lifetime?
– Ricky Mo
yesterday
@RickyMo right.
– Balz Guenat
yesterday
3
@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))
– Haem
yesterday
compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such a
compareTo
would be unusable– Lino
yesterday
compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such a
compareTo
would be unusable– Lino
yesterday
3
3
Which clause of the contract would be broken exactly?
– Balz Guenat
yesterday
Which clause of the contract would be broken exactly?
– Balz Guenat
yesterday
Did you mean you want when
A
and B
have getName()
equal, you don't care whether A > B
or B > A
, but you want consistent result i.e. if for once A > B
is true, then A > B
is always true throughout the whole process lifetime?– Ricky Mo
yesterday
Did you mean you want when
A
and B
have getName()
equal, you don't care whether A > B
or B > A
, but you want consistent result i.e. if for once A > B
is true, then A > B
is always true throughout the whole process lifetime?– Ricky Mo
yesterday
@RickyMo right.
– Balz Guenat
yesterday
@RickyMo right.
– Balz Guenat
yesterday
3
3
@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))
– Haem
yesterday
@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))
– Haem
yesterday
|
show 3 more comments
6 Answers
6
active
oldest
votes
I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.
If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.
In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.
8
A comparator seems like a non-broken solution. Even if the expectation ofComparable
is thatcompare==0
only when the two objects are equal, a comparator does not have that expectation.
– khelwood
yesterday
2
Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".
– Balz Guenat
yesterday
@BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)
– GhostCat
yesterday
1
@BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?
– GhostCat
yesterday
1
@Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make yourequals
consistent withcompareTo
you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.
– Voo
yesterday
|
show 6 more comments
You could add a second property (say int id
or long id
) which would be unique for each instance of your class (you can have a static
counter variable and use it to initialize the id
in your constructor).
Then your compareTo
method can first compare the names, and if the names are equal, compare the id
s.
Since each instance has a different id
, compareTo
will never return 0
.
1
This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.
– Balz Guenat
yesterday
@BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, theid
would have to be serialized.
– Eran
yesterday
1
"the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.
– Balz Guenat
yesterday
@BalzGuenat good point.
– Eran
yesterday
1
The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.
– kutschkem
yesterday
|
show 8 more comments
By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.
If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.
You could explain where to get that UUID, and why collision isn't a (practical) problem.
– Yakk - Adam Nevraumont
yesterday
@Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.
– Tezra
yesterday
add a comment |
Assuming that with two objects with same name, if equals()
returns false
then compareTo()
should not return 0. If this is what you want to do then following can help:
- Override
hashcode()
and make sure it doesn't rely solely onname
- Implement
compareTo()
as follows:
public void compareTo(MyObject object)
this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
Object.hashCode
has the same problem asSystem.identityHashCode
in that in case of a collision, compareTo will return 0 for two different objects.
– Balz Guenat
yesterday
That is the reason why I advised overridinghashcode()
and make it rely not just on name.
– Darshan Mehta
yesterday
any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.
– Balz Guenat
yesterday
add a comment |
You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.
private static Set<Pair<C, C> collisions = ...;
@Override
public boolean equals(C other)
return this == other;
@Override
public int compareTo(C other)
...
if (this == other)
return 0
if (super.equals(other))
// Some stable order would be fine:
// return either -1 or 1
if (collisions.contains(new Pair(other, this))
return 1;
else if (!collisions.contains(new Pair(this, other))
collisions.add(new Par(this, other));
return 1;
...
So go with the answer of Eran or put the requirement as such in question.
- One might consider the overhead of non-identical 0 comparisons neglectable.
- One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.
1
This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.
– Yakk - Adam Nevraumont
yesterday
@Yakk-AdamNevraumont true, just the mention ofstatic
should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?
– Joop Eggen
yesterday
1
Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.
– Voo
yesterday
@Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P
– Tezra
10 hours ago
@Tezra "Made to work", agreed that the current solution is not going to be correct.
– Voo
9 hours ago
add a comment |
While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".
Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)
import java.time.Instant;
import java.util.ArrayList;
import java.util.UUID;
public class Test implements Comparable<Test>
private final UUID antiCollisionProp = UUID.randomUUID();
private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();
private UUID getParanoiaLevelId(int i)
while(antiuniverseProp.size() < i)
antiuniverseProp.add(UUID.randomUUID());
return antiuniverseProp.get(i);
@Override
public int compareTo(Test o)
if(this == o)
return 0;
int temp = System.identityHashCode(this) - System.identityHashCode(o);
if(temp != 0)
return temp;
//If the universe hates you
temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
if(temp != 0)
return temp;
//If the universe is activly out to get you
temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
if(temp != 0)
return temp;
for(int i = 0; i < Integer.MAX_VALUE; i++)
UUID id1 = this.getParanoiaLevelId(i);
UUID id2 = o.getParanoiaLevelId(i);
temp = id1.compareTo(id2);
if(temp != 0)
return temp;
temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
if(temp != 0)
return temp;
// If you reach this point, I have no idea what you did to deserve this
throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55450569%2fhow-to-implement-comparable-so-it-is-consistent-with-identity-equality%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.
If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.
In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.
8
A comparator seems like a non-broken solution. Even if the expectation ofComparable
is thatcompare==0
only when the two objects are equal, a comparator does not have that expectation.
– khelwood
yesterday
2
Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".
– Balz Guenat
yesterday
@BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)
– GhostCat
yesterday
1
@BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?
– GhostCat
yesterday
1
@Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make yourequals
consistent withcompareTo
you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.
– Voo
yesterday
|
show 6 more comments
I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.
If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.
In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.
8
A comparator seems like a non-broken solution. Even if the expectation ofComparable
is thatcompare==0
only when the two objects are equal, a comparator does not have that expectation.
– khelwood
yesterday
2
Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".
– Balz Guenat
yesterday
@BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)
– GhostCat
yesterday
1
@BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?
– GhostCat
yesterday
1
@Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make yourequals
consistent withcompareTo
you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.
– Voo
yesterday
|
show 6 more comments
I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.
If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.
In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.
I think the real answer here is: don't implement Comparable then. Implementing this interface implies that your objects have a natural order. Things that are "equal" should be in the same place when you follow up that thought.
If at all, you should use a custom comparator ... but even that doesn't make much sense. If the thing that defines a < b ... is not allowed to give you a == b (when a and b are "equal" according to your < relation), then the whole approach of comparing is broken for your use case.
In other words: just because you can put code into a class that "somehow" results in what you want ... doesn't make it a good idea to do so.
answered yesterday
GhostCatGhostCat
95.5k1794160
95.5k1794160
8
A comparator seems like a non-broken solution. Even if the expectation ofComparable
is thatcompare==0
only when the two objects are equal, a comparator does not have that expectation.
– khelwood
yesterday
2
Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".
– Balz Guenat
yesterday
@BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)
– GhostCat
yesterday
1
@BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?
– GhostCat
yesterday
1
@Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make yourequals
consistent withcompareTo
you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.
– Voo
yesterday
|
show 6 more comments
8
A comparator seems like a non-broken solution. Even if the expectation ofComparable
is thatcompare==0
only when the two objects are equal, a comparator does not have that expectation.
– khelwood
yesterday
2
Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".
– Balz Guenat
yesterday
@BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)
– GhostCat
yesterday
1
@BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?
– GhostCat
yesterday
1
@Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make yourequals
consistent withcompareTo
you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.
– Voo
yesterday
8
8
A comparator seems like a non-broken solution. Even if the expectation of
Comparable
is that compare==0
only when the two objects are equal, a comparator does not have that expectation.– khelwood
yesterday
A comparator seems like a non-broken solution. Even if the expectation of
Comparable
is that compare==0
only when the two objects are equal, a comparator does not have that expectation.– khelwood
yesterday
2
2
Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".
– Balz Guenat
yesterday
Hm yes, I think what's really happening is that my objects really only have a partial ordering and I'm trying to force a total ordering using object identity. When I want to sort these objects, I can use a separate Comparator where it is not an issue if two different objects are "equal".
– Balz Guenat
yesterday
@BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)
– GhostCat
yesterday
@BalzGuenat That sounds like a reasonable approach. Especially given the fact that this will avoid the headaches you get when thinking how to properly implement a reasonable hashcode for your class ;-)
– GhostCat
yesterday
1
1
@BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?
– GhostCat
yesterday
@BalzGuenat But then you define your order to be TWO orders. What you are asking for ... isn't that different. Like merging an "order" with ... well, something that is not?
– GhostCat
yesterday
1
1
@Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make your
equals
consistent with compareTo
you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.– Voo
yesterday
@Balz Your problem is inherently different from chained comparators. Chained comparators are independent of each other, particularly the result of the first does not depend on the latter. If you want to make your
equals
consistent with compareTo
you'll have to violate one of the two contracts (there is btw. no requirement for equals being consistent with compareTo so that's your escape hatch if you wanted to - bad idea though). Even if you could represent object identity as a long you couldn't get around that.– Voo
yesterday
|
show 6 more comments
You could add a second property (say int id
or long id
) which would be unique for each instance of your class (you can have a static
counter variable and use it to initialize the id
in your constructor).
Then your compareTo
method can first compare the names, and if the names are equal, compare the id
s.
Since each instance has a different id
, compareTo
will never return 0
.
1
This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.
– Balz Guenat
yesterday
@BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, theid
would have to be serialized.
– Eran
yesterday
1
"the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.
– Balz Guenat
yesterday
@BalzGuenat good point.
– Eran
yesterday
1
The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.
– kutschkem
yesterday
|
show 8 more comments
You could add a second property (say int id
or long id
) which would be unique for each instance of your class (you can have a static
counter variable and use it to initialize the id
in your constructor).
Then your compareTo
method can first compare the names, and if the names are equal, compare the id
s.
Since each instance has a different id
, compareTo
will never return 0
.
1
This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.
– Balz Guenat
yesterday
@BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, theid
would have to be serialized.
– Eran
yesterday
1
"the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.
– Balz Guenat
yesterday
@BalzGuenat good point.
– Eran
yesterday
1
The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.
– kutschkem
yesterday
|
show 8 more comments
You could add a second property (say int id
or long id
) which would be unique for each instance of your class (you can have a static
counter variable and use it to initialize the id
in your constructor).
Then your compareTo
method can first compare the names, and if the names are equal, compare the id
s.
Since each instance has a different id
, compareTo
will never return 0
.
You could add a second property (say int id
or long id
) which would be unique for each instance of your class (you can have a static
counter variable and use it to initialize the id
in your constructor).
Then your compareTo
method can first compare the names, and if the names are equal, compare the id
s.
Since each instance has a different id
, compareTo
will never return 0
.
answered yesterday
EranEran
291k37479563
291k37479563
1
This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.
– Balz Guenat
yesterday
@BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, theid
would have to be serialized.
– Eran
yesterday
1
"the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.
– Balz Guenat
yesterday
@BalzGuenat good point.
– Eran
yesterday
1
The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.
– kutschkem
yesterday
|
show 8 more comments
1
This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.
– Balz Guenat
yesterday
@BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, theid
would have to be serialized.
– Eran
yesterday
1
"the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.
– Balz Guenat
yesterday
@BalzGuenat good point.
– Eran
yesterday
1
The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.
– kutschkem
yesterday
1
1
This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.
– Balz Guenat
yesterday
This sounds simple at first but becomes tricky once multiple threads create objects and the counter has to be synchronized. It would also complicate things if you wanted to (de)serialize objects, as the ID would have to be regenerated.
– Balz Guenat
yesterday
@BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, the
id
would have to be serialized.– Eran
yesterday
@BalzGuenat yes, the counter would have to be synchronized to support multiple threads. And as for (de)serialization, the
id
would have to be serialized.– Eran
yesterday
1
1
"the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.
– Balz Guenat
yesterday
"the id would have to be serialized." Well, no, because then you'd end up with multiple objects with the same ID. Say execution 1 of the program will create an object with ID 42, serializes it and stores it on disk. Execution 2 then creates its own object with ID 42 but also deserializes the object from execution 1, resulting in two objects with the same ID. There are solutions to this of course, but it gets way too complicated for the task at hand.
– Balz Guenat
yesterday
@BalzGuenat good point.
– Eran
yesterday
@BalzGuenat good point.
– Eran
yesterday
1
1
The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.
– kutschkem
yesterday
The second property can be the hashCode. And with using the hashCode, I think this is the correct answer as it implements an order relation that is consistent with the equals implementation.
– kutschkem
yesterday
|
show 8 more comments
By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.
If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.
You could explain where to get that UUID, and why collision isn't a (practical) problem.
– Yakk - Adam Nevraumont
yesterday
@Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.
– Tezra
yesterday
add a comment |
By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.
If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.
You could explain where to get that UUID, and why collision isn't a (practical) problem.
– Yakk - Adam Nevraumont
yesterday
@Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.
– Tezra
yesterday
add a comment |
By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.
If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.
By definition, by assigning each object a Universally unique identifier (UUID) (or a Globally unique identifier, (GUID)) as it's identity property, the UUID is comparable, and consistent with equals. Java already has a UUID class, and once generated, you can just use the string representation for persistence. The dedicated property will also insure that the identity is stable across versions/threads/machines. You could also just use an incrementing ID if you have a method of insuring everything gets a unique ID, but using a standard UUID implementation will protect you from issues from set merges and parallel systems generating data at the same time.
If you use anything else for the comparable, that means that it is comparable in a way separate from its identity/value. So you will need to define what comparable means for this object, and document that. For example, people are comparable by name, DOB, height, or a combination by order of precedence; most naturally by name as a convention (for easier lookup by humans) which is separate from if two people are the same person. You will also have to accept that compareto and equals are disjoint because they are based on different things.
edited yesterday
answered yesterday
TezraTezra
5,21321244
5,21321244
You could explain where to get that UUID, and why collision isn't a (practical) problem.
– Yakk - Adam Nevraumont
yesterday
@Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.
– Tezra
yesterday
add a comment |
You could explain where to get that UUID, and why collision isn't a (practical) problem.
– Yakk - Adam Nevraumont
yesterday
@Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.
– Tezra
yesterday
You could explain where to get that UUID, and why collision isn't a (practical) problem.
– Yakk - Adam Nevraumont
yesterday
You could explain where to get that UUID, and why collision isn't a (practical) problem.
– Yakk - Adam Nevraumont
yesterday
@Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.
– Tezra
yesterday
@Yakk-AdamNevraumont Added links and expanded a little. I didn't go into detail of the UUID because I want to stress more the "unique id" part. UUID is just an implementation provided by Java.
– Tezra
yesterday
add a comment |
Assuming that with two objects with same name, if equals()
returns false
then compareTo()
should not return 0. If this is what you want to do then following can help:
- Override
hashcode()
and make sure it doesn't rely solely onname
- Implement
compareTo()
as follows:
public void compareTo(MyObject object)
this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
Object.hashCode
has the same problem asSystem.identityHashCode
in that in case of a collision, compareTo will return 0 for two different objects.
– Balz Guenat
yesterday
That is the reason why I advised overridinghashcode()
and make it rely not just on name.
– Darshan Mehta
yesterday
any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.
– Balz Guenat
yesterday
add a comment |
Assuming that with two objects with same name, if equals()
returns false
then compareTo()
should not return 0. If this is what you want to do then following can help:
- Override
hashcode()
and make sure it doesn't rely solely onname
- Implement
compareTo()
as follows:
public void compareTo(MyObject object)
this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
Object.hashCode
has the same problem asSystem.identityHashCode
in that in case of a collision, compareTo will return 0 for two different objects.
– Balz Guenat
yesterday
That is the reason why I advised overridinghashcode()
and make it rely not just on name.
– Darshan Mehta
yesterday
any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.
– Balz Guenat
yesterday
add a comment |
Assuming that with two objects with same name, if equals()
returns false
then compareTo()
should not return 0. If this is what you want to do then following can help:
- Override
hashcode()
and make sure it doesn't rely solely onname
- Implement
compareTo()
as follows:
public void compareTo(MyObject object)
this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
Assuming that with two objects with same name, if equals()
returns false
then compareTo()
should not return 0. If this is what you want to do then following can help:
- Override
hashcode()
and make sure it doesn't rely solely onname
- Implement
compareTo()
as follows:
public void compareTo(MyObject object)
this.equals(object) ? this.hashcode() - object.hashcode() : this.getName().compareTo(object.getName());
answered yesterday
Darshan MehtaDarshan Mehta
23.6k32955
23.6k32955
Object.hashCode
has the same problem asSystem.identityHashCode
in that in case of a collision, compareTo will return 0 for two different objects.
– Balz Guenat
yesterday
That is the reason why I advised overridinghashcode()
and make it rely not just on name.
– Darshan Mehta
yesterday
any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.
– Balz Guenat
yesterday
add a comment |
Object.hashCode
has the same problem asSystem.identityHashCode
in that in case of a collision, compareTo will return 0 for two different objects.
– Balz Guenat
yesterday
That is the reason why I advised overridinghashcode()
and make it rely not just on name.
– Darshan Mehta
yesterday
any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.
– Balz Guenat
yesterday
Object.hashCode
has the same problem as System.identityHashCode
in that in case of a collision, compareTo will return 0 for two different objects.– Balz Guenat
yesterday
Object.hashCode
has the same problem as System.identityHashCode
in that in case of a collision, compareTo will return 0 for two different objects.– Balz Guenat
yesterday
That is the reason why I advised overriding
hashcode()
and make it rely not just on name.– Darshan Mehta
yesterday
That is the reason why I advised overriding
hashcode()
and make it rely not just on name.– Darshan Mehta
yesterday
any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.
– Balz Guenat
yesterday
any hash function, by definition, will have collisions, regardless of whether it relies on just the name or not.
– Balz Guenat
yesterday
add a comment |
You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.
private static Set<Pair<C, C> collisions = ...;
@Override
public boolean equals(C other)
return this == other;
@Override
public int compareTo(C other)
...
if (this == other)
return 0
if (super.equals(other))
// Some stable order would be fine:
// return either -1 or 1
if (collisions.contains(new Pair(other, this))
return 1;
else if (!collisions.contains(new Pair(this, other))
collisions.add(new Par(this, other));
return 1;
...
So go with the answer of Eran or put the requirement as such in question.
- One might consider the overhead of non-identical 0 comparisons neglectable.
- One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.
1
This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.
– Yakk - Adam Nevraumont
yesterday
@Yakk-AdamNevraumont true, just the mention ofstatic
should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?
– Joop Eggen
yesterday
1
Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.
– Voo
yesterday
@Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P
– Tezra
10 hours ago
@Tezra "Made to work", agreed that the current solution is not going to be correct.
– Voo
9 hours ago
add a comment |
You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.
private static Set<Pair<C, C> collisions = ...;
@Override
public boolean equals(C other)
return this == other;
@Override
public int compareTo(C other)
...
if (this == other)
return 0
if (super.equals(other))
// Some stable order would be fine:
// return either -1 or 1
if (collisions.contains(new Pair(other, this))
return 1;
else if (!collisions.contains(new Pair(this, other))
collisions.add(new Par(this, other));
return 1;
...
So go with the answer of Eran or put the requirement as such in question.
- One might consider the overhead of non-identical 0 comparisons neglectable.
- One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.
1
This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.
– Yakk - Adam Nevraumont
yesterday
@Yakk-AdamNevraumont true, just the mention ofstatic
should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?
– Joop Eggen
yesterday
1
Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.
– Voo
yesterday
@Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P
– Tezra
10 hours ago
@Tezra "Made to work", agreed that the current solution is not going to be correct.
– Voo
9 hours ago
add a comment |
You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.
private static Set<Pair<C, C> collisions = ...;
@Override
public boolean equals(C other)
return this == other;
@Override
public int compareTo(C other)
...
if (this == other)
return 0
if (super.equals(other))
// Some stable order would be fine:
// return either -1 or 1
if (collisions.contains(new Pair(other, this))
return 1;
else if (!collisions.contains(new Pair(this, other))
collisions.add(new Par(this, other));
return 1;
...
So go with the answer of Eran or put the requirement as such in question.
- One might consider the overhead of non-identical 0 comparisons neglectable.
- One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.
You are having unique objects, but as Eran said you may need an extra counter/rehash code for any collisions.
private static Set<Pair<C, C> collisions = ...;
@Override
public boolean equals(C other)
return this == other;
@Override
public int compareTo(C other)
...
if (this == other)
return 0
if (super.equals(other))
// Some stable order would be fine:
// return either -1 or 1
if (collisions.contains(new Pair(other, this))
return 1;
else if (!collisions.contains(new Pair(this, other))
collisions.add(new Par(this, other));
return 1;
...
So go with the answer of Eran or put the requirement as such in question.
- One might consider the overhead of non-identical 0 comparisons neglectable.
- One might look into ideal hash functions, if at some point of time no longer instances are created. This implies you have a collection of all instances.
edited yesterday
answered yesterday
Joop EggenJoop Eggen
78.8k755105
78.8k755105
1
This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.
– Yakk - Adam Nevraumont
yesterday
@Yakk-AdamNevraumont true, just the mention ofstatic
should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?
– Joop Eggen
yesterday
1
Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.
– Voo
yesterday
@Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P
– Tezra
10 hours ago
@Tezra "Made to work", agreed that the current solution is not going to be correct.
– Voo
9 hours ago
add a comment |
1
This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.
– Yakk - Adam Nevraumont
yesterday
@Yakk-AdamNevraumont true, just the mention ofstatic
should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?
– Joop Eggen
yesterday
1
Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.
– Voo
yesterday
@Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P
– Tezra
10 hours ago
@Tezra "Made to work", agreed that the current solution is not going to be correct.
– Voo
9 hours ago
1
1
This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.
– Yakk - Adam Nevraumont
yesterday
This is basically a resource leak; anything that every collided has its lifetime extended to the end of the program. Thanks however, I can use this as a good example of why garbage collection doesn't imply no resource leaks.
– Yakk - Adam Nevraumont
yesterday
@Yakk-AdamNevraumont true, just the mention of
static
should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?– Joop Eggen
yesterday
@Yakk-AdamNevraumont true, just the mention of
static
should trigger an immediate nausea. "So go with the answer of Eran". The code was just a temptative argument. There is something fishy here, Eran's solution is probably also not what is actually desired. Does the OP want an ideal hash function?– Joop Eggen
yesterday
1
1
Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.
– Voo
yesterday
Contrary to all other solutions this can at least be made to work correctly without violating either equals or compareTo contracts. Although if your solution involves WeakHashMaps you already have much bigger problems.
– Voo
yesterday
@Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P
– Tezra
10 hours ago
@Voo but compareTo only returns 0 or 1... Is the second 1 supposed to be -1 or is there a return -1 missing? Also would probably be more efficient to just remove static and just use system.idenity on that object to resolve collisions. If you have 2 collisions, that should prove god hates you. =P
– Tezra
10 hours ago
@Tezra "Made to work", agreed that the current solution is not going to be correct.
– Voo
9 hours ago
@Tezra "Made to work", agreed that the current solution is not going to be correct.
– Voo
9 hours ago
add a comment |
While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".
Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)
import java.time.Instant;
import java.util.ArrayList;
import java.util.UUID;
public class Test implements Comparable<Test>
private final UUID antiCollisionProp = UUID.randomUUID();
private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();
private UUID getParanoiaLevelId(int i)
while(antiuniverseProp.size() < i)
antiuniverseProp.add(UUID.randomUUID());
return antiuniverseProp.get(i);
@Override
public int compareTo(Test o)
if(this == o)
return 0;
int temp = System.identityHashCode(this) - System.identityHashCode(o);
if(temp != 0)
return temp;
//If the universe hates you
temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
if(temp != 0)
return temp;
//If the universe is activly out to get you
temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
if(temp != 0)
return temp;
for(int i = 0; i < Integer.MAX_VALUE; i++)
UUID id1 = this.getParanoiaLevelId(i);
UUID id2 = o.getParanoiaLevelId(i);
temp = id1.compareTo(id2);
if(temp != 0)
return temp;
temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
if(temp != 0)
return temp;
// If you reach this point, I have no idea what you did to deserve this
throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
add a comment |
While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".
Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)
import java.time.Instant;
import java.util.ArrayList;
import java.util.UUID;
public class Test implements Comparable<Test>
private final UUID antiCollisionProp = UUID.randomUUID();
private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();
private UUID getParanoiaLevelId(int i)
while(antiuniverseProp.size() < i)
antiuniverseProp.add(UUID.randomUUID());
return antiuniverseProp.get(i);
@Override
public int compareTo(Test o)
if(this == o)
return 0;
int temp = System.identityHashCode(this) - System.identityHashCode(o);
if(temp != 0)
return temp;
//If the universe hates you
temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
if(temp != 0)
return temp;
//If the universe is activly out to get you
temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
if(temp != 0)
return temp;
for(int i = 0; i < Integer.MAX_VALUE; i++)
UUID id1 = this.getParanoiaLevelId(i);
UUID id2 = o.getParanoiaLevelId(i);
temp = id1.compareTo(id2);
if(temp != 0)
return temp;
temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
if(temp != 0)
return temp;
// If you reach this point, I have no idea what you did to deserve this
throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
add a comment |
While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".
Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)
import java.time.Instant;
import java.util.ArrayList;
import java.util.UUID;
public class Test implements Comparable<Test>
private final UUID antiCollisionProp = UUID.randomUUID();
private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();
private UUID getParanoiaLevelId(int i)
while(antiuniverseProp.size() < i)
antiuniverseProp.add(UUID.randomUUID());
return antiuniverseProp.get(i);
@Override
public int compareTo(Test o)
if(this == o)
return 0;
int temp = System.identityHashCode(this) - System.identityHashCode(o);
if(temp != 0)
return temp;
//If the universe hates you
temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
if(temp != 0)
return temp;
//If the universe is activly out to get you
temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
if(temp != 0)
return temp;
for(int i = 0; i < Integer.MAX_VALUE; i++)
UUID id1 = this.getParanoiaLevelId(i);
UUID id2 = o.getParanoiaLevelId(i);
temp = id1.compareTo(id2);
if(temp != 0)
return temp;
temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
if(temp != 0)
return temp;
// If you reach this point, I have no idea what you did to deserve this
throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
While I stick by my original answer that you should use a UUID property for a stable and consistent compare / equality setup, I figured I'd go ahead an answer the question of "how far could you go if you were REALLY paranoid and wanted a guaranteed unique identity for comparable".
Basically, in short if you don't trust UUID uniqueness or identity uniqueness, just use as many UUIDs as it takes to prove god is actively conspiring against you. (Note that while not technically guaranteed not to throw an exception, needing 2 UUID should be overkill in any sane universe.)
import java.time.Instant;
import java.util.ArrayList;
import java.util.UUID;
public class Test implements Comparable<Test>
private final UUID antiCollisionProp = UUID.randomUUID();
private final ArrayList<UUID> antiuniverseProp = new ArrayList<UUID>();
private UUID getParanoiaLevelId(int i)
while(antiuniverseProp.size() < i)
antiuniverseProp.add(UUID.randomUUID());
return antiuniverseProp.get(i);
@Override
public int compareTo(Test o)
if(this == o)
return 0;
int temp = System.identityHashCode(this) - System.identityHashCode(o);
if(temp != 0)
return temp;
//If the universe hates you
temp = this.antiCollisionProp.compareTo(o.antiCollisionProp);
if(temp != 0)
return temp;
//If the universe is activly out to get you
temp = System.identityHashCode(this.antiCollisionProp) - System.identityHashCode(o.antiCollisionProp);;
if(temp != 0)
return temp;
for(int i = 0; i < Integer.MAX_VALUE; i++)
UUID id1 = this.getParanoiaLevelId(i);
UUID id2 = o.getParanoiaLevelId(i);
temp = id1.compareTo(id2);
if(temp != 0)
return temp;
temp = System.identityHashCode(id1) - System.identityHashCode(id2);;
if(temp != 0)
return temp;
// If you reach this point, I have no idea what you did to deserve this
throw new IllegalStateException("RAGNAROK HAS COME! THE MIDGARD SERPENT AWAKENS!");
edited 10 hours ago
answered 10 hours ago
TezraTezra
5,21321244
5,21321244
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55450569%2fhow-to-implement-comparable-so-it-is-consistent-with-identity-equality%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
compareTo() must not return 0, even if two objects have the same name., This will break the contract of compareTo, and thus such a
compareTo
would be unusable– Lino
yesterday
3
Which clause of the contract would be broken exactly?
– Balz Guenat
yesterday
Did you mean you want when
A
andB
havegetName()
equal, you don't care whetherA > B
orB > A
, but you want consistent result i.e. if for onceA > B
is true, thenA > B
is always true throughout the whole process lifetime?– Ricky Mo
yesterday
@RickyMo right.
– Balz Guenat
yesterday
3
@Lino: It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))
– Haem
yesterday