When I first encountered Java interfaces like Iterable
/Iterator
and Comparable
/Comparator
, I was thoroughly confused. The reason? The suffixes -able
and -tor
threw me off. Despite their similar naming conventions, their design philosophies were quite different.
I initially assumed that XXX-able
would always correspond to some kind of XXX-tor
, with the latter providing methods that supported the former. This led me to believe that Iterator
existed purely to implement the methods defined by Iterable
. However, when I came across Comparable
, I was confused: "Wait, what’s Comparator
for, then?"
To clear up this confusion, I organized my thoughts and am sharing them here.
-able
Is an Interface, but What About -tor
?
In Java, Iterable
and Comparable
are both interfaces.
When a class implements these interfaces, it must include the methods specified by the interface.
For example, in the case of Iterable
, the required method is iterator()
, which returns an object that implements the Iterator
interface. And yes, Iterator
itself is also an interface, which means it defines its own required methods: hasNext()
and next()
.
Similarly, Comparable
is an interface that requires implementing the compareTo()
method. Meanwhile, Comparator
is another interface, with its own required method, compare()
. Both Comparable
and Comparator
are used to define comparison logic, but there is an important difference:
-
Comparable
defines a "natural order" for a class. -
Comparator
, on the other hand, is used to define custom comparison logic without modifying the class itself.
Comparison of Comparable
and Comparator
Feature | Comparable | Comparator |
---|---|---|
Purpose | Defines natural ordering within the class itself | Defines alternative ordering without modifying the class |
Implementation | Implemented directly in the class | Implemented in a separate class |
Key Method | compareTo() |
compare() |
Import Requirement | No explicit import needed | Requires importing Comparator
|
Understanding Through Illustrations
The confusion arose because the design philosophies behind interfaces for iteration and comparison differ. To better understand, I created some illustrations to visualize these concepts.
In the Case of Iteration
An Iterator
is a mechanism equipped with a "Next" button and an "is-empty" check, designed for iteration processing. At least one standard iteration logic must be defined. If necessary, it is also possible to have multiple versions with different names and custom logic.
Meanwhile, Iterable
acts as the manager for the standard iteration mechanism. Thanks to Iterable
, when called in a for-loop, the default iteration logic is implicitly used. Custom Iterator
objects created with different iteration logic lack such an Iterable
manager, so looping requires explicitly calling hasNext()
and next()
.
In the Case of Comparison
Comparable
is like attaching a tag for the default sorting criteria. On the other hand, Comparator
is responsible for attaching tags for alternative sorting criteria. Based on these sorting tags, methods like compareTo()
or compare()
determine the relative order of objects. This evaluation is then utilized in other processes like sorting.
Understanding the distinction between -able
and -tor
involves recognizing that both Iterable
and Comparable
provide standards—Iterable
for iteration and Comparable
for default comparison criteria.
What Happens If You Implement Iterator
Directly?
What if we skip Iterable
and directly implement hasNext()
and next()
?
In this case, we wouldn't be constrained by the method names defined in the interface. This allows for adding custom methods like reset()
to build iteration logic tailored for specific use cases.
However, the drawback is that without implementing Iterable
, your class won't be compatible with Java's standard collections API. This means you lose the ability to seamlessly use Java's built-in tools and methods. For example:
- You can't use enhanced
for-each
loops. - Utility methods from the
Collections
class, such asmin
,max
, orsort
, won't work with your custom class.
To maintain compatibility with standard APIs and ensure versatility, it's crucial to implement Iterable
.
It’s worth noting that Iterable
only requires the iterator()
method to be implemented. If you decide to implement a custom iterator, in practice, the process is similar to directly implementing Iterator
. You'll still need to explicitly call Iterator
methods for loop processing.
// Reverse iteration: explicitly using a reverseIterator()
Iterator<String> reverseIterator = collection.reverseIterator();
while (reverseIterator.hasNext()) {
System.out.println(reverseIterator.next());
}
Summary of Design Intentions
In the Case of Iterable
/ Iterator
-
Clear Separation of Responsibilities
-
Iterable
defines the capability of being iterable ("able to be iterated over"). -
Iterator
provides the mechanism for "how to execute the iteration."
-
-
Focus on Fundamental Functionality Over Flexibility
-
Iterable
andIterator
are designed with the assumption of having a single iteration criterion and are not intended to support multiple iteration criteria.
-
In the Case of Comparable
/ Comparator
-
Flexible Comparison Criteria
- By combining the default ordering provided by
Comparable
and custom ordering viaComparator
, they offer flexibility as needed.
- By combining the default ordering provided by
-
Emphasis on Independence
-
Comparable
embeds the natural ordering directly within the class, whereasComparator
is defined externally, allowing it to be used without modifying the class.
-
I hope this article is helpful to anyone looking to better understand these concepts.
Top comments (0)