0

Class Collections has some static methods as utilities to manipulate collections like List. For example the sort method (Collections.sort(list)). I do not understand why Java specs made another class to host the sort method (and all the others like binarySearch) and not to List interface and concrete subclasses like ArrayList and LinkedList implement these methods.

UPDATED

As I made a global research and read the answers from this post I have to say that (bird's eye view): Some people (I mention @dan,@WJS,@cdalxndr) said in this post, using the sort method as example, that because the sort of ArrayList and LinkedList can be done with the same way then we can implemented writing only one time. So (I say) we could put the code in the List interface but until Java 7 we couldn't put any implementation in interface's body and the only way to write it one time was to implemented in utility class. But since Java 8 interfaces has the feature of "default" method. And Java team took advantage of this feature to have sort method implementation in interface level and that method can be used by ArrayList and LinkedList (as default if the classes do not override it)

  • @Steyrix You misunderstood Federicos comment. He didn't mean that Lists aren't collections, but that Sets aren't Lists, thus would need their own declaration and implementations for `sort()` when that would only exist in the `List` interface face. – Tom Oct 14 '20 at 12:17
  • 2
    @FedericoklezCulloca Yeah, sorry for misunderstanding, I missed the meaning of your comment :) – Steyrix Oct 14 '20 at 12:19
  • 1
    @Steyrix This question is about the static class `Collections` not the interface `Collection`. The utility methods operating on collections are the subject of the question, inheritance doesn't apply here. – dan Oct 14 '20 at 12:20
  • @dan Well, I misunderstood question too then. However, it is still about OOP concept called polymorphism – Steyrix Oct 14 '20 at 12:22
  • 1
    Not every Collection can be sorted, so forcing a Collection that cannot be sorted to implement the sort() method could be considered unintuitive design. You could of course point to the add() method and that there are collections that don't support adding and the implementation of the method will just throw an unsupportedOperationException. I guess in the end its a design choice to keep the interface functional and only have the methods that the majority of implementations will also support, so that you don't end up with classed where 50% of all methods just throw an Exception. – OH GOD SPIDERS Oct 14 '20 at 12:22
  • @OHGODSPIDERS he asks about `List` interface, where it makes sense to have a sort method, not `Collection` – cdalxndr Oct 14 '20 at 12:33
  • possibly duplicate of https://stackoverflow.com/questions/3340032/utility-classes-are-evil – cdalxndr Oct 14 '20 at 12:54
  • similar https://stackoverflow.com/questions/40996614/whats-the-best-practice-for-creating-stateless-utility-classes-in-java – cdalxndr Oct 14 '20 at 12:56

5 Answers5

2

Sorting is an algorithm, and List is a container.

The developers wanted to separate list algorithms (sort, binary search, etc) from container logic (add, remove, etc) so they put the algorithms to the utility class Collections.

cdalxndr
  • 1,435
  • 1
  • 15
  • 20
2

Before Java 8, interfaces could not have default nor static methods, hence, every method added to the interface needed to be implemented by all classes implementing the interface. Even when you provided a helpful implementation in a support class, the implementing class needed at least a delegating method.

So, unless you wanted to force all implementations to inherit from some abstract base class providing those methods, you had to be careful with what you add to the interface.

Even with the default methods, you have to be careful, to avoid polluting the name space of an implementing class with too many methods. This might also be the reason why not every operation has been retrofitted to default methods in Java 8:

While adding a default method to an interface is less intrusive, as it does not create the need to implement it in already existing implementation classes, it may still cause a clash with a concrete method of the implementation class that didn’t implement an interface method in the previous version.

Just imagine a custom List implementation in pre-Java 8 times that provided a helpful void sort(Comparator c) instance method just delegating to Collections.sort(this, c);. That worked before Java 8, not improving the performance, but allowing to write list.sort(c);. Nowadays, this method would unintentionally happen to override the default method with the same name and type, to which Collections.sort will delegate, producing an infinite loop (or rather, recursion).

Still, the sort method has been added to the List interface, because of the immediate benefits. Unlike the static methods in the Collections utility class, the default method can be overridden. This has been done for the most commonly used list types, ArrayList, Vector, and the implementation returned by Array.asList(…). Since all those implementations are backed by an array, the overriding method can delegate to Arrays.sort using the backing array directly, whereas the default implementation will work with a temporary copy of the list contents.

It’s also worth noting that those methods in Collections seem to be originally based on the assumption that those algorithms were suitable to all kind of implementations, which didn’t hold. Two releases after the introduction of the Collection API, the RandomAccess marker interface was introduced, to tell two fundamentally different list implementation categories apart, so the static method could branch to two alternative algorithms based on it.

Whenever we have to branch based on the class we’re operating on, we could question the abstraction and say that we might be better off with overridable methods on the type itself, but as explained above, there are historical reasons for the design and there still are reasons to be careful with adding methods to the interface.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • This answer is in the right direction although it is essentially related to and takes into account all the contributions that have already been made to this question. So it is practically a (good) mix of the answers already offered and takes the subject one step further. But I have a question. I didn't understand why the override it sort method in custom List would cause problem in the Java 8 version. What an infinite loop would be created? – nonlinearly Oct 15 '20 at 09:36
  • 1
    Consider [this example](https://ideone.com/TvAgPl) which works smoothly in Java 5, 6, and 7, as well as early Java 8 versions. But fails nowadays, because it unintentionally overrides a `default` method that didn’t exist prior to Java 8. – Holger Oct 15 '20 at 09:44
  • 2
    And a different problem with the `default` `sort` method that happened in a real like: [Java8 Collections.sort (sometimes) does not sort JPA returned lists](https://stackoverflow.com/q/26816650/2711488). But as developers know, [every change breaks someone's workflow](https://imgs.xkcd.com/comics/workflow.png)… – Holger Oct 15 '20 at 09:52
  • I see that the problem in the example you sent is the use of Collections.sort in the body of MyList.sort method. If I understand the problem exist because since Java 8 version Collections.sort delegates to List.sort and List.sort even if it has the default sort method implemented it delegates to MyList.sort due to override and this is the loop that you mentioned. Am I right? But I have a question. I put the example code in NetBeans and it didn't warn me to set an Override annotation in sort method. Why? – nonlinearly Oct 16 '20 at 10:59
  • 1
    When I put it in my Netbeans and the JDK is 8 or newer, it does warn. – Holger Oct 16 '20 at 13:02
  • Sorry... I closed it and opened it again and is ok...Thanks – nonlinearly Oct 16 '20 at 14:01
  • Also maybe in your answer have to mention that in Java 8 Collections.sort delegates to List.sort. Without this information it is almost impossible for someone to understand that a problem will arise with infinite loop – nonlinearly Oct 16 '20 at 14:10
  • 1
    It’s there, “*…to which Collections.sort will delegate…*” – Holger Oct 16 '20 at 14:11
0

There is sort of an option since Java 8, just requires you to define (or use predefined comparator).

Dummy example below:

    List<Integer> list = new ArrayList();
    list.addAll(List.of(1,5,4,3,6,8,9,2));

    list.sort(Comparator.naturalOrder());

But obviously it is not done the same way to you as an user as it is in Collections util (although I do believe that Collections implementation also wraps around using such comparator or something like it).

kiselitza
  • 119
  • 8
  • Yes... I was looking Java 7 documentation... but the question still makes sense for the other methods (like binarySearch) of Collections static class that concern List interface. Why not in List. what it serves? – nonlinearly Oct 14 '20 at 12:34
  • 1
    You can also use `list.sort(null)` to sort by the natural order, but compared to the `list.sort(Comparator.naturalOrder())`, you lose the type safety, i.e. get no compiler error when the list’s type is not comparable. This is the same as using `Collections.sort(list, null)` instead of `Collections.sort(list)` or `Collections.sort(list, Comparator.naturalOrder())`. So `Collections.sort(list)` is a convenience method for doing the same as `list.sort(null)`, but with type safety. They’ll end up at the same implementation code. – Holger Oct 15 '20 at 08:58
0

Because it isn't necessary. All the following extend Collection

BeanContext, BeanContextServices, BlockingDeque<E>, BlockingQueue<E>,<br>
Deque<E>, EventSet, List<E>, NavigableSet<E>, Queue<E>, Set<E>,<br>
SortedSet<E>, TransferQueue<E>

So what you are advocating is that each interface provide the exact same implementation or perhaps a convenience method to each method in Collections. That would be, imho, a form of code bloat. In the former case, it would require changing multiple implementations if improvements were discovered.

I know they added sort to the List interface, perhaps because it is such a common requirement. But I never had a problem using Collections.sort to do sorting. There may be other reasons of which I am unaware.

But I tend to think of Collections as very similar to the Math class. Double and Integer don't have duplicate math functions. Similar to Math, Collections is a utility that offers a variety of static methods that are usable by related classes. Granted, the Math class is not in the Double or Integer, etc hierarchy, but its use is very similar.

WJS
  • 36,363
  • 4
  • 24
  • 39
  • 1
    The reason is indeed not to be able to write `list.sort(…)`, but as explained in [my answer](https://stackoverflow.com/a/64367868/2711488), that the interface method can be overridden (and has been, for often used types). This performance benefit has been considered so important, that even `Collections.sort(…)` had been retrofitted to delegate to `list.sort(…)` to get the same benefit (despite this is not without some danger, as also explained in my answer). – Holger Oct 15 '20 at 09:02
0

The designers of the Collections Framework (primarily Josh Bloch while working at Sun Microsystems), as with many other sections of the Java API, had an eye to the longevity of the language. Java incorporates the notion of sustainment and evolution of APIs directly into the syntax supported by the documentation with the @deprecated tag. Specifically, they anticipated additional sorting and searching algorithms would likely be developed over the years long before additional "container" operations would be discovered to add to the Collection, and List interfaces.

They knew very well changes to the interfaces would impose upgrade requirements on development teams to deal with. Upgrade requirements slows the adoption of fixes and improvements that Sun Microsystems wanted teams to be able to absorb with ease. Incorporating new methods for sorting and searching into the interface would greatly impede that goal; placing an unnecessary burden on teams choosing to upgrade to the latest version of the Java language. Instead, they wisely chose to shunt these utility methods to a static utility class.

As with Java 8's List.sort(..), I can only guess Oracle felt the pressures of the industry and other languages incorporating these common operations right into their collection itself. However, keeping these utilities separate from the collection minimizes adoption requirements they would impose on those who directly implement their interfaces.

dan
  • 741
  • 9
  • 14
  • As with Java 8's List.sort(..) I think that it is not only the pressure... Since Java 8 interfaces has a feature called "default". So we can implement a method as default that all classes that implement this interface can use this method. As result we do not have to use or to create utility classes that have methods which normally should resides in a non utility classes – nonlinearly Oct 14 '20 at 14:35
  • @nonlinearly You missed my point. Suppose your team creates an implementation of `java.util.Set` and you use JDK8. Then suppose in JDK9 they added non-default method `Set.reduce(Comparator)`. In order for your team to upgrade to JDK9, you have to respond to the new method and your project won't compile until you do. This is work they're imposing on your team. They wanted to minimize that by dropping these utility methods into a static class so that upgrades would be much simpler for Java teams. – dan Oct 14 '20 at 16:39
  • Secondly, `java.util.Collections` came around long before there was `default` for interfaces. This was a design decision made long ago. – dan Oct 14 '20 at 16:52
  • I did not say anything different... of course you didn't read my update of question before. The answer resulted from a mix of this topic responses. – nonlinearly Oct 15 '20 at 08:33
  • @ dan... and one of them is yours – nonlinearly Oct 15 '20 at 08:43
  • 1
    The reason for adding `sort` to the list interface is not “pressures of the industry and other languages”, but a real practical benefit (other than being able to write `list.sort(…)`). As explained in [my answer](https://stackoverflow.com/a/64367868/2711488), the interface method can be overridden (and has been, for often used types). This explains in turn, why other methods have not been added. The was no direct benefit with a similar impact. – Holger Oct 15 '20 at 08:48
  • @nonlinearly I apologize, I've since seen your update. I can't defend having `sort` on the interface without also the capability of `default`. Pre-JDK8, while I see the simple conveniences of having `sort` on the interface, I think they made the right decision putting it into the static utility. However, there are performance optimizations to be made depending on which implementation is being sorted: `ArrayList` or `LinkedList`. Wherever the implementation is provided the algorithm should discern which collection it is sorting. – dan Oct 15 '20 at 12:21
  • @Holger The complexities of a `sort(..)` method are sufficiently high enough that it would be worthwhile to reconsider having a single `sort` overrideable method and instead offer the various types of sorting algorithms by name as desired. While I certainly see the value of overriding a common operation for a custom implementation a single `sort(..)` may have served the community better defined in the interface as `public final void sort();`. It's worth considering; not saying it's the right answer. This would block overriding and leave us to actually name our kind of sort implementation. – dan Oct 15 '20 at 12:31
  • 1
    I don’t consider naming an algorithm an advantage. That would imply that applications do not benefit from updating the jdk anymore when a better algorithm exists, as they would keep using the old algorithm. Compare with [this answer](https://stackoverflow.com/a/32334651/2711488), as `Arrays.sort` does name algorithms, though only in the documentation, so it didn’t hinder optimizations, but still turned out as a bad idea, as the documentation does not match the implementation anymore. – Holger Oct 15 '20 at 14:14