• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Tim Cooke
  • Jeanne Boyarsky
  • Bear Bibeault
Sheriffs:
  • Knute Snortum
  • paul wheaton
  • Devaka Cooray
Saloon Keepers:
  • Tim Moores
  • Stephan van Hulst
  • Ron McLeod
  • Piet Souris
  • Ganesh Patekar
Bartenders:
  • Tim Holloway
  • Carey Brown
  • salvin francis

Implementing the Comparator interface

 
Ranch Hand
Posts: 247
3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Source of code snippets:
Java 8 in Action: Lambdas, streams, and functional-style programming
(Raoul-Gabriel Urma, Mario Fusco, and Alan Mycroft)
Page 57.


The anonymouse class can be replace with a lambda expression as in:

The Comaparator interface has two abstract methods and for this reason, the Comparator is not a functional interface.
1.  I thought that when an interface is implemented, all the abstract methods must be overriden. We are not suppose to pick and choose which abstract method to override.  In the above anonymous class, the equals() method was not overridden. Is it the case that the instance created from the anonymous class embeds the abstract equals() method; making the instance an abstract instance? Really, abstract instance?

2.  Again, I thought that a lambda expression is used to implement a functional interface and at the same time create an instance of the implementation.  This means a lambda expression cannot be used to implement a Comparator let alone create an instance of the implementation.  Besides, the right hand side of the lambda expression evaluates to an instance of a BiFunction<Apple, Apple, Integer>. How does a Bifunction become a Comparator?  
I assume the book is autoritative, but these things are kind of confusing.
 
Rancher
Posts: 1039
6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
java.util Interface Comparator<T>

Functional Interface:
This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.
 
Ivan Jozsef Balazs
Rancher
Posts: 1039
6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
"equals" is inherited from Object. The other methods of Comparator are static or default.  
 
Biniman Idugboe
Ranch Hand
Posts: 247
3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, that is what the documentation says.  However, there two abstract methods in the Comparator interface.  The lambda expression only provides a body for the compare( ) method.  What about the equals( ) method? Can we implement an interface that has multiple abstract methods with a lambda expression? Are we allowed to provide a body for one of the multiple abstract methods and forget about the other abstract methods? A class (whether anonymous or not) that has any abstract method is an abstract class.  Can we have abstract instance?
 
Rancher
Posts: 100
6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This should be helpful:

If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface's abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere.



source
 
Saloon Keeper
Posts: 10523
224
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Biniman Idugboe wrote:In the above anonymous class, the equals() method was not overridden.


It was. Lambda expressions create an object that inherits from the Object class, so it also inherits the implementations of the methods declared in Object. Functional interfaces are allowed to redeclare the methods that were already declared in Object and the effect will be the same as if they weren't declared at all. The only reason to do this is if you want to add extra information to the method documentation. You'll notice when you read the JavaDoc that Comparator.equals() has a more specific description than Object.equals().

Besides, the right hand side of the lambda expression evaluates to an instance of a BiFunction<Apple, Apple, Integer>. How does a Bifunction become a Comparator?


It doesn't. It never was a BiFunction to begin with. The return type of a lambda expression depends on the context it was called in. It was called in a context where a Comparator was expected, so it will return a Comparator. All that's necessary is that the lamba's parameters and return value correspond to the parameters and return type of the abstract method in the functional interface.
 
Stephan van Hulst
Saloon Keeper
Posts: 10523
224
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Biniman Idugboe wrote:Can we implement an interface that has multiple abstract methods with a lambda expression?


Only if there is exactly one abstract method that is not implemented by Object.

Are we allowed to provide a body for one of the multiple abstract methods and forget about the other abstract methods?


No. You must always provide a body for the method that doesn't inherit its implementation from Object, which in Comparator's case is compare().
 
Biniman Idugboe
Ranch Hand
Posts: 247
3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Lambda expressions create an object that inherits from the Object class, so it also inherits the implementations of the methods declared in Object.


The Object class does not have any abstract method. I have not read the documentation in much detail, but I do not know whether the Comparator interface extends the Object class.  I was of the opinion that the equals( ) method in Object class is different from the equals( ) method in Comparator interface. Looks like they are not different after all.  Is it the case that the equals( ) method in Object class takes precedence over the equals( ) method is Comparator interface?

Functional interfaces are allowed to redeclare the methods that were already declared in Object and the effect will be the same as if they weren't declared at all.


If that is so, why does the equals( ) method in Comparator not count when implementing the Comparator as in the above?

You'll notice when you read the JavaDoc that Comparator.equals() has a more specific description than Object.equals().


Object:
boolean         equals(Object obj)
Indicates whether some other object is "equal to" this one.

Comparator:
boolean         equals(Object obj)
Indicates whether some other object is "equal to" this comparator.
Is the equals( ) method in Comparator useless?
 
Stephan van Hulst
Saloon Keeper
Posts: 10523
224
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Biniman Idugboe wrote:I have not read the documentation in much detail, but I do not know whether the Comparator interface extends the Object class.


Interfaces don't extend any classes, including Object. However, because it is guaranteed that EVERY object inherits from the Object class, you don't have to implement abstract methods declared in interfaces if they have the same signature as a method in Object, because EVERY object will inherit the implementation given in Object, even objects created in lambda expressions.

Is it the case that the equals( ) method in Object class takes precedence over the equals( ) method is Comparator interface?


Precedence has nothing to do with it. An interface just says that objects implementing it must contain methods with certain signatures. If a class happens to inherit the implementation from a super-class, that's just fine. Here's another example:



In this example, Person doesn't implement HasName, but it has a method that has the same signature and return type as the name() method in HasName.

Student implements HasName simply by extending Person. It doesn't have to provide an implementation for name(), because it already inherits the implementation from Person, even though Person doesn't implement HasName.

The same happens with a lambda expression. The Comparator interface says that instances have to implement the equals() and the compare() methods. The implementation for equals() is inherited from Object in the same way that Student inherits name() from Person, and the compare() method is implemented in the lambda's body.


If that is so, why does the equals( ) method in Comparator not count when implementing the Comparator as in the above?


Like I said, because functional interfaces are allowed to redeclare methods that are already declared in Object. This is a special case because it is guaranteed that ALL objects inherit from Object.


Is the equals( ) method in Comparator useless?


No, it serves to extend the method documentation. If you read beyond just the summary, you will come across this passage:

This method must obey the general contract of Object.equals(Object). Additionally, this method can return true only if the specified object is also a comparator and it imposes the same ordering as this comparator. Thus, comp1.equals(comp2) implies that sgn(comp1.compare(o1, o2))==sgn(comp2.compare(o1, o2)) for every object reference o1 and o2.


This is a pretty important addendum.
 
Biniman Idugboe
Ranch Hand
Posts: 247
3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Apology for submitting the same response twice.  I was having internet connectivity issues.
Okay, may be I do not truly understand the contextual meaning of "implements".  I was of the understanding that when a class implements an interface, all the methods and fields of the interface are transferred to the class.  Then, the class must add code body to the abstract methods and if need be, override appropriate methods already having code bodies.  In this particular case where  class XXX implements Comparator, XXX class inherits the Object class.  So, XXX class has the equals() method already having a code body.  Now, there is the equals( ) method inherited from Object class and there is equals( ) method transferred from Comparator interface.  Java chooses to discard the equals() method coming from the Comparator.  I see this as Java leaning to a preferred method; prioritizing.  Otherwise, it could just as well have chosen the equals( ) method coming from the Comparator interface.
Permit me to ask.  What happens when a class implements an interface?
 
Stephan van Hulst
Saloon Keeper
Posts: 10523
224
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
An interface is really just a collection of method declarations. When a concrete class implements an interface, it just means it promises to provide an implementation for all the methods in that interface, regardless of whether it provides a new implementation or inherits the implementation from a supertype.

Nothing is discarded. Object.equals() and Comparator.equals() refer to the same method. When a class implements Comparator, it promises to implement equals(), which is REALLY easy to do because every concrete class inherits an implementation from Object. There's only one abstract method left to implement: compare(). Because there's only one method left to implement, you can use a lambda expression.

If an interface provides a default implementation for a method, implementations in classes always take precedence. That's why in an interface, you can't give default implementations for methods that are also declared in Object: their implementation would always be overridden by the implementation given by Object, and therefore useless.
 
Biniman Idugboe
Ranch Hand
Posts: 247
3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

If an interface provides a default implementation for a method, implementations in classes always take precedence. That's why in an interface, you can't give default implementations for methods that are also declared in Object: their implementation would always be overridden by the implementation given by Object, and therefore useless.


Thank you! That peels off a layer of mystery.
 
There's a way to do it better - find it. -Edison. A better tiny ad:
Java file APIs (DOC, XLS, PDF, and many more)
https://products.aspose.com/total/java
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!