I'm in the middle of QA'ing a bunch of code and have found several instances where the developer has a DTO which implements Comparable. This DTO has 7 or 8 fields in it. The compareTo method has been implemented on just one field:
private DateMidnight field1; //from Joda date/time library
public int compareTo(SomeObject o) {
if (o == null) {
return -1;
}
return field1.compareTo(o.getField1());
}
Similarly the equals method is overridden and basically boils down to:
return field1.equals(o.getField1());
and finally the hashcode method implementation is:
return field1.hashCode;
field1 should never be null and will be unique across these objects (i.e. we shouldn't get two objects with the same field1).
So, the implementations are consistent which is good, but should I be concerned that only one field is used? Is this unusual? Is it likely to cause problems or confuse other developers? I'm thinking of the scenario where a list of these objects are passed around and another developer uses a Map or Set of somesort and gets unusual behaviour from these objects. Any thoughts appreciated. Thanks!
I suspect that this is a case of "first use wins" - someone needed to sort a collection of these objects or put them in a hash map, and they only cared about the date. The easiest way of implementing that was to override equals/hashCode and implement Comparable<T> in the way you've said.
For specialist sorting, a better approach would be to implement Comparator<T> in a different class... but Java doesn't have any equivalent class for equality testing, unfortunately. I consider it a major weakness in the Java collections, to be honest.
Assuming this really isn't "the one natural and obvious comparison", it certainly smells in terms of design... and should be very carefully document.
Strictly speaking, this violates the Comparable spec:
http://download.oracle.com/javase/6/docs/api/java/lang/Comparable.html
Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.
Similarly, it looks like the equals method will throw NPE on equals(null) instead of returning false (unless of course you "boiled" out the null handling code).
Is it likely to cause problems or confuse other developers?
Possibly, possibly not. It really depends on how large your project is and how widespread/"reusable"/long-lived your object source code is expected to be used:
Small/short-lived/limited use == probably not a problem.
Large/long-lived/widespread use == counter-intuitive implementation may cause future problems
You shouldnt be concerned with it, if field1 is really unique. If it`s not, you may have problems. Anyway, my advise is to do some unit tests. They should show the truth.
I don't think you need to be concerned. The contract between the three methods is kept and it's consistent.
Whether it's correct from a business logic point of view is a different question.
If e.g. field1 maps to a primary key in the database it's perfectly valid. If field1 is the "firstname" of a person, I would be concerned
Related
I've read here why Optional.of() should be used over Optional.ofNullable(), but the answer didn't satisfy me at all, so I ask slightly different:
If you are SURE that your method does not return null, why should you use Optional at all? As far as I know, the more or less only purpose of it is to remind the "user of a method", that he might have to deal with null-values. If he does not have to deal with null-values, why should he be bothered with an Optional?
I ask, because I recently made my service-layer return Optionals instead of nulls (in certain situations). I used Optional.of() and was highly confused when it threw a NullPointer.
A sample of what I did:
Optional valueFromDB = getUserById("12");
User user = valueFromDB.get();
.....
public Optional<User> getUserById(String id) {
//...
return Optional.of(userRepository.findOne(id)); // NullPointerException!
}
If null is not possible, I don't see why one would wrap it in an Optional. The dude in the linked answer said "well, if a NullPointer happens, it happens right away!" But do I really want that? If the sole purpose of an Optional is, to remind the programmer who gets such an object, to keep null in mind (he HAS to unwrap it), why should I want to have NullPointerException at wrapping-time?
Edit: I needed to edit the question, because it got marked as duplicate, even though I already linked said question from the start. I also did explain, why the answer did not satisfy me, but now I need to edit my text with an explanation.
But here is some appendix to what I want to ask, since I got 5 answers and everyone answers a different case, but none fully covered what I try to ask here:
Is there a reason, that Optional.of(null) is impossible and they specifically added Optional.ofNullable() for the null case?
Using streams should not be the problem with my idea of the implementation.
I got a lot of insight from your answers, thanks for that. But the real question has not been answered until now, as far as I can tell/read/understand.
Maybe I should have asked: "What if we remove the Optional.of() method and only allow Optional.ofNullable() in Java 9, would there be any problem except backwards-compatibility?"
You are mixing up the API design rationale with knowledge within a particular implementation code. It’s perfectly possible that a method declares to return an Optional, because the value might be absent, while at a certain code location within the method, it is known to be definitely present. I.e.
String content;
public Optional<String> firstMatch(String pattern) {
Matcher m = Pattern.compile(pattern).matcher(content);
return m.find()? Optional.of(m.group()): Optional.empty();
}
This method’s return type denotes a String that might be absent, while at the code locations creating an Optional instance, it is known whether the value is present or absent. It’s not about detecting a null value here.
Likewise, within the Stream API methods findFirst() and findAny(), it will be known at one point, whether there is a matching element, whereas supporting the conversion of its presence to absence in case of a matching null element is explicitly unsupported and supposed to raise a NullPointerException, per specification. Therefore, Optional.of will be used to return the matching element, which you can easily recognize in the stack trace when using Stream.of((Object)null) .findAny();
The other reason to use Optional.of(value) when you know that value can't be null is that if you want to do additional filtering operations on that Optional.
For example:
public static long getPageSizeFrom(HttpServletRequest request) {
return Optional.of(request.getParameter("pageSize"))
.filter(StringUtils::isNumeric)
.map(Long::valueOf)
.filter(page::hasPageSize)
.orElse(page::getDefaultPageSize)
}
I think you are right with your opinion that you should not use Optional if you are sure that you always have a return-value.
But your method is not sure, that it always returns a value!
Think of an call to getUserById(-1). There is (normally) no User with this id, and your userRepository will return null.
So in this case you should use Optional.ofNullable.
https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#ofNullable-T-
Optional is one of those things that has been imported from functional programming languages and dumped into the laps of OO and procedural programmers without much background explanation...which has caused much pain and hand wringing.
First, a quick link to a blog post (not by me) which greatly helps to clear the air on this: The Design of Optional
Optional is related to functional programming types like Haskell Maybe. Because of the way strong typing works in functional programming, a programmer in that language would use Maybe to say that a value can be either Something, or Nothing. The Something and Nothing are actually different types, here. Anything that needs the values inside a Maybe has to handle both - the code simply won't compile if it doesn't handle both.
Compare that scenario to what is the typical situation in C-based object-oriented languages (Java, C#, C++, etc.) where an object can either have a value, or be null. If a method needs to handle null parameters as an edge case, you need to explicitly write that code - and being the lazy programmers we all are, it's just as often we don't bother to.
Imagine what coding would be like if code wouldn't compile unless null cases were always explicitly handled. That's a pretty close comparison to what happens when using Maybe in functional languages.
When we pull language features over from functional programming, and the compiler behaves the way it always has, and we code the way we always have... you can see there's a disconnect happening.
Separately, Optional can be used as a simple stand-in for null. Because it seems familiar that way, and is new, magpie developers are prone to using it as a replacement for situations where null-checks would have happened before. But, in the end, is foo.isPresent() really so different than foo != null. If that is the sole difference, it's pointless.
And let's not even get started on how Optional can be a stand-in for autoboxing and unboxing in Java.
Now, getting back to your specific question about the particular API of Optional in Java, comparing ofNullable() vs. of(), the best I can work out is that you probably aren't expected to use those in typical code. They are mainly used at the terminal end of stream() operations. You can look at the code to Optional.of() vs. Optional.ofNullable() and see for yourself that the only difference is that ofNullable checks if the value is null and arranges things for that situation.
My jaded eye doesn't see a whole lot of benefit to using Optional in Java, unless I am using Java 8 streams and I have to. Some would say that the main benefit of using Optional as a type for non-stream usage is to specify that a particular parameter is optional - that is, the logic takes a different route if it's there vs. not there. Which, again, you can simply do with null. But I would say that the mental baggage associated with Optional means that for every forward step of supposedly more verbose code, you are taking multiple steps backwards with requiring people to understand that the Optional (in this specific case) is almost entirely cosmetic. For the situation you described, I would probably go back to using nulls and null checks.
Angelika Langer says that Optional.ofNullable is only a convenience-method, calling the other both static methods from Optional. It is implemented as:
return value == null ? empty() : of(value) ;
Also she says that Optional.ofNullable was added lately to the API.
Here is her text in german language: http://www.angelikalanger.com/Articles/EffectiveJava/80.Java8.Optional-Result/80.Java8.Optional-Result.html
So I would use Optional.of only when null is an error, which should be found early. This is what Tagir Valeev said in:
Why use Optional.of over Optional.ofNullable?
The practical answer is: on most occasions, no. As you mention, if the whole point of using Optional is not knowing if a value can return null, and you want to make it explicit in certain API, the fact that .of() can throw a null exception does not make any sense. I always use ofNullable.
The only situation I can think of is if you have a method that returns Optional (to make explicit this null-value possibility), and that method has a default/fallback value under some circumstances, you will return a "default value" Optional, using .of().
public Optional<String> getSomeNullableValue() {
if (defaultSituationApplies()) { return Optional.of("default value"); }
else {
String value = tryToGetValueFromNetworkOrNull();
return Optional.ofNullable(value);
}
}
Then again, someone can question whether in that case you can return this default value in case of a null.
Metaphysical discussions aside, IMHO if you use Optionals, and want them to make any sense and not throw exceptions, use ofNullable().
I agree that Optional.of is counterintuitive and for most use cases you would want to use Optional.ofNullable, but there are various purposes for Optional.of:
To explicitly throw a NullPointerException if the value is null. In this case Optional.of functions as a Guard.
When the value simply cannot be null. For instance, constants like Optional.of("Hello world"!). This is a programming esthetics thing. Optional.ofNullable("Hello world!") looks weird.
To turn a non-null value into an Optional for further chaining with map or filter. This is more a programming convenience thing. Just like Optional.stream() exists to turn an Optional into a Stream for further chaining.
"What if we remove the Optional.of() method and only allow Optional.ofNullable() in Java 9, would there be any problem except backwards-compatibility?"
Yes, of course there will be compatibility issues. There's just too much code out there using Optional.of.
I agree with your general sentiment though: Optional.of is doing too much (wrapping the value and null-checking). For null-checks we already have Objects.requireNonNull which is conveniently overloaded to accept a descriptive text.
Optional.of and Optional.ofNullable should have been discarded in favor of a constructor made available for users:
return new Optional<>(value);
For null-checks this would have sufficed:
return new Optional<>(Objects.requireNonNull(value, "cannot be null!"));
As I've always understood it, the main cases where an instanceof is appropriate are:
Implementing Object.equals(Object). So if I were writing a List class, and not extending AbstractList for whatever reason, I would implement equals(o) by first testing o instanceof List, and then comparing elements.
A significant (algorithmic?) optimization for a special case that does not change semantics, but only performance. For example, Collections.binarySearch does an instanceof RandomAccess test, and uses a slightly different binary search for RandomAccess and non-RandomAccess lists.
I don't think instanceof represents a code smell in these two cases. But are there any other cases where it is sensible to use instanceof?
One way to answer your question would be to answer "when does a solid Java library use instanceof?" If we assume Guava is an example of a well designed Java library, we can look at where it uses instanceof to decide when it is acceptable to do.
If we extract the Guava source code jar and grep it, we see instanceof is mentioned 439 times, across 122 files:
$ pwd
/tmp/guava-13.0.1-sources
$ grep -R 'instanceof' | wc -l
439
$ grep -Rl 'instanceof' | wc -l
122
And looking at some of these cases we can see several patterns emerge:
To check for equality
This is the most common usage. This is somewhat implementation specific, but assuming you do in fact want to measure equality based on the class/interface it extends/implements, you can use instanceof to ensure the object your working with is . However this can potentially cause odd problems if a child class overrides equals() and doesn't respect the same instanceof requirements as the parent. Examples everywhere, but an easy one is Lists.equalsImpl() which is used by ImmutableList.
To short-circuit unnecessary object construction
You can use instanceof to check if the passed in argument can be safely used or returned without further transforming it, for instance if it's already an instance of the desired class, or if we know it's immutable. See examples in CharMatcher.forPredicate(), Suppliers.memoize(), ImmutableList.copyOf(), etc.
To access implementation-details without exposing different behavior
This can be seen all over the place in Guava, but notably in the static utility classes in the com.google.common.collect package, for instance in Iterables.size() where it calls Collection.size() if possible, and otherwise counts the number of items in the iterator in O(n) time.
To avoid calling toString()
I'm skeptical this merits being done in more than a very select few cases, but assuming you're sure you're doing the right thing, you can avoid needlessly converting CharSequence objects into Strings with instanceof, like is done in Joiner.toString(Object).
To do complex Exception handling
Obviously the "right" thing to do is use a try/catch block (though really, that's doing instanceof checks already), but sometimes you have more complex handling logic that merits using conditional blocks or passing processing off to a separate method, for instance pulling out causes or having implementation-specific processing. An example can be found in SimpleTimeLimiter.throwCause().
One thing that stands out looking at this behavior is nearly all of them are addressing problems I should not be solving. They're useful in library code, e.g. in Iterables, but if I'm implementing this behavior, I should probably be asking myself if there aren't libraries or utilities that solve this for me.
In all cases, I would say that instanceof checks should only ever be used internally as an implementation detail - that is to say the caller of any method that relies on an instanceof check should not be able to (easily) tell that's what you did. For instance, ImmutableList.copyOf() always returns an ImmutableList. As an implementation detail it uses instanceof to avoid constructing new ImmutableLists, but that is not necessary to acceptably provide the expected behavior.
As an aside, it was amusing coming across your name, Louis, as I was digging through Guava's source code. I swear I had no idea!
Legacy code or APIs outside of your control are a legitimate use-case for instanceof. (Even then I'd rather write an OO layer over it, but timing sometimes precludes a redesign like that.)
In particular, factories based on external class hierarchies seem a common usage.
Your first case is an example where I would not use the instanceof operator, but see whether the classes are equal:
o != null && o.getClass() == this.getClass()
This will avoid that an instance of A extends B and B are considered equal
Other cases I can immediately think of but I am pretty sure more valid cases are available
factory instances where you have for example a canCreate and create method which receive a general interface as parameter. Each of the factories can handle a specific implementation of the interface, so it would require an instanceof. Defining only the interface in the factory abstract class/interface allows for example to write a composite factory
composite implementations (as illustrated in my first example)
As you have mentioned, the "correct" uses of instanceof are rather limited. As far as I know, you have basically summed up the two main uses.
However you can generalize your statements a bit though as follows:
Type-checking before necessary casts.
Implementing special case scenarios that depend on very particular class instances
After reading this article , im bending toward not overriding equals() and hashCode() altogether.
In the summary of that article, concerning the no eq/hC at all column, the only consequence is that i couldnt do the comparison operations like :
contains() in a List for detached entities, or
compare the same entities from different sessions
and expect the correct result.
But im still in doubt and would like to ask your experiences about this whether it is a bad practice to skip equals and hashCode altogether and what other consequences that i still dont know for now.
Just another point of information, im bending towards using List Collections over Set. And my assumption is that i dont really need to override hashCode and equal when storing in a List.
Read this very nice article on the subject: Don't Let Hibernate Steal Your Identity.
The conclusion of the article goes like this:
Object identity is deceptively hard to implement correctly when
objects are persisted to a database. However, the problems stem
entirely from allowing objects to exist without an id before they are
saved. We can solve these problems by taking the responsibility of
assigning object IDs away from object-relational mapping frameworks
such as Hibernate. Instead, object IDs can be assigned as soon as the
object is instantiated. This makes object identity simple and
error-free, and reduces the amount of code needed in the domain model.
whether it is a bad practice to skip equals and hashCode altogether
Yes. You should always override your equals and hashCode. Period. The reason is that this method is present already in your class, implemented in Object. Turns out that this implementation is generic, and nearly 100% of the times it's a wrong implementation for your own objects. So, by skipping equals/hashCode you are in fact providing a wrong implementation and will (in the best case scenario) confuse whoever uses these classes. It may be your colleagues, or it may be some framework you are using (which can lead to unpredictable and hard-to-debug issues).
There's no reason to not implement these methods. Most IDEs provides a generator for equals/hashCode. You just need to inform the IDE about your business key.
You got the exact opposite conclusion from that article of what it was trying to convey.
Hibernate heavily relies on equals being implemented properly. It will malfunction if you don't.
In fact, almost everything does; including standard java collections.
The default implementation does not work when using persistence. You should always implement both equals and hashcode. There's a simple rule on how to do it, too:
For entities, use the key of the object.
For value objects, use the values
Always make sure the values you use in your equals/hashcode are immutable. If you pass these out (like in a getter), preferably pass them out in an immutable form.
This advice will improve your life :)
I recently watched this youtube tutorial on the Null Object design pattern. Even though there were some errors in it: such as the NullCar that doesn't do anything creates an infinite loop, the concept was well explained. My question is, what do you do when the objects that can be null have getters, and are used in your code? How do you know which value to return by default? Or should I implement this pattern inside all the objects? What if I need to return strings or primitives? I'm talking from a Java perspective.
EDIT: won't I be trading null objects testing for default value testing ? If not , why not ?
The objective of a Null Object is to avoid having Null references in the code. The values returned by Null Object getters depend on your domain. Zero or empty string are usually appropriate.
If we transpose the Null Object pattern to real life, what you're asking is similar to ask "how old is nobody ?".
Perhaps your design can be improved as you seem not to follow the tell, don't ask principle.
EDIT: the Null Object design pattern is typically used when an object delegates behavior to another object (such as in Strategy or State Design Patterns) ; as Tom Hawtin - tackline commented, use Special Case Objects for objects returning values.
As far as I've understood it the idea is that the null object's value is as close to "nothing" as possible. That unfortunately means you have to define it yourself. As an example I personally use "" when I can't pass a null String, null object number for me is -1 (mostly because by default most database sequences start at 1 and we use those for item id:s a lot so -1 is dead giveaway it's a null object), with lists/maps/sets it's Collections.EMPTY_SET, EMPTY_MAP or EMPTY_LIST and so on and so forth. If I have custom class I have to create a null object from, I remove all actual data from it and see where that takes me and then apply what I just mentioned until it's "empty".
So you really don't "know" which value to return by default, you just have to decide it by yourself.
what do you do when the objects that can be null have getters , and are used in your code ? How do you know which value to return by default ?
How do you know which classes to implement? This is a design question, it depends on the application.
Generally speaking the purpose of the NullObject pattern is to support a Replace Conditional with Polymorphism refactoring in the special case where the the conditional is a comparison against the null value of the programming language.
A correct implementation of the example in the video would require delegating the driveCar method to the Car classes. The SlowCar and FastCar classes would perform the loop, presumably through a shared implementation in a base class, and the NullCar would just return immediately.
In a Java context, the NullCar.speed attribute would probably be an unboxed int. So setting it to null is not an option. I would probably hide the attribute behind accessor, and have NullCar.getSpeed raise an exception. Any client code that would need a test to avoid this exception would instead move into the car classes.
Delegating all operations that directly depend on a speed value being available is an application of the Tell Don't Ask principle of object-oriented design mentioned by philippe
What should be the integration point of Null design pattern in code ? I think that DAO objects are the fisrt level client for this design pattern as they lookup an entity in database and return it simply.
The nullability check of these objects pollute the code in service layer or command layer where they are actually accessed and used.
Please comment.
It should return the null object for the class you are getting. For example, if you have a class A with a getter that returns an object of class B, then the corresponding NullA's getter should return NullB.
In a nutshell, the hashCode contract, according to Java's object.hashCode():
The hash code shouldn't change unless something affecting equals() changes
equals() implies hash codes are ==
Let's assume interest primarily in immutable data objects - their information never changes after they're constructed, so #1 is assumed to hold. That leaves #2: the problem is simply one of confirming that equals implies hash code ==.
Obviously, we can't test every conceivable data object unless that set is trivially small. So, what is the best way to write a unit test that is likely to catch the common cases?
Since the instances of this class are immutable, there are limited ways to construct such an object; this unit test should cover all of them if possible. Off the top of my head, the entry points are the constructors, deserialization, and constructors of subclasses (which should be reducible to the constructor call problem).
[I'm going to try to answer my own question via research. Input from other StackOverflowers is a welcome safety mechanism to this process.]
[This could be applicable to other OO languages, so I'm adding that tag.]
EqualsVerifier is a relatively new open source project and it does a very good job at testing the equals contract. It doesn't have the issues the EqualsTester from GSBase has. I would definitely recommend it.
My advice would be to think of why/how this might ever not hold true, and then write some unit tests which target those situations.
For example, let's say you had a custom Set class. Two sets are equal if they contain the same elements, but it's possible for the underlying data structures of two equal sets to differ if those elements are stored in a different order. For example:
MySet s1 = new MySet( new String[]{"Hello", "World"} );
MySet s2 = new MySet( new String[]{"World", "Hello"} );
assertEquals(s1, s2);
assertTrue( s1.hashCode()==s2.hashCode() );
In this case, the order of the elements in the sets might affect their hash, depending on the hashing algorithm you've implemented. So this is the kind of test I'd write, since it tests the case where I know it would be possible for some hashing algorithm to produce different results for two objects I've defined to be equal.
You should use a similar standard with your own custom class, whatever that is.
It's worth using the junit addons for this. Check out the class EqualsHashCodeTestCase http://junit-addons.sourceforge.net/ you can extend this and implement createInstance and createNotEqualInstance, this will check the equals and hashCode methods are correct.
I would recommend the EqualsTester from GSBase. It does basically what you want. I have two (minor) problems with it though:
The constructor does all the work, which I don't consider to be good practice.
It fails when an instance of class A equals to an instance of a subclass of class A. This is not necessarily a violation of the equals contract.
[At the time of this writing, three other answers were posted.]
To reiterate, the aim of my question is to find standard cases of tests to confirm that hashCode and equals are agreeing with each other. My approach to this question is to imagine the common paths taken by programmers when writing the classes in question, namely, immutable data. For example:
Wrote equals() without writing hashCode(). This often means equality was defined to mean equality of the fields of two instances.
Wrote hashCode() without writing equals(). This may mean the programmer was seeking a more efficient hashing algorithm.
In the case of #2, the problem seems nonexistent to me. No additional instances have been made equals(), so no additional instances are required to have equal hash codes. At worst, the hash algorithm may yield poorer performance for hash maps, which is outside the scope of this question.
In the case of #1, the standard unit test entails creating two instances of the same object with the same data passed to the constructor, and verifying equal hash codes. What about false positives? It's possible to pick constructor parameters that just happen to yield equal hash codes on a nonetheless unsound algorithm. A unit test that tends to avoid such parameters would fulfill the spirit of this question. The shortcut here is to inspect the source code for equals(), think hard, and write a test based on that, but while this may be necessary in some cases, there may also be common tests that catch common problems - and such tests also fulfill the spirit of this question.
For example, if the class to be tested (call it Data) has a constructor that takes a String, and instances constructed from Strings that are equals() yielded instances that were equals(), then a good test would probably test:
new Data("foo")
another new Data("foo")
We could even check the hash code for new Data(new String("foo")), to force the String to not be interned, although that's more likely to yield a correct hash code than Data.equals() is to yield a correct result, in my opinion.
Eli Courtwright's answer is an example of thinking hard of a way to break the hash algorithm based on knowledge of the equals specification. The example of a special collection is a good one, as user-made Collections do turn up at times, and are quite prone to muckups in the hash algorithm.
This is one of the only cases where I would have multiple asserts in a test. Since you need to test the equals method you should also check the hashCode method at the same time. So on each of your equals method test cases check the hashCode contract as well.
A one = new A(...);
A two = new A(...);
assertEquals("These should be equal", one, two);
int oneCode = one.hashCode();
assertEquals("HashCodes should be equal", oneCode, two.hashCode());
assertEquals("HashCode should not change", oneCode, one.hashCode());
And of course checking for a good hashCode is another exercise. Honestly I wouldn't bother to do the double check to make sure the hashCode wasn't changing in the same run, that sort of problem is better handled by catching it in a code review and helping the developer understand why that's not a good way to write hashCode methods.
You can also use something similar to http://code.google.com/p/guava-libraries/source/browse/guava-testlib/src/com/google/common/testing/EqualsTester.java
to test equals and hashCode.
If I have a class Thing, as most others do I write a class ThingTest, which holds all the unit tests for that class. Each ThingTest has a method
public static void checkInvariants(final Thing thing) {
...
}
and if the Thing class overrides hashCode and equals it has a method
public static void checkInvariants(final Thing thing1, Thing thing2) {
ObjectTest.checkInvariants(thing1, thing2);
... invariants that are specific to Thing
}
That method is responsible for checking all invariants that are designed to hold between any pair of Thing objects. The ObjectTest method it delegates to is responsible for checking all invariants that must hold between any pair of objects. As equals and hashCode are methods of all objects, that method checks that hashCode and equals are consistent.
I then have some test methods that create pairs of Thing objects, and pass them to the pairwise checkInvariants method. I use equivalence partitioning to decide what pairs are worth testing. I usually create each pair to be different in only one attribute, plus a test that tests two equivalent objects.
I also sometimes have a 3 argument checkInvariants method, although I finds that is less useful in findinf defects, so I do not do this often