I have a question which appeared in a past paper (I'm revising for my exams) and I came across this word natural order which appears to be a keywords since it was written in bold on the paper. I've looked online at Natural Order but I couldn't find anything that related it to arraylist's like my question asks.
Please note, I do not need help solving the actual question, I just wish to understand what natural order means.
Question:
Write a Java static method called atLeast which takes an ArrayList of objects which
have natural order, an object of the element type of the ArrayList, and an integer n. A
call to the method should return true if at least n elements of the ArrayList are greater
than the element type object according to natural order, otherwise it should return false.
This likely means the objects in the List implement Comparable:
This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.
The declaration would look something like this:
static <T extends Comparable<? super T>>
boolean atLeast(List<T> list, T key, int n) {
...
}
Natural order means the default ordering for a particular type of collection. It actually depends upon the type of collection you are using. eg. if its a string collection, it will be sorted in alphabetical order, for numbers it follows numerical order.
Refer here for better understanding about natural ordering.
You can have a look at here for detail.
For objects to have a natural order they must implement the interface java.lang.Comparable. In other words, the objects must be comparable to determine their order. Here is how the Comparable interface looks:
public interface Comparable<T> {
int compareTo(T o);
}
Related
I have recently started learning Java. I was looking at Comparable and Comparator. One of the difference I read was "when you have one sorting criteria, use comparable interface and for more than one use Comparator".
But for Comparable I can use multiple sorting criteria's too like below :
class Employee implements Comparable<Employee>{
public int empID;
public int empStartDate;
public int compareTo(Employee empObj){
int result = this.empID - empObj.empID;
if(result == 0){
result = this.empStartDate - empObj.empStartDate;
}
return result;
}
}
I do understand other differences they have. But I am kind of stuck on this difference (Single and multiple sorting criteria).
Please correct me if I am wrong. Why is Comparable recommended for single sorting criteria if we can do using above approach? Could someone please explain me with an example? Thank you!
Why is Comparable recommended for single sorting criteria if we can do using above approach?
There is no generally accepted recommendation for that.
Wherever you read that is mistaken.
Comparable vs Comparator is not at all about whether you're comparing one or many values.
An object can have (at most) one natural order. If it does, that natural order is implemented using Comparable. It is actually written in the javadoc of Comparable:
This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.
Whether or not the object has a natural order, (alternative) ordering can be implemented using Comparator.
Neither is about the complexity of the comparison being done.
Unrelated:
Do not calculate compare / compareTo result using integer subtraction, since it will fail if the two values are more than MAX_VALUE apart (numeric overflow).
Always use Integer.compare(x, y) when comparing int values (available since Java 7). Same for Long.compare(x, y).
java.util.stream.Stream interface has two versions of sorted method – sorted() which sorts elements in natural order and sorted(Comparator). Why min() method was not introduced to Stream interface, which would return minimal element from natural-ordering point of view?
It should be clear that for min, max, and sorted, adding a method to Stream that does not require a comparator introduces a way to lose the generic type safety. The reason is that the current version of the Java language does not support restricting methods to instances of a specific parameterization, i.e. limit them to streams of comparable elements.
So the question could be the other way round, why has this potential break of the type safety been allowed with sorted()?
I can’t look into the developers mind, but one interesting point is that sorting has been treated specially for a long time now. With the introduction of Generics, it became possible to enforce that sorting without a Comparator can only be attempted for collections or arrays with comparable elements. However, especially when implementing generic collections, developers might face the fact that arrays can’t be created with a generic element type. There might be other scenarios, where a developer encounters an array or collection of a formally non-comparable type while the contained elements are comparable for sure. As said, I can’t look into the developers mind to say, which scenarios were considered.
But
Arrays.sort(Object[]) does not enforce the array type to be a subtype of Comparable. Even if it did,
sort(T[] a, Comparator<? super T> c) specifies that a null comparator implies “natural order”, which allows requesting natural order for any type
Collections.sort(List<T> list) requires a comparable element type, but
Collections.sort(List<T> list, Comparator<? super T> c) again specifies that a null comparator implies “natural order”, so there’s still an easy way to undermine the type system. Since the “null means natural” rule was already specified before Generics existed, it had to be kept for compatibility.
But it’s not just all about backwards compatibility. List.sort(Comparator), introduced in Java 8, is also specified as accepting null as argument for “natural order”, so now we have another scenario, where an implementer might have to sort data without a compile-time type that guarantees comparable elements.
So when it comes to sorting, there are already lots of opportunities to dodge the type system. But Stream.sorted(Comparator) is the only sort method not accepting a null comparator. So sorting by natural order without specifying Comparator.naturalOrder() is only possible using sorted() without arguments. By the way, having an already sorted input with a null comparator and requesting sorted() without comparator is the only situation where the Stream implementation will detect that sorting isn’t necessary, i.e. it doesn’t compare comparators and doesn’t check for Comparator.naturalOrder().
Generally, the type safety of comparators is astonishing weak. E.g. Collections.reverseOrder() returns a comparator of arbitrary type, not demanding the type to be comparable. So instead of min(), you could use max(Collections.reverseOrder()) to request the minimum, regardless of the stream’s formal type. Or use Collections.reverseOrder(Collections.reverseOrder()) to get the equivalent of Comparator.naturalOrder() for an arbitrary type. Likewise, Collator implements Comparator<Object>, for whatever reason, despite it can only compare Strings.
I'd assume that would just pollute the API. one could say "why is there no max parameterless version", "why is there no CharStream" and it could on and on in terms of the things that could be made available but were decided best not to.
having a parameterless min method over this:
someList.stream().min(Comparator.naturalOrder());
would be no different.
therefore it's best to just create a reusable method rather than polluting the API with all the possible things.
I think min() only allows the signature that accepts a Comparator because the Stream could be of any type, even a type created by you. In such case it would be impossible to rely on a natural order, as the class you've created, can't have a natural order until you specify it.
If, insteam of the class Stream you use, IntStream, you'll see that a min() method with no arguments is defined. This does what you want. It is the following:
public static void main (String... args){
IntStream s=IntStream.of(1,2,3,4,5,6,7,8,9,10);
System.out.println(s.min().getAsInt());
}
Comparator.naturalOrder serves this purpose. Its existence (or custom implementations thereof) allows other classes to remain simpler because they don't have to implement special codepaths for null-values in Comparator fields.
Its type will also force the stream's T to implement Comparable.
I have a class PriorityList with the signature
Tree<Key extends Comparable<Key>, Value>(which is given, I can't modify). The elements Tree are inserted in some order, given the key (i.e. it considers the key's compareTo method).
Let's say I have Tree<Integer, Integer>. The default compareTo of integer considers ascending order. I would like to be able to somehow have Tree insert the elements in descending order, if I wanted to. I know I could probably write another class MyInteger which implements Comparable and has a compareTo on its own.
But is there another way? What I would really like is to be able to somehow tell the Tree how to order the values.
Second question: If I were able to modify Tree, how would one pass a comparator as argument? (keeping generic types-syntax in mind).
You've named the two ways to do it: pass in a comparator or have key be comparable. If the class doesn't let you pass in your own comparator, then you're stuck monkeying with the keys or creating your own subclass with the Comparable interface
The alternative code would look something like this.
public class Tree<K,V>{
public Tree( Comparator<K> cmp ) {...}
}
You wouldn't need to create a new class for reverse. you can use Collections.reverseOrder() to obtain a Comparator in reverse of a given one.
As for the second question, you will simply add a setter to your tree. Something like: setComparator(Comparator<Key> c) and then use that comparator for all the comparisons needed in your Tree.
I have to implement a generic AVL tree as homework. It's defined as follows:
public class AVL<Key,Elem>;
The problem is that I assume that at some point, I'll have to compare keys to decide in which side of a node I allocate an element. For the purpose of this homework, Integers will be used as Keys.
Since no other restriction or information about that is given, I first thought of just asuming that Key will always be an Integer. However, that makes the generic "Key" superfluous, and I don't think that's what the teachers expect. So, I think that the best solution involves forcing that whatever that is passed as Key implements a Comparator, or something like that (I've really never worked with Comparator, just guessing), and then using that comparator to compare the Keys instead of using the ==,<,> and != operators. However, I have no idea on how to do it. Any hints?
Thanks in advance.
Try public class AVL<Key extends Comparable<Key>,Elem>; and use the compareTo() method which is required by the Comparable<T> interface and which is implemented by Integer.
The SortedMap and SortedSet implementations in the standard Java API either use a Comparator<Key> and call its compare(k1, k2) method, or assume the keys implement Comparable<Key>, and call k1.compareTo(k2). Most offer both, depending on which constructor is used. (EnumMap/EnumSet don't, as they support only the build-in ordering of the enum values by declaration order.)
The Comparable approach mandates that the keys are always sorted in the same way, and would be used for keys which have a canonical ordering (like integers), where you want to use this ordering.
The Comparator approach is more flexible, since you can use the same key objects for different maps where they are differently ordered, and you can use it for keys over which you have no control, or who don't have a canonical ordering (like List, trees/graphs, etc. You can also use it to sort strings keys by other criteria than the pure unicode value (e.g. Locale-based), using a Collator (this is a class implementing Comparator).
Both require a total order on your keys, but I suppose this is necessary for your AVL tree, too.
Here is a Comparator implementation which works on any comparable objects, so you could use it (maybe internally) as an adapter for the Comparable variant.
public static <X extends Comparable<X>> Comparator<X> makeComparator() {
return new Comparator<X>() {
public int compare(X left, X right) {
return left.compareTo(right);
}
};
}
List<MyClass> myclassList = (List<MyClass>) rs.get();
TreeSet<MyClass> myclassSet = new TreeSet<MyClass>(myclassList);
I don't understand why this code generates this:
java.lang.ClassCastException: MyClass cannot be cast to java.lang.Comparable
MyClass does not implement Comparable. I just want to use a Set to filter the unique elements of the List since my List contains unncessary duplicates.
Does MyClass implements Comparable<MyClass> or anything like that?
If not, then that's why.
For TreeSet, you either have to make the elements Comparable, or provide a Comparator. Otherwise TreeSet can't function since it wouldn't know how to order the elements.
Remember, TreeMap implements SortedSet, so it has to know how to order
the elements one way or another.
You should familiarize yourself with how implementing Comparable
defines natural ordering for objects of a given type.
The interface defines one method, compareTo, that must return a negative integer, zero, or a positive integer if this object is less than, equal to, or greater than the other object respectively.
The contract requires that:
sgn(x.compareTo(y)) == -sgn(y.compareTo(x))
it's transitive: x.compareTo(y)>0 && y.compareTo(z)>0 implies x.compareTo(z)>0
x.compareTo(y)==0 implies that sgn(x.compareTo(z)) == sgn(y.compareTo(z)) for all z
Additionally, it recommends that:
(x.compareTo(y)==0) == (x.equals(y)), i.e. "consistent with equals
This may seem like much to digest at first, but really it's quite natural with
how one defines total ordering.
If your objects can not be ordered one way or another, then a TreeSet wouldn't make sense. You may want to use a HashSet instead, which have its own contracts. You are likely to be required to #Override hashCode() and equals(Object) as appropriate for your type (see: Overriding equals and hashCode in Java)
If you don't pass an explicit Comparator to a TreeSet, it will try to compare the objects (by assuming they are Comparable). And if they aren't Comparable, it cannot compare them, so this exception is thrown!
TreeSets are sorted sets and require either objects to be Comparable or a Comparator to be passed in to determine how to sort the objects in the Set.
If you just want the set to remove duplicates, used a HashSet, although that will shuffle the order of the objects returned by the Iterator in ways that appear random.
But if you want to preserve the order somewhat, use LinkedHashSet, that will at least preserve the insertion order of the list.
TreeSet is only appropriate if you need the Set sorted, either by the Object's implementation of Comparable or by a custom Comparator passed to the TreeSet's constructor.