Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Lambda Expressions (Java), how is an expression without parameter used?

As I know, there are 3 kinds of java lambda expressions.

  1. (int x, int y) -> { return x + y; }
  2. x -> x * x
  3. ( ) -> x

The third one seems never ever used.

Could you give an example for each of the 3 cases (an extra example for case 3 will be good) to illustrate their usage? Please make them as simple as possible (preferably starting with list.stream()....)

like image 802
NoMoreErrors Avatar asked Nov 26 '16 04:11

NoMoreErrors


3 Answers

  1. The first expression will be used where you get 2 parameters for a method and return a value.

  2. The second expression will be used x -> x * x where you get 1 parameters for a method and return a value.

  3. The third expression ( ) -> x will be used ( ) -> x where you get 0 parameters for a method and return a value.

Let's take the third one. Suppose you have an interface which takes no parameters and returns a value.

static interface RandomMath {
    public int random();
}

Now You want to instantiate this interface along with its implementation. Without using lambda it will be done as below:-

Random random = new Random();
RandomMath randomMath = new RandomMath() {
    @Override
    public int random() {
        return random.nextInt();
    }
};

Using lambda it will be like:-

Random random = new Random();
RandomMath randomMath = () -> random.nextInt(); //the third type.

Similarly, for first two it can be used for methods which take two and one parameters and return a value.

static interface PlusMath {
    public int plus(int a, int b);
}

PlusMath plusMath = (a, b) -> a + b;

static interface SquareMath {
    public int square(int a);
}

SquareMath squareMath = a -> a * a;
like image 69
Mritunjay Avatar answered Oct 12 '22 23:10

Mritunjay


The first two examples are different from the last one. The variables in the function (lambda expression) refer to its parameters.

While in the third example the x refers to variable outside of the lambda expression but within the lexical scope (can be either local variable from the method or instance variable).

Example 1 (typically stream reduce), computes the sum by passing the so far computed sum and next item from the list to lambda function:

 int sum = list.stream().reduce((int x, int y) -> x+y);

Example 2, computes the squares from the elements:

 squares = list.stream().map((int x) -> x*x).collect(Collectors.toList());

Example 3, sets the element to default value if it's null in the list:

 final int x = MY_DEFAULT_VALUE;
 // lambda refers the the variable above to get the default
 defaults = list.stream().map((Integer v) -> v != null ? v : x);

Or better for example 3 is the map atomic methods:

 int x = MY_DEFAULT_VALUE;
 // lambda refers the the variable above to get the default
 map.computeIfAbsent(1, (Integer key) -> x);
 // the same could be achieved by putIfAbsent() of course
 // but typically you would use (Integer key) -> expensiveComputeOfValue(x)
 // ...
 // or quite common example with executor
 public Future<Integer> computeAsync(final int value) {
     // pass the callback which computes the result synchronously, to Executor.submit()
     // the callback refers to parameter "value"
     return executor.submit(() -> computeSync(value));
 }
like image 20
Zbynek Vyskovsky - kvr000 Avatar answered Oct 12 '22 23:10

Zbynek Vyskovsky - kvr000


Before going through the below examples, first, note that Lambda expressions can be written for any SAM (also called Functional) interfaces (Infact, Lambda expression is a syntactic sugar for replacing the verbose anonymous class (with single method) in Java).

Single Abstract Method interface or Functional Interface is an interface which contains only one abstract method), you can look here. If you know this simple point, you can write (play with) any number of your own Functional interfaces and then write the different Lambda Expressions according to each of those the Functional interface methods.

Below examples have been written by making use of the existing JDK (1.8) Functional interfaces like Callable, Function, BiFunction (Like these, there are many in built Functional interfaces in JDK 1.8, most of the times they readily suit our requirements).

(1) Example for (int x, int y) -> { return x + y; }

//Below Lamda exp, takes 2 Input int Arguments and returns string
BiFunction<Integer, Integer, String> biFunction = (num1, num2) -> 
               "Sum Is:" +(num1 + num2);
System.out.println(biFunction.apply(100, 200));

(2) Example for x -> x * x

//Below Lamda exp, takes string Input Argument and returns string
list.stream().map((String str1) -> 
       str1.substring(0, 1)). 
           forEach(System.out::println);    

(3) Example for () -> x

//Below Lambda exp, Input argument is void, returns String
Callable<String> callabl = () -> "My Callable";
ExecutorService service =  Executors.newSingleThreadExecutor();
Future<String> future = service.submit(callable);
System.out.println(future.get());
like image 39
developer Avatar answered Oct 13 '22 00:10

developer