Comparing two comparator objects in Java - java

If I do the following
myObject.myMethod(myClass.getComparator());
with
public void myMethod(Comparator<? super myOtherObject> comparator) {
if (comparator.equals(myClass.getComparator()) {
//do sth
}
}
and in myClass
static Comparator<ListItem> getComparator() {
return new Comparator<myOtherObject>() {
public int compare(myOtherObjectitem1, myOtherObjectitem2) {
return (Integer.valueOf(myOtherObject.getRating()).compareTo(Integer.valueOf(myOtherObject.getRating())));
}
};
}
then "//do sth" is not gonna be executed. So the objects I get from getComparator the two times are different. How can that be? Is there a chance to see, which comparator "myMethod" gets?

You're calling the equals method on this line:
if (comparator.equals(myClass.getComparator())
Since you haven't defined this method explicitly on your Comparator class (which is an anonymous inner class), this defaults to the version inherited from Object - which considers two references equal only if they are the exact same object.
And your getComparator() method states return new Comparator() { ... }, so it's calling the constructor and creating a new object each time it's called. Thus the result of one call to getComparator will be a distinct object, and hence will not be considered equal to, the result of another call.
I can think of two possible ways to change your code so that the equality test returns true:
Create the comparator only once, and return this same object from
getComparator. This would involve a change somewhat like the
following in myClass:
private static Comparator<ListItem> cmp = new Comparator<myOtherObject>() {
public int compare(myOtherObjectitem1, myOtherObjectitem2) {
return (Integer.valueOf(myOtherObject.getRating()).compareTo(Integer.valueOf(myOtherObject.getRating())));
}
};
static Comparator<ListItem> getComparator() {
return cmp;
}
Provide an explicit equals() implementation (and thus a hashCode() one too, ideally). You can then control exactly which objects are considered equal to one of your comparators. This might be much easier if you define a concrete class for your comparator rather than it being an anonymous inner class.
At the end of the day, though, I fear your approach might not be right. What does it mean for two comparators to be equal to one another? I feel this is an ambiguous concept for anything other than data classes, and I would be hesitant to use the Object.equals method for this.
(For example, if by equality you mean "they will sort lists in the same order", then I'd add a method to your comparator class called isEquivalentSortOrder or something similar. This way you can specify exactly what you mean without having to rely on the woolly definition of "being the same".)

Why not to create inside myClass static variable of Comparator like:
class myClass{
public static Comparator<ListItem> = new Comparator<myOtherObject>() {
public int compare(myOtherObjectitem1, myOtherObjectitem2) {
...
}
};
}

Related

How can I unit test a method with multiple internal calls to class I want to mock using EasyMock

I would like to unit test a method with multiple internal calls to a class I want to mock using EasyMock.
The test method actually runs 5 times and calls the mocked method.
During each loop, I will create some objects, all of the same class (let's say of class A).
The private method will call the mock object method that takes the instance of class A, evaluate it and return a result.
In the end, the public method will return a List of results.
I tried the standard EasyMock.expect(MockClass.method(A)).andReturn() but it does not work since there is no implementation of equals() for class A:
// this is the method example I am trying to test
public methodToTest(){
// some logic
privateMethodToTest(x);
// some logic
}
private List<B> privateMethodToTest(int x){
List<B> list = new ArrayList<>();
List<A> all = getObjects(x); //getObjects private method
for (A a:all){
list.add(objectToMock.methodToMock(a));
return list;
}
This is how I would like it to work:
EasyMock.createMock(ObjectToMock.class);
EasyMock.expect(ObjectToMock.methodToMock(A)/* when A.getValue() == 1 */.andReturn("B object number 1")
EasyMock.expect(ObjectToMock.methodToMock(A)/* when A.getValue() == 2 */.andReturn("B object number 2")
//... and so on
//object of class A does not implement equals()
I am not sure how to do it and I was not able to find any similar example or answer to my question.
You need another matcher. By default, EasyMock will indeed match using equals. But you can't do that. Your basic choices are:
You don't care about matching precisely
If seems to be the easiest for you. It means doing:
expect(objectToMock.methodToMock(anyObject()).andReturn("B object number 1");
expect(objectToMock.methodToMock(anyObject()).andReturn("B object number 2");
Use a comparator
According to your comment, you might actually prefer this
expect(mock.methodToTest(EasyMock.cmp(new A(1), Comparator.comparingInt(A::getValue), LogicalOperator.EQUAL))).andReturn(1);
The only problem is that you need a A with the correct value to compare with.
To have a simplified version, you can use your own matcher
The expectation using the custom matcher right below.
expect(mock.methodToTest(cmp(0))).andReturn(3);
public static <T> T cmp(int value) {
reportMatcher(new IArgumentMatcher() {
#Override
public boolean matches(Object argument) {
return value == ((A) argument).getValue();
}
#Override
public void appendTo(StringBuffer buffer) {
buffer.append("A.value=").append(value);
}
});
return null;
}
When unittesting we verify public observable behavior of the code under test, that is return values and communication with dependencies.
Anything else is implementation detail which we do not test. The reason is that you might want to refactor your code. That means you want to improve the structure of your code without changing its behavior. Your unittest schould verify that you did not change behavior accidentally. But they can only do this if you do not have to change them too.

How to switch sorting order in TreeSet

I have a custom class where I have implemented both Comparable and Comparator interface. The sorting/comparison logic is opposite for the two.
consider the below class as an example:
class Test implements Comparable<Test>, Comparator<Test>{
private Integer field;
public Test(Integer field){this.field = field;}
#Override
public int compareTo(Test obj){
return this.field.compareTo(obj.field);
}
#Override
public int compare(Test t1, Test t2){
return -t1.compareTo(t2);
}
//impl of equals, hashCode and toString omitted for this example
}
So when I add objects of Test to a TreeSet by default it is sorting by the implementation of the Comparable which is understood as per the JDK source. So is there any flag/switch to switch to the sorting represented by the Comparable implementation?
I do not want to pass another Comparator to the TreeSet constructor.
There is a misconception on your side:
A Comparable class has objects that can be compared against each other (for example by a container that wants to sort them
A Comparator is the thing that compares two objects of some class.
There is no need for you to make your class implement both.
And worse: remember that code communicates intent: the idea that your class implements both interfaces, but in "opposite" ways, that is very much counter intuitive. It will simply confuse your readers, and can lead to all kinds of bugs, just because your code does something that few experienced java developers would expect it to do. Never write code that surprises your readers (in a bad way).
Instead note that you can simply create a TreeSet using Collections.reverseOrder() for example! In other words: the fact that you defined how to compare two objects of Test allows you to use a default (reversing) comparator already.
Long story short: avoid "inventing" "clever" tricks to work around framework behavior. Instead, learn how the framework "ticks", and adapt to that. Don't fight the tide, flow with it.
Using the same object as both Comparator and Comparable is quite atypical. You can achieve both sort orders using just one of the two interfaces.
With just Comparator:
//Test implements Comparator. reversed() changes order
new TreeSet(new Test().reversed());
With just Comparable:
//elements are Comparable. reverseOrder changes order
new TreeSet(Comparator.reverseOrder());
If you use Comparator.comparingInt(Test::getField).reversed()) then you don't need to implement your own comparation methods to the Test class.
Full example code:
static class Test {
private int field;
public Test(int field) {
this.field = field;
}
public int getField() {
return field;
}
}
public static void main(String[] args) {
Test test = new Test(5);
Test test2 = new Test(8);
TreeSet<Test> tests = new TreeSet<>(Comparator.comparingInt(Test::getField).reversed());
tests.add(test);
tests.add(test2);
for (Test t:tests)
System.out.println(t.getField());
}
Outputs:
8
5

searching keys of subclass in HashMap

just tried to do something like:
public class GameMap {
protected HashMap<Sector, Integer[]> mapping;
protected void loadMapFromFile(String fileLocation, int numPlayers) {
.
//Other stuff
.
.
case "ALIENSECT":
Integer[] someValue = {5};
mapping.put(new AlienSector(row, col), someValue);
break;
}
public justATestMethod() {
System.out.println(mapping.containsKey(new Sector(6, 'L')));
}
Where AlienSector is a subclass of Sector.
But when I try to do this in another class:
mappa.justATestMethod();
The result is "false".
Instead if I rewrite the method "justATestMethod()" like this:
System.out.println(mapping.containsKey(new AlienSector(6, 'L')));
Result is "true".
I obtain "true" also changing this lines of "loadMapFromFile" method:
case "ALIENSECT":
Integer[] someValue = {5};
mapping.put(new AlienSector(row, col), someValue);
break;
This way:
case "ALIENSECT":
mapping.put(new Sector(row, col), new Integer[1]);
Integer[] aCazzo = {5};
mapping.put(new AlienSector(row, col), aCazzo);
break;
That is first filling the HashMap with Sector objects keys and then assigning keys of AlienSector objects.
Someone could explain me why this happens? AlienSector is a subclass of Sector, why Java doesn't recognize the presence of a Sector in the HashMap keys if I simply instantiate a subclass of it without first instantiate the key with an istance of the superclass "Sector" itself?
You are storing an AlienSector in the HashMap, and then trying to retrieve it with another Sector created using the same parameters. When you try to retrieve an object from a HashMap it is looking for an object that is 'equal' to the one you stored. But by default Java does not recognize two objects as 'equal' just because they have the same members. By default they are only equal if they are the same object (Strings, Integers etc. are special cases).
What you need to do is tell Java that two objects with the same parameters are 'equal' by overriding the 'equals' method. From your test results it looks like yo uhave done this for AlienSector. But you will need to do this for both Sector and AlienSector, and arrange it so the objects are considered equal even if they have different classes i.e. an AlienSector is considered equal to a Sector with the same members, and a Sector is considered equal to an AlienSector with the same members. There are tutorials on how to do this.
You will also need to override the hashCode() method to make sure that any two objects that would be considered 'equal' also return the same hashCode. HashMap uses hashCode a filter, deciding that things with different hashCodes can never be equal.
The details of all this are too long to put in an answer like this.
by the way, if you used the same object in the containsKey call, instead of creating a new one, you would find it worked.
You can use the class below to perform this behaviour.
One caveat to note is that if it is a large map, it may not be particularly performant, but for most cases the size of the map will be small so there is no real performance impact with this.
NOTE: JDK8+ code
Essentially we override the regular hashmap class methods for containsKey and get to do the appropriate searching.
import java.util.HashMap;
import java.util.Optional;
public class PolymorphicHashMap<K extends Class<?>,V> extends HashMap<K,V> {
#Override
public boolean containsKey(Object key) {
return findEntry((K)key).isPresent();
}
#Override
public V get(Object key) {
var entry = findEntry((K)key);
return entry.map(Entry::getValue).orElse(null);
}
private Optional<Entry<K,V>> findEntry(K key) {
return entrySet().stream()
.filter(e -> e.getKey().isAssignableFrom(key))
.findFirst();
}
}
HashMap uses the hashCode() function in order to lookup and store key/value pairs.
I believe you need to have both the superclass/subclass return the same hashcode in order to be able to lookup the keys of subclass in the HashMap.
public class AlienSector {
public int hashcode() {
//
// Generate a hashcode unique to this AlienSector object here
//
}
}
public class Sector {
public int hashCode() {
return super.hashCode(); // Return the same hashcode as the super class
}
}
As pointed out in the comment, the rule is that if you override the hashCode() function, you need to override the equals() function as well (and vice-versa)

Why does equals() in Java must be passed Object as a parameter?

When we override the equals() method in Java, I know that Object needs to be a parameter, but I wonder - why Object?.
Second, let us say we override hashcode() and implement equals(), but set the parameter in equals() to MyClass instead of Object (MyClass being the class whose equals() method we override). Will we still get the expected behavior if we use HashMap?
Update: Yes, it will be overloading instead of overriding. But what will happen if we use HashMap with overloaded equals()? Also, I don't find the answer in related posts. Or is it something obvious that I am missing?
If you write an equals() method whose parameter is not Object, you are overloading the method, not overriding it.
Now, as for HashMap - HashMap calls equals to compare keys. The type of the compared keys is Object. Therefore, if you define an equals() method with a parameter whose not Object, this method will be ignored by HashMap.
I tried the following code :
public class SomeClass
{
int privateMember;
// note it's important to override hashCode, since if the hashCode of two
// keys is not the same, equals() won't be called at all
public int hashCode ()
{
return privateMember;
}
public boolean equals (Object other)
{
if (other instanceof SomeClass) {
return this.privateMember==((SomeClass)other).privateMember;
}
else {
return false;
}
}
public static void main(String[] args)
{
HashMap<SomeClass,String> map = new HashMap<SomeClass,String>();
SomeClass s1 = new SomeClass ();
SomeClass s2 = new SomeClass ();
s1.priv=4;
s2.priv=4;
map.put (s1, "something");
if (map.containsKey (s2)) {
System.out.println ("found!");
} else {
System.out.println ("not found!");
}
}
}
This code outputs "found!".
Now, if you run the exact same code, but replace the equals method with :
public boolean equals (SomeClass other)
{
if (other instanceof SomeClass) {
return this.privateMember==((SomeClass)other).privateMember;
}
else {
return false;
}
}
The output will be "not found!", which means our equals method was ignored.
The collections use the equals and hashcode methods from the Object base class. Therefore you must override them in order for your custom class to provide an implementation. You can overload equals if you wish, and that would work for situations where some code knows that it's dealing with an instance of MyClass. However, this would be misleading.
All the collections classes are designed to work with instances of Object and Object provides a general purpose equals method.
You shouldn't really need to write an equals method directly. You can either generate one using your IDE, or use EqualsBuilder from Apache Commons (https://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/builder/EqualsBuilder.html) to help put it all together.

Hiding a constructor behind a static creator method?

I've recently discovered an interesting way to create a new instance of an object in Google Guava and Project Lombok: Hide a constructor behind a static creator method. This means that instead of doing new HashBiMap(), you do HashBiMap.create().
My question is why? What advantage do you have of hiding the constructor? To me I see absolutely no advantage of doing this, and it seems to break basic object creation principles. Since the beggining you create an object with new Object(), not some Object.createMe() method. This almost seems like creating a method for the sake of creating a method.
What do you gain from doing this?
There are a number of reasons why you might prefer a static factory method instead of a public constructor. You can read Item 1 in Effective Java, Second Edition for a longer discussion.
It allows the type of the object returned by the method to be different than the type of the class that contains the method. In fact, the type returned can depend on the parameters. For example, EnumSet.of(E) will return a different type if the emum type has very few elements vs if the enum type has many elements (Edit: in this particular case, improving performance for the common case where the enum doesn't have many elements)
It allows caching. For instance, Integer.valueOf(x) will, by default, return the same object instance if called multiple times with the same value x, if x is between -128 and 127.
It allows you to have named constructors (which can be useful if your class needs many constructors). See, for example, the methods in java.util.concurrent.Executors.
It allows you to create an API that is conceptually simple but actually very powerful. For instance, the static methods in Collections hides many types. Instead of having a Collections class with many static methods, they could have created many public classes, but that would have been harder for someone new to the language to understand or remember.
For generic types, it can limit how much typing you need to do. For example, instead of typing List<String> strings = new ArrayList<String>() in Guava you can do List<String> strings = Lists.newArrayList() (the newArrayList method is a generic method, and the type of the generic type is inferred).
For HashBiMap, the last reason is the most likely.
This is usually done because the class actually instantiated by the create() method might be different than the type upon which you are invoking the method. i.e. a factory pattern where the create() method returns a specific subclass that is appropriate given the current context. (For example, returning one instance when the currrent environment is Windows, and another when it is Linux).
Unlike constructors, static methods can have method names. Here's a recent class I wrote where this was useful:
/**
* A number range that can be min-constrained, max-constrained,
* both-constrained or unconstrained.
*/
public class Range {
private final long min;
private final long max;
private final boolean hasMin;
private final boolean hasMax;
private Range(long min, long max, boolean hasMin, boolean hasMax) {
// ... (private constructor that just assigns attributes)
}
// Static factory methods
public static Range atLeast (long min) {
return new Range(min, 0, true, false);
}
public static Range atMost (long max) {
return new Range(0, max, false, true);
}
public static Range between (long min, long max) {
return new Range(min, max, true, true);
}
public static Range unconstrained () {
return new Range (0, 0, false, false);
}
}
You couldn't do this using just constructors, as atLeast and atMost would have the exact same signature (they both take one long).
This is called a Factory method pattern. Where the factory lies within the class itself. Wikipedia describes it pretty well but here are a few snippets.
Factory methods are common in toolkits and frameworks where library code needs to create objects of types which may be subclassed by applications using the framework.
Parallel class hierarchies often require objects from one hierarchy to be able to create appropriate objects from another.
Well it would be possible for SomeClass.create() to pull an instance from a cache. new SomeClass() won't do that without some shenanigans.
It would be also be possible for create() to return any number of implementations of SomeClass. Basically, a Factory type of dealio.
Although not applicable to this particular code example, the practice of hiding the constructor behind a static method is Singleton Pattern. This is used when you want to ensure that a single instance of the class is created and used throughout.
There are many reasons to use this factory method pattern, but one major reason Guava uses it is that it lets you avoid using type parameters twice when creating a new instance. Compare:
HashBiMap<Foo, Bar> bimap = new HashBiMap<Foo, Bar>();
HashBiMap<Foo, Bar> bimap = HashBiMap.create();
Guava also makes good use of the fact that factory methods can have useful names, unlike constructors. Consider ImmutableList.of, ImmutableList.copyOf, Lists.newArrayListWithExpectedSize, etc.
It also takes advantage of the fact that factory methods don't necessarily have to create a new object. For instance, ImmutableList.copyOf, when given an argument that is itself an ImmutableList, will just return that argument rather than doing any actual copying.
Finally, ImmutableList's factory methods return (non-public) subclasses of ImmutableList such as EmptyImmutableList, SingletonImmutableList and RegularImmutableList depending on the arguments.
None of these things are possible with constructors.
i got very interesting reason to hide constructor check it and please let me know if there is any other alternative to achieve this
enter code here
Class A
{
String val;
protected A( )
{
}
protected A(String val)
{
this.val=val;
}
protected void setVal( String val)
{
this.val=val;
}
public String getVal()
{
return val;
}
}
class B extends A
{
B()
{
super();
}
public val setVal(String val)
{
super.val=val;
}
}
class C extends A
{
C(String val)
{
super(val);
}
}
Some main reasons
Primarily it gives you the power to instantiate a different (sub) class
Possibility to return null
It enables you to return an already existing object

Categories