15

I have been spending some time trying to learn some of Java 8's new features. As an exercise, I wrote a MergeSort using some Java 8 Functional Interfaces. I'm including the full code below (bugs/optimizations may exist, I am only interested in them if they relate to Java 8 features). My question is, I believe there are opportunities to utilize lambda expressions when I am using my functional interfaces, but it's just not clicking in my brain yet. It feels like everytime I am calling apply, there should be a way I can use "->" instead. Can someone please show me the light?

Merge Function written using BinaryOperator Functional Interface

public class Merge implements BinaryOperator<int[]>{

@Override
public int[] apply(int[] t, int[] u) {

    int[] result = new int[t.length + u.length];

    for (int i = 0, j = 0, k = 0; i < result.length; i++){

        if( j == t.length){
            result[i] = u[k++];
        } else if (k == u.length) {
            result[i] = t[j++];
        } else {
            result[i] = t[j] < u [k] ? t[j++] : u[k++];
        }

    }

    return result;
}

}

MergeSort written as a java.util.function.Function

public class MergeSort implements Function<int[], int[]>{

Merge merge = new Merge();

@Override
public int[] apply(int[] t) {

    if(t.length <= 1){
        return t;
    }

     return merge.apply( apply(Arrays.copyOfRange(t, 0, t.length / 2)), 
                         apply(Arrays.copyOfRange(t, t.length / 2, t.length )));

}

}

Main with one simple test case

public class MergeSortMain {

public static void main(String[] args) {

    int values[] = {3,12,6,7,2,1,23,4,5,7,8,4,2,5,365};

    MergeSort mergeSort = new MergeSort();

    System.out.println(Arrays.toString(mergeSort.apply(values)));
}

}

produces

[1, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 12, 23, 365]
Denial
  • 363
  • 1
  • 5
  • 12
  • I'd encourage you to edit this with more specific questions and attempt to reopen it. Examples: am I using functional interfaces correctly? How can I use lambdas to improve this code? – Stuart Marks Jul 21 '14 at 05:27
  • 2
    Observation: there are several upvotes for this question (including mine) and no downvotes, yet it was put on hold. This suggests that there are worthy questions and answers lurking in here, if the question can be improved and reopened. – Stuart Marks Jul 21 '14 at 05:29
  • @StuartMarks Thanks for the feedback. I struggled with how to properly ask this question, so I appreciate the advice. I'll see if I can't come up with a better follow-on. BTW, how can you tell if a question is on hold? It doesn't look on hold on my end. – Denial Jul 23 '14 at 13:16
  • This question got reopened fairly quickly. If it were still closed or on hold it would be easy to tell. There would be a big banner at the bottom of the question, and there's no text box to start an answer. I'm still pondering an answer to this, but I've been busy.... – Stuart Marks Jul 23 '14 at 23:31

1 Answers1

14

The idea of lambda expressions is that instead of creating a class that implements a functional interface, you can define a lambda expression of the type of that interface.

For example, your Merge class implements BinaryOperator<int[]> and can be replaced by the following lambda expression :

BinaryOperator<int[]> merge = (t,u) -> {
    int[] result = new int[t.length + u.length];
    for (int i = 0, j = 0, k = 0; i < result.length; i++){
        if( j == t.length){
            result[i] = u[k++];
        } else if (k == u.length) {
            result[i] = t[j++];
        } else {
            result[i] = t[j] < u [k] ? t[j++] : u[k++];
        }
    }
    return result;
};

Now we can similarly create a lambda expression to replace the MergeSort class, and, combining the two lambdas, we get :

public class MergeSortMain {
    public static Function<int[], int[]> mergeSort;
    public static void main(String[] args) {
        int values[] = {3,12,6,7,2,1,23,4,5,7,8,4,2,5,365};
        mergeSort = l -> {
            BinaryOperator<int[]> merge = (t,u) -> {
                int[] result = new int[t.length + u.length];
                for (int i = 0, j = 0, k = 0; i < result.length; i++){
                    if( j == t.length){
                        result[i] = u[k++];
                    } else if (k == u.length) {
                        result[i] = t[j++];
                    } else {
                        result[i] = t[j] < u [k] ? t[j++] : u[k++];
                    }
                }
                return result;
            };
            if(l.length <= 1){
                return l;
            }
            return merge.apply( mergeSort.apply(Arrays.copyOfRange(l, 0, l.length / 2)), 
                                mergeSort.apply(Arrays.copyOfRange(l, l.length / 2, l.length )));
        };
        System.out.println(Arrays.toString(mergeSort.apply(values)));
    }
}

Some points regarding this code :

  1. I had to rename the parameter of mergeSort lambda from t to l, since t is also used in the merge lambda.
  2. I had to declare the mergeSort lambda as a static member (prior to assigning its value), since it contains recursive calls to itself.
Eran
  • 387,369
  • 54
  • 702
  • 768
  • Interesting. I had thought the lambdas might allow for something more... elegant. Perhaps my example is not the best. – Denial Jul 23 '14 at 13:32