JoBins採用企業サイト JoBinsエージェントサイト

アカウントをお持ちの方はこちら 採用企業ログイン
エージェントログイン


background

test

Jun 26, 2019

Programming in Java with lambdas and expression.

Lambda expression will enable you to solve common problems in a more concise and more flexible way that can take advantage of multiple cores and CPUs in your machine by parallel code of execution using this type of syntax. After 20 years it’s the new feature included from JDK8. It also improve the Collections In java making easy on iterate processes, manipulating Collections Data by managing new concurrency feature improved performance by which you can take advantages of multi-core processor or multiprocessing and if you look the history of java from the beginning, java had the concept of multiple thread of execution and now this is power up by Lambda Expression. Lambda expression simplifies how to pass behavior as a parameter.

 

Let’s understand Lambda Expressions important with these terms.

  • 1.Why does java required Lambda Expression.
  • 2.Lambda expression syntax
  • 3.Functional interfaces and their definition
  • 4.Method and constructor references.
  • 5.Stream method.

Let’s consider following section of code :


	List employee = //...some list
	Double highestSalary = 0.0;
	
	for( Employee e : employee ){
		if( e.getDepartment().equals(“HR”)){
			if(s.getSalay() > highestSalary){
				highestSalary= s.getSalay();
                         }	
                  }
	}

Let’s have a look, What we exactly trying to do with this block of code is to extract highest salary of employee from HR department. Where highestSalary variable is created to hold the highest salary. And  we used iterate of employee with for loop by getting each exist Employee up-to  end of list. At the end we get our answer that we looking for highest salary and nothing is wrong here to get output only but the real problem is,

  1. Our code controls iteration.

We are defining through our loop the order in which the element of collection is going to process. But what if the process needs to be break into parallel operations for huge process, we could not do that using this concept.

  1. Inherently serial (iterate from beginning to end)

We could not break the process into parallel operation because doing so without lambda we will introduce non-deterministic behavior different thread could be executing in different time they may looking different data, could update data from different resources and we may not get same result all the time. So our code is inherently serial as we start from beginning of collection move upto end of collections.

  1. Not thread safe

Let’s write same code in more functional approach.


List employee = //...some list
Double highestSalary   = employee
			.filter(Employee e -> e.getDepartment().equals(“HR”))
			.map(Employee e -> e.getSalary())
			.max();

The result is being generated internally, passing the collection of employee into filter method there is no loop there, here filter method removes all the element that do not match the condition given i.e HR department, so iteration is handled internally by the library. That means if library code want to handle by parallel we have not forced order of execution on that as in above previous example. So we are not doing inherently serial, we can do that in parallel if we want to. And also we do not have variable which is updating explicitly (as in above example holding highestSalary), this implies we are also thread safe and the client logic is stateless.

Lambda Expressions are Anonymous Functions. It is not associated with a Class.

Syntax: (parameter)  -> {lambda-body}

Parameter on the left hand side is parameter that passed into anonymous function. Where -> is the lambda operator. Single line of lambda do not need braces.

Lambda with no parameter must have empty brackets. A lambda expression can be used wherever the type is a functional interface.

Lets get more clear by some of example:

Example 1:

	List list = Arrays.asList("alpha", "bravo", "charlie", "delta", "echo", 
"foxtrot"); StringBuilder sb = new StringBuilder(); list.forEach(s -> sb.append(s.charAt(0))); String result = sb.toString(); System.out.println("result = " + result);

Example 2:

List list = new ArrayList<>(Arrays.asList("alpha", "bravo", "charlie", "delta", "echo", 
"foxtrot")); list.removeIf(s -> (s.length()%2) == 1); list.forEach(System.out::println);

Example 3:

List list = new ArrayList<>(Arrays.asList("alpha", "bravo", "charlie", "delta", "echo", 
"foxtrot")); list.replaceAll(String::toUpperCase); list.forEach(System.out::println);

Method and Constructor Reference:

 This is the short hand form of defining certain type of lambda expression. And let us reuse as a lambda expression. This is represented by :: sign.

Example:

    
List list = new ArrayList<>(Arrays.asList("alpha", "bravo", "charlie", "delta", "echo",
                                                     "foxtrot"));
//Using lambda expression example A.
list.foreach(e->System.out.println(e));

//Using method reference example B.
list.forEach(System.out::println);

In this example A we are passing the parameter but in second Example B we used :: and body of lambda expression calling method println with target reference(Existing object) of System that we want to call for that parameter exist in list. Where the compiler takes method reference and expanded into lambda expression as in example A and compile in the same way.

Format :  targgate_reference::method_name.

Some of the method reference rules are as follows:

                 

sn

Lambda expression

With method reference

1

(arg) -> ClassName.staticMethod(arg)

ClassName::staticMethod

2

(arg1,arg2) ->arg1.instanceMethod(arg2)

ClassName::instanceMethod

3

(arg) -> expr.instanceMethod(arg)

expr::instanceMethod

Examples:

Sn

Lambda example

Lambda with method reference example

1

(String s) -> System.out.println(s)

System.out::println

2

(String s,int i) -> s.substring(i)

String::substring

3

Axis a-> getLength(a)

this::getLength

 

Method reference provides a shorthand notation for simple lambdas.

Java with Lambdas and Streams:

Object Steams:

                  By default, a stream produces elements that are objects

Some time, this is not the best solution,

                                    List employee = ……

int highestSalary   = employee

                                                      .filter(Employee e -> e.getDepartment().equels(“HR”))

                                                      .map(Employee e -> e.getSalary())

                                                      .max();

 

In above example we extract salary using e.getSalary() and it returns a primitive value int not Integer and auto-box into objects and all object are unbox by method max() to get the value from object. so here we are creating  object that we do not need with unnecessary process.

To avoid a lot of unnecessary object creation and work we have three primitive stream types

  • IntStream,DoubleStream,LongStream
  • These can be used with certain operations.

List employee = ……

int highestSalary   = employee

                                                      .filter(Employee e -> e.getDepartment().equels(“HR”))

                                                      .mapToInt(Employee e -> e.getSalary())

                                                      .max();

The stream from mapToInt is a stream of int values, so no boxing and unboxing.

 

 

 

The Stream Method.

 

Stream method is called before the looping. This method takes Collections as input and returns java.util.stream.Stream interface as the output. Stream can be serial or parallel depending on the method called.

 

Examples:

  1. List list = Arrays.asList(

                                                      "The", "Quick", "BROWN", "Fox", "Jumped", "Over", "The", "LAZY", "DOG");

 

    List newList = list.stream()

                                                                                          .map(String::toLowerCase)

 .collect(Collectors.toList());

 

 

  1. List list = Arrays.asList(

        "The", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog");

 

    String merged = list.stream()

                                     .skip(1)

 .limit(3)

                                    .collect(Collectors.joining("-"));

 

  1. List list = Arrays.asList(

                  "The", "Quick", "BROWN", "Fox", "Jumped", "Over", "The", "LAZY", "DOG");

    List newList = list.stream()

        .filter(w -> w.length() % 2 == 1)

        .map(String::toLowerCase)

        .collect(Collectors.toList());

 

                   newList.forEach(System.out::println);

 

We can also apply parallerStream() Method to get parallel stream so that the values can be computed concurrently.when a stream execute in parallel, the java runtime partions the stream into multiple substreams. Aggreate operations iterate over and process these substreams in parallel and then combine the esults. For example following statement calculates the average age of all male members in parallel.

 

double average = roster

                                    .parallelStream()

                                   .filter(p -> p.getGender() == Person.Sex.MALE)

                                   .mapToInt(Person::getAge)

                                   .average()

                                   .getAsDouble();