rayman
rayman

Reputation: 21606

Farther explaning about Sort and Static methods using Java8

I have the following example:

public class Utils{
   public static int compareByLength(String s1, String s2)
  {
    return s1.length() - s2.length();
   }
}


Arrays.sort(srt,Utils::compareByLength);

I understand reference methods in Java8 and I understand the sorting condition here.

What I don't understand is how under the hood Sort works. It accepts the static method: 'compareByLength' and knows how to translate the Strings s1,s2 as it's comparators variables.

I understand that Array.sort takes the second param as: Comparator<? super T> c

But still was hard for me to understand how it takes the function compareByLength and actually "understanding" the comparator criteria.

Thanks, ray.

Upvotes: 0

Views: 183

Answers (2)

Pshemo
Pshemo

Reputation: 124235

Arrays.sort method code looks like

public static <T> void sort(T[] a, Comparator<? super T> c) {
    if (c == null)
        c = NaturalOrder.INSTANCE;
    if (LegacyMergeSort.userRequested)
        legacyMergeSort(a, c);
    else
        TimSort.sort(a, 0, a.length, c, null, 0, 0);
}

so based on arguments, it uses sorting algorithms like in this case merge sort or tim sort passing to them array you want to sort and Comparator which should be used to decide how elements should be sorted (in case comparator will not be passed default one NaturalOrder.INSTANCE will be used).

Since Comparator is functional interface because it has only one abstract method

int compare(T o1, T o2);

we can use method reference Utils::compareByLength which is same as using lambda
(String s1, String s2) -> Utils.compareByLength(s1,s2) so it is almost the same as passing instance of anonymous inner class which extends Comparator<String> interface and implements its compare method using body of lambda. So your code is similar to

Arrays.sort(arr, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return Utils.compareByLength(s1, s2);
    }
});

Now general contract is that Comparator#compare(value1, value2) returns

  • 0 for equal values,
  • negative value if first element is lesser then second, which means that in ascending order they are in correct places
  • and positive value if first element is greater than second which means they are not ordered (using ascending order).

This criteria are used in implementations of sorting algorithms so regardless if it is used merge sorting, quick sort or tim sort contract stays the same. Now each of this sorting algorithms can use comparator passed in sort method which in your case is Comparator which thanks to Lambdas or more precisely method reference is using Utils.compareByLength method to decide it two elements are suppose to be switched or not.

Upvotes: 2

user146043
user146043

Reputation:

It's just returning the difference between the two lengths. You're going to end up with a negative number, or a positive one (in which case one or the other of the two variables should come first in the sort order) or the lengths are the same, meaning you'll get a zero. That's it. If you swap around the two numbers involved in the subtraction you'll see that you switch the sort order (ie from ascending to descending). This comparison is applied to all of the numbers involved in the sort by the java sort method.

You could compare strings, or sizes of buffers, or what have you, in that method, depending on what you're sorting (ie strings, classes etc). You could put logic there to first do the subtraction, and it's that's 0 then the tie breaker could be to check some other variable. But you're always going to have to return a number which is positive, negative or zero, which tells the algorithm doing the sort which of the two parameters being compared is the "winner".

Upvotes: 0

Related Questions