From my understanding if you implement an interface in java, the methods specified in that interface have to be used by the sub classes implementing the said interface.
The optional methods in the Collection interface mean that the implementation of the method is allowed to throw an exception, but it has to be implemented anyway. As specified in the docs:
Some collection implementations have restrictions on the elements that they may contain. For example, some implementations prohibit null elements, and some have restrictions on the types of their elements. Attempting to add an ineligible element throws an unchecked exception, typically NullPointerException or ClassCastException. Attempting to query the presence of an ineligible element may throw an exception, or it may simply return false; some implementations will exhibit the former behavior and some will exhibit the latter. More generally, attempting an operation on an ineligible element whose completion would not result in the insertion of an ineligible element into the collection may throw an exception or it may succeed, at the option of the implementation. Such exceptions are marked as "optional" in the specification for this interface.
If we go through the code of AbstractCollection.java in grepCode which is a ancestor class for all collection implementations, it will help us to understand the meaning of optional methods. Here is the code for add(e) method in AbstractCollection class. add(e) method is optional according to collection interface
public boolean add(E e) {
throw new UnsupportedOperationException();
}
Optional method means it is already implemented in ancestor classes and it throws UnsupportedOperationException upon invocation. If we want to make our collection modifiable then we should override the optional methods in collection interface.
There seems to be an awful lot of confusion in the answers here.
The Java language requires that every method in an interface is implemented by every implementation of that interface. Period. There are no exceptions to this rule. To say "Collections are an exception" suggests a very fuzzy understanding of what's really going on here.
It's important to realize that there are sort of two levels of conforming to an interface:
What the Java language can check. This pretty much just boils down to: is there some implementation for each of the methods?
Actually fulfilling the contract. That is, does the implementation do what the documentation in the interface says it should?
Well written interfaces will include documentation explaining exactly what is expected from implementations. Your compiler can't check this for you. You need to read the docs, and do what they say. If you don't do what the contract says then you'll have an implementation of the interface as far as the compiler is concerned, but it will be a defective/invalid implementation.
When designing the Collections API Joshua Bloch decided that instead of having very fine-grained interfaces to distinguish between different variants of collections (eg: readable, writable, random-access, etc.) he'd only have very coarse set of interfaces, primarily
Collection
, List
, Set
and Map
, and then document certain operations as "optional". This was to avoid the combinatorial explosion that would result from fine-grained interfaces. From the Java Collections API Design FAQ:
To illustrate the problem in gory detail, suppose you want to add the notion of modifiability to the Hierarchy. You need four new interfaces: ModifiableCollection, ModifiableSet, ModifiableList, and ModifiableMap. What was previously a simple hierarchy is now a messy heterarchy. Also, you need a new Iterator interface for use with unmodifiable Collections, that does not contain the remove operation. Now can you do away with UnsupportedOperationException? Unfortunately not.
Consider arrays. They implement most of the List operations, but not remove and add. They are "fixed-size" Lists. If you want to capture this notion in the hierarchy, you have to add two new interfaces: VariableSizeList and VariableSizeMap. You don't have to add VariableSizeCollection and VariableSizeSet, because they'd be identical to ModifiableCollection and ModifiableSet, but you might choose to add them anyway for consistency's sake. Also, you need a new variety of ListIterator that doesn't support the add and remove operations, to go along with unmodifiable List. Now we're up to ten or twelve interfaces, plus two new Iterator interfaces, instead of our original four. Are we done? No.
Consider logs (such as error logs, audit logs and journals for recoverable data objects). They are natural append-only sequences, that support all of the List operations except for remove and set (replace). They require a new core interface, and a new iterator.
And what about immutable Collections, as opposed to unmodifiable ones? (i.e., Collections that cannot be changed by the client AND will never change for any other reason). Many argue that this is the most important distinction of all, because it allows multiple threads to access a collection concurrently without the need for synchronization. Adding this support to the type hierarchy requires four more interfaces.
Now we're up to twenty or so interfaces and five iterators, and it's almost certain that there are still collections arising in practice that don't fit cleanly into any of the interfaces. For example, the collection-views returned by Map are natural delete-only collections. Also, there are collections that will reject certain elements on the basis of their value, so we still haven't done away with runtime exceptions.
When all was said and done, we felt that it was a sound engineering compromise to sidestep the whole issue by providing a very small set of core interfaces that can throw a runtime exception.
When methods in the Collections API are documented as being "optional operations", it does not mean that you can just leave the method implementation out in the implementation, nor does it mean you can use an empty method body (for one thing, many of them need to return a result). Rather, it means that a valid implementation choice (one that still conforms to the contract) is to throw an UnsupportedOperationException.
Note that because UnsupportedOperationException
is a RuntimeException
you can throw it from any method implementation, as far as the compiler is concerned. For example, you could throw it from an implementation of Collection.size()
. However, such an implementation would violate the contract as the documentation for Collection.size()
does not say that this is permitted.
Aside: The approach used by Java's Collections API is somewhat controversial (probably less now than when it was first introduced, however). In a perfect world, interfaces would not have optional operations, and fine grained interfaces would instead be used. The problem is that Java supports neither inferred structural types or intersection types, which is why attempting to do things the "right way" ends up becoming extremely unwieldy in the case of collections.
Well, this topic has been adressed to ... yeah .. but think, one answer is missing. Im talking about the "Default Methods" of interfaces. For example, let's imagine you'll have a class for closing anything (like a destructor or something). Let's say it should have 3 methods. Let's call them "doFirst()", "doLast()" and "onClose()".
So we say we want any object of that type to at least realize "onClose()", but the other are optional.
You can realize that, using the "Default Methods" of interfaces. I know, this would most of the Time negate the reason of an interface, but if you are designing an framework, this can be useful.
So if you want to realize it this way, it would look the following
public interface Closer {
default void doFirst() {
System.out.print("first ... ");
}
void onClose();
default void doLast() {
System.out.println("and finally!");
}
}
What now would happen, if you for example implemented it in an class called "Test", the compiler would be perfectly fine with the following:
public class TestCloser implements Closer {
@Override
public void onClose() {
System.out.print("closing ... ");
}
}
with the Output:
first ... closing ... and finally!
or
public class TestCloser implements Closer {
@Override
public void onClose() {
System.out.print("closing ... ");
}
@Override
public void doLast() {
System.out.println("done!");
}
}
with the output:
first ... closing ... done!
All combinations are possible. Anything with "default" can be implemented, but must not, however anything without must be implemented.
Hope it is not fully wrong that i now answer.
Have a great day everybody!
[edit1]: Please note: This only works in Java 8.
Oracle's Java Collections Tutorial:
To keep the number of core collection interfaces manageable, the Java platform doesn't provide separate interfaces for each variant of each collection type. (Such variants might include immutable, fixed-size, and append-only.) Instead, the modification operations in each interface are designated optional — a given implementation may elect not to support all operations. If an unsupported operation is invoked, a collection throws an UnsupportedOperationException. Implementations are responsible for documenting which of the optional operations they support. All of the Java platform's general-purpose implementations support all of the optional operations.
All methods have to be implemented for the code to compile, (aside from those with default
implementations in Java 8+), but the implementation doesn't have to do anything functionally useful. Specifically, it:
UnsupportedOperationException
(or similar)The latter approach is often taken in the collection classes - all the methods are still implemented, but some may throw an exception if called at runtime.