Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding when and how to use Java 8 Lambdas

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]
like image 828
Denial Avatar asked Jul 20 '14 23:07

Denial


People also ask

When should lambdas be used?

Use a Lambda when you need to access several services or do custom processing. As data flows through services, you use Lambdas to run custom code on that data stream. This is useful in a Kinesis Pipeline that's receiving data from things like IoT devices.

What is the use of lambda expression in Java 8?

Lambda Expressions were added in Java 8. A lambda expression is a short block of code which takes in parameters and returns a value. Lambda expressions are similar to methods, but they do not need a name and they can be implemented right in the body of a method.

What is the benefit of lambda expressions in Java?

Advantages of Lambda ExpressionFewer Lines of Code − One of the most benefits of a lambda expression is to reduce the amount of code. We know that lambda expressions can be used only with a functional interface. For instance, Runnable is a functional interface, so we can easily apply lambda expressions.


1 Answers

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.
like image 51
Eran Avatar answered Oct 19 '22 23:10

Eran