Showing posts with label Lambda. Show all posts
Showing posts with label Lambda. Show all posts

Wednesday, January 5, 2022

Lambda and final variables

Introduction

Lambda expressions can use the variables in the scope of the lambda expression, but only if they are final or effectively final. What is the reason for that? Why is that? It is an interesting question because the answer is not apparent and opinionated.

Lambda, final variables, Core Java, Oracle Java Preparation, Java Career, Java Guides, Oracle Java Certification

There is only one ultimate answer, though: because that is what the Java Language Specification says. But saying that is boring. True, but boring. I prefer the answer that says lambdas can only use final and effectively final local variables because lambdas are not closures.

In the following, I will discuss what final and effectively final mean, the differences between closures and lambdas, and finally, how we can create closures in Java using lambda expressions. I am not advocating the creation of lambda expression-based closures in Java, nor the abandonment of the idea.

final and effectively final

When declaring it, a local variable is final if we use the final keyword. The compiler will also require that the variable get a value only once. This value assignment may happen at the location of the declaration but can be a bit later. There can be multiple lines that assign value to the final variable so long as long only one of them can execute for each method invocation. The typical case is when you declare a final variable without assigning value to it, and then you have an if statement giving different values in the “then” and the “else” branch.

Needless to say that the variable has to be initialized before the lambda expression is created.

A variable is effectively final if not final, but it could be. It gets an assigned value at the declaration or can get a given value only once.

Life of a Lambda

A lambda expression is a kind of anonymous class. The JVM handles it differently, and it is more efficient than an anonymous class, not to mention that it is more readable. However, from our point of view, we can think of it as an inner class.

public class Anon {

    public static Function<Integer, Integer> incrementer(final int step) {

        return (Integer i) -> i + step;

    }

    public static Function<Integer, Integer> anonIncrementer(final int step) {

        return new Function<Integer, Integer>() {

            @Override

            public Integer apply(Integer i) {

                return i + step;

            }

        };

    }

}

When the lambda expression is created, the JVM makes an instance of the lambda class that implements the Function interface.

var inc = Anon.incrementer(5);

assertThat(inc.getClass().getName()).startsWith("javax0.blog.lambdas.Anon$Lambda$");

assertThat(inc.getClass().getSuperclass().getName()).isEqualTo("java.lang.Object");

assertThat(inc.getClass().getInterfaces()).hasSize(1);

assertThat(inc.getClass().getInterfaces()[0]).isEqualTo(java.util.function.Function.class);

The JVM will place this object on the heap. In some cases, the compiler may realize that the object cannot get out of the method’s scope, and in this case, it may store it in the stack. It is called local variable escape analysis, which can just put any object on the stack, which cannot escape from the method and may die together with the method return. However, for our discussion, we can forget this advanced feature of the Java environment.

The lambda is created in the method and stored in the stack. It is alive so long as long there is a hard reference to this object and is not collected. If a lambda expression could reference and use a local variable, which lives in the stack, it would need access to something gone after the method returns. It is not possible.

There are two solutions to overcome this discrepancy. One is what Java follows, creating a copy of the variable’s value. The other one is creating a closure.

Closure and Groovy

We will look at Groovy examples when talking about closures. The reason to select Groovy is that it is very close to Java. We will look at some Groovy examples, and for the matter of demonstration, we will use Java-style as much as possible. Groovy is more or less compatible with Java; any Java code can be compiled as a Groovy source. The actual semantic may, however, be different slightly.

Groovy solved the issue of local variable accessibility creating closures. The closure closes the functionality and the environment into a single object. For example, the following Groovy code:

class MyClosure {

    static incrementer() {

        Integer z = 0

        return { Integer x -> z++; x + z }

    }

}

creates a closure, similar to our lambda expression, but it also uses the local variable z. This local variable is not final and not effectively final. What happens here is that the compiler creates a new class that contains a field for each local variable used in the closure. A new local variable references an instance of this new class, and the local variable uses all references to this object and its fields. This object, along with the “lambda expression” code, is the closure.

Since the object is on the heap, it stays alive as long as there is a hard reference. The object, which holds the described function has one, so this object will be available so long as long the closure is alive.

def inc = MyClosure.incrementer();

assert inc(1) == 2

assert inc(1) == 3

assert inc(1) == 4

It is clearly shown in the test execution where the closure increases the z amount at each execution.

Closures are lambdas with state.

Lambda in Java

Java approaches this problem differently. Instead of creating a new synthetic object to hold the referenced local variables, it simply uses the values of the variables. Lambdas seem to use the variables, but they don’t. They use only constants copying the value of the variables.

When designing lambdas, there were two options. I was not part of the team making the decisions, so what I write here is only my opinion, guessing, but it may help you understand why the decision was made. One option could be to copy the variable’s value when the lambda is created, not caring about the later value change of the local variable. Could it work? Inevitably. Would it be readable? In many cases, it would not be. What if the variable changes later? Will the lambda use the changed value? No, it will use the copied, frozen value. It is different from how variables work usually.

Java requires the variable to be final or effectively final to solve this discrepancy. The disturbing case having the different variable value when the lambda is used is avoided.

When designing language elements, there are always tradeoffs. On one end, some constructs provide great power to the hands of the developers. However, great power requires great responsibility. Most of the developers are not mature enough to take on the responsibility.

On the other side of the scale are the simple constructs providing less functionality. It may not solve some problems so elegantly, but you also cannot create unreadable code so easily. Java is usually going this way. There has been an obfuscated C contest almost since the language C started. Who can write less readable code in that programming language? Since then, almost all languages started the contest, except two. Java and Perl. In the case of Java, the contest would be dull, as you cannot write obfuscated code in Java. In the case of Perl, the contest is pointless.

Closure in Java

If you want to have a closure in Java, you can create one yourself. The good old way is to use anonymous, or for that matter, regular classes. The other is to mimic the behavior of the Groovy compiler and create a class that encapsulates the closure data.

The Groovy compiler creates the class for you to enclose the local variables, but nothing stops you from making it manually if you want it in Java. You have to do the same thing. Move every local variable that the closure uses into a class as an instance field.

public static Function<Integer, Integer> incrementer() {

    AtomicInteger z = new AtomicInteger(0);

    return x -> {

        z.set(z.get() + 1);

        return x + z.get();

    };

}

We only had one local variable, int z, in our example. We need a class that can hold an int. The class for that is AtomicInteger. It does many other things, and it is usually used when concurrent execution is an issue. Because of that, some overhead may slightly affect the performance, which I abjectly ignore for now.

If there are more than one local variables, we need to craft a class for them.

public static Function<Integer, Integer> incrementer() {

    class DataHolder{int z; int m;}

    final var dh = new DataHolder();

    return x -> {

        dh.z++;

        dh.m++;

        return x + dh.z*dh.m;

    };

}

As you can see in this example, we can declare a class even inside the method, and for the cohesion of the code, it is the right place. Eventually, it is easy to see that this approach is working.

final var inc = LambdaComplexClosure.incrementer();

assertThat(inc.apply(1)).isEqualTo(2);

assertThat(inc.apply(1)).isEqualTo(5);

assertThat(inc.apply(1)).isEqualTo(10);

It is, however, questionable if you want to use this approach. Lambdas generally should be stateless. When you need a state that a lambda uses, in other words, when you need a closure, which the language does not directly support, you should use a class.

Source: javacodegeeks.com

Monday, September 27, 2021

Java – Lambda Expressions Parameters

Java – Lambda Expressions Parameters, Core Java, Oracle Java Tutorial and Material, Oracle Java Preparation, Oracle Java Career, Java Guides

Lambda Expressions are anonymous functions. These functions do not need a name or a class to be used. Lambda expressions are added in Java 8. Lambda expressions basically express instances of functional interfaces An interface with a single abstract method is called a functional interface.

Lambda expressions implement only one abstract function and therefore implement functional interfaces. Predicate interface is an example of a functional interface that has only one abstract method called test().

Illustration:

interface Predicate

{

    ......

    abstract boolean test(T t)

}

The above is a functional interface that has one abstract method test receiving only one parameter of type T and returns a boolean value. This method is a generic method that takes a type parameter. This interface can be implemented anywhere in a program using a lambda expression instead of creating classes with multiple functions. For eg, to implement a runnable interface used only for multithreading one needs to implement only a run() method. Then there is the comparable interface which can be implemented using compare() method.

Important points:

Java – Lambda Expressions Parameters, Core Java, Oracle Java Tutorial and Material, Oracle Java Preparation, Oracle Java Career, Java Guides

◉ The body of a lambda expression can contain zero, one, or more statements.

◉ When there is a single statement curly brackets are not mandatory and the return type of the anonymous function is the same as that of the body expression.

◉ When there is more than one statement, then these must be enclosed in curly brackets (a code block) and the return type of the anonymous function is the same as the type of the value returned within the code block, or void if nothing is returned.

These are for single–line lambda expressions having void return type.

Type 1: No Parameter.

Syntax:

() -> System.out.println("Hello");
It takes interface of the following form:

interface Test1
{
    void print()
}

Type 2: Single Parameter.

Syntax:

(p) -> System.out.println(p);

It is not mandatory to use parentheses if the type of that variable can be inferred from the context

It takes interface of the following form:

interface Test2
{
    void print(Integer p)
}

The type and return type of the lamdas are automatically inferred.

Type 3: Multi parameters

(p1, p2) -> System.out.println(p1 + " " + p2);

It is not mandatory to use parentheses if the type of that variable can be inferred from the context

It takes interface of the following form:

interface Test3
{
    void print(Integer p1, Integer p2)
}

The type and return type of the lamdas are automatically inferred.

Now, we are done with discussing out the theoretical concept, now let us come up with the implementation part. So here primarily we will be discussing out the codes for the above three types as discussed above:

Note: forEach() method is of Iterable interface that is used to iterate through a collection. Here it takes an argument of Consumer type interface. This is a functional interface having only one abstract method called accept(). Since it is a functional interface, a lambda expression can be passed.

Hence, if we do conclude out the above 

Example 1: Lambda expression with no parameters

// Java code to illustrate lambda expression
// without parameters

// functional interface
// without parameters
interface Test1 {
void print();
}

class OJC {
// functional interface parameter is passed
static void fun(Test1 t) { t.print(); }
public static void main(String[] args)
{
// lambda expression is passed
// without parameter to functional interface t
fun(() -> System.out.println("Hello"));
}
}

Output

Hello

Example 2: Type 2 Lambda expression with a single parameter

// Java code to illustrate lambda expression
// with single parameter

// functional interface
// with one parameter of Integer type
interface Test2 {
// The void type and the Integer type
// is automatically inferred from here
// and assigned to the lambda expression
void print(Integer p);
}

class OJC {
// takes lambda expression and a variable of
// Integer type as arguments
static void fun(Test2 t, Integer p)
{
// calls the print function
t.print(p);
}
public static void main(String[] args)
{
// lambda expression is passed
// with a single parameter
// lambda expression is mapped to the
// single argument abstract function in the
// functional interface Test2
fun(p -> System.out.println(p), 10);
}
}

Output

10

Example 3: Type 3 Lambda expression with multi parameters

// Java code to illustrate lambda expression
// with multi parameters

// functional interface Test3
// with 2 parameter of Integer type
interface Test3 {
// The void type and the Integer type
// is automatically inferred from here
// and assigned to the lambda expression
void print(Integer p1, Integer p2);
}

class OJC {
// takes parameter of Test3 type followed
// by 2 integer parameters p1 and p2
static void fun(Test3 t, Integer p1, Integer p2)
{
// calls the print function
t.print(p1, p2);
}
public static void main(String[] args)
{
// lambda expression is passed
// with two parameters
// lambda expression is mapped to the
// double argument abstract function in the
// functional interface Test3
fun((p1, p2)
-> System.out.println(p1 + " " + p2),
10, 20);
}
}

Output

10 20

Source: geeksforgeeks.org

Tuesday, May 26, 2020

Java 8 Lambda Expressions with examples and Rules

Java 8 Lambda Expressions, Oracle Java Tutorial and Material, Oracle Java Learning, Oracle Java Exam Prep

Java 8 is first released in 2014 and introduced lot of new features. Lambda expressions are the most significant change in java 8 version.

As of java 7, Oracle/Sun people have given impartance to the object oriented programming languages but in java 8, they have introduced functional programming to compete with other programming languages such as Scala, C# etc.

What is Lambda Expression?


Any function which is having no name is called as Lambda expression. Which is also called as anonymous function.

Rules:

1) function should not have access modifier
2) Should not have any return type (even void also not allowed)
3) Should not have name for function
4) Should use arrow symbol "->"

We will see now a few examples how to convert normal java fucntions to lambda expression.

Example 1:

Before java 8:

public void print() {
  System.out.println("Hello World");
 }

In java 8:

() -> {
  System.out.println("Hello World");
   };

Please observe here, we have remvoed fucntion access modifier (public), return type(void) and method name (print) in the lambda expression and added -> symbol. Note: If method body has only statement then curly braces are optional. Curly braces are mandetory if multiple statements are present in the method body. we can rewrite the above lambda expression as below.

() -> System.out.println("Hello World");

Example 2:

Before java 8:

public void sum(int a, int b) {
  System.out.println("sum :" + (a + b));
 }

In java 8:

(int a, int b) -> System.out.println("sum :" + (a + b));

Example 3: Finding the length of string Before java 8:

public int getLength(String value) {
  return value.length();
 }

In java 8:

(String value) -> {
   return value.length();
  }; 

Java 8 Lambda Expressions, Oracle Java Tutorial and Material, Oracle Java Learning, Oracle Java Exam Prep

Lambda Expressions Thumb Rules:


1) Parameters are optional. It can be zero or more.

() -> {System.out.println("Hello World");};
(int a) -> {System.out.println("value "+a);};

2) If no parameters are available then need to use empty parenthesis ().

() -> {System.out.println("Hello World");};

3) If we have multiple parameters then need to separate them with comma(,)

(int a, int b) -> System.out.println("sum "+(a+b));

4) if body has only statement then curly braces are optional.

(int a) -> System.out.println("value "+a);

5) if body has more than one statement then curly braces are mandetory.

() -> {
   System.out.println("Hello World");};
   System.out.println("value "+a);
    };
 
6) parameter type(s) is optional. No need to declare manually because compile can expect based on the context. We will disscuss more in the next post.

(a) -> System.out.println("value "+a);
(a, b) -> System.out.println("sum "+(a+b));

7) If only one parameter is available then parenthesis are optional.

(int a) -> {System.out.println("value "+a);};

The above can be rewritten as a -> {System.out.println("value "+a);};

Thursday, April 2, 2020

How to create AWS Lambda function with Java

In this post, we will see how we can create AWS Lambda function in Java and I tell you, it is quite easy to do so…

Basically, there are three ways in which we can create AWS Lambda function :

– By implementing RequestHandler interface

– By implementing RequestStreamHandler interface

– Custom implementation, which does not require us to implement any AWS specific interface

AWS Lambda function with Java, Oracle Java Cert Exam, Oracle Java Tutorial and Material, Oracle Java Guides

AWS Lambda function by implementing RequestHandler interface


For using this method of creating AWS lambda function, we need to have following dependency in our project :

<dependency>
 <groupId>com.amazonaws</groupId>
 <artifactId>aws-lambda-java-core</artifactId>
 <version>1.1.0</version>

</dependency>

And below is how your class will look like :

package com.blogspot.javasolutionsguide;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

public class HelloWorldWithRequestHandler implements RequestHandler<object,object> {

 @Override
 public Object handleRequest(Object input, Context context) {
  return String.format("Hello %s%s.", input ," from " + context.getFunctionName());
 }
} 
</object,object>

Once you have created maven project with above dependency and class in your project, maven build the project, which will create jar for you in the target folder of your project.

Now open the AWS Console, go to Services and search for AWS Lambda.

AWS Lambda function with Java, Oracle Java Cert Exam, Oracle Java Tutorial and Material, Oracle Java Guides

On the following screen ,click on Create Function.

AWS Lambda function with Java, Oracle Java Cert Exam, Oracle Java Tutorial and Material, Oracle Java Guides

On following screen, enter Function name “HelloWorld” and choose Runtime as Java 11.

AWS Lambda function with Java, Oracle Java Cert Exam, Oracle Java Tutorial and Material, Oracle Java Guides

In Permissions section, choose “Create a new role with basic Lambda permissions”and AWS Lambda will create and execution role with name HelloWorld-role-jc6cmpnj. This role is required to allow AWS Lambda to upload logs to AWS Cloudwatch logs.

Click on Create Function.

AWS Lambda function with Java, Oracle Java Cert Exam, Oracle Java Tutorial and Material, Oracle Java Guides

You will see following screen, where it says that “Successfully created the function HelloWorld.You can now change its code and configuration.To invoke your function with a test event, choose Test”.

AWS Lambda function with Java, Oracle Java Cert Exam, Oracle Java Tutorial and Material, Oracle Java Guides

AWS Lambda function with Java, Oracle Java Cert Exam, Oracle Java Tutorial and Material, Oracle Java Guides

Now in the Function code section, click on the upload button and browse on your computer for the jar that you created earlier.

– Also, in the Handler textbox, replace
example with package name where your “HelloWorldWithRequestHandler” class is residing, which in our case it is “
com.blogspot.javasolutionsguide“

– And replace Hello with “HelloWorldWithRequestHandler”.

– And replace handleRequest will stays as is ,because we also have same method name in our class.

Click on Save button on extreme right side of the screen.

AWS Lambda function with Java, Oracle Java Cert Exam, Oracle Java Tutorial and Material, Oracle Java Guides

Now to test our lambda function, we need to configure test event(s),for which we will click on “Select a Test event” drop down and then click on “Configure test events”.

AWS Lambda function with Java, Oracle Java Cert Exam, Oracle Java Tutorial and Material, Oracle Java Guides

You will see following screen.Enter Event name as “HelloWorldEvents” and replace following

{

  “key1”: “value1”,

  “key2”: “value2”,

  “key3”: “value3”

}

with just your name like as below :

“Gaurav Bhardwaj”

and click on Create button.

AWS Lambda function with Java, Oracle Java Cert Exam, Oracle Java Tutorial and Material, Oracle Java Guides

Now click on Test button and you should see your lambda function executed successfully with message “Hello Gaurav Bhardwaj from HelloWorld”,which is the output returned by our lambda function.


AWS Lambda function with Java, Oracle Java Cert Exam, Oracle Java Tutorial and Material, Oracle Java Guides

If you click on the logs link in the above screen, it will take you to the AWS Cloudwatch screen where you can see that for your lambda function a LogGroup has been created and under which you have LogStream where you can see logs of your lambda function.This was the reason we assigned role to our lambda function, because AWS lambda used that role to push logs to the Cloudwatch.

AWS Lambda function with Java, Oracle Java Cert Exam, Oracle Java Tutorial and Material, Oracle Java Guides

AWS Lambda function by implementing RequestStreamHandler interface


In this case you need to follow exact same steps as in above case.It is just that in the code you need to implement RequestStreamHandler interface rather than RequestHandler interface as below.

package com.blogspot.javasolutionsguide;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;

public class HelloWorldWithRequestStreamHandler implements RequestStreamHandler {

 @Override
 public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
  int letter;
        while((letter = inputStream.read()) != -1)
        {
            outputStream.write(Character.toUpperCase(letter));
        }
 }
}

AWS Lambda function by custom implementation, which does not require us to implement any AWS specific interface


You can also have your custom lambda function ,which does not follow signature from some AWS specific interface.You can even omit Context object as well, if you don’t want it.

In the following code,I have tried to put two handler methods, one with Context object and one without Context object.To test these both ,you just need to change the name of the method in the AWS console and it will start hitting that method.

Also ,we can see that from Context object ,we can get lots of useful information like name of AWS fucnton,its version,ARN,how much memory is allocated to the function(by default it is 512 mb) .

package com.blogspot.javasolutionsguide;

import com.amazonaws.services.lambda.runtime.Context;

public class HelloWorld {
  
        //Handler method without Context
 public String sayHelloWorldWithoutContext(String name) {
  return String.format("Hello %s.", name);
 }
  
 //We need to add aws-lambda-java-core dependency if we add Context as parameter.
 public String sayHelloWorldWithContext(String name, Context context) {
   
  context.getLogger().log("Lambda Function Name:" + context.getFunctionName() +
    "Version:" + context.getFunctionVersion() + 
    "Arn:" + context.getInvokedFunctionArn() +
    "Allocated Memory:" + context.getMemoryLimitInMB() +
    "Remaining Time:"+ context.getRemainingTimeInMillis());
  return String.format("Hello %s.", name);
 }

}

Also in the following example ,we can see that if we have two handler methods with same name in our class,the handler method which has Context object as its last parameter will be called.

package com.blogspot.javasolutionsguide;

import com.amazonaws.services.lambda.runtime.Context;

public class HelloWorldWithMultipleHandlersWithSameName {
  
 public String handler(String name) {
  return String.format("Hello %s.", name);
 }
  
 public String handler(String name, Context context) {
   
  return String.format("Hello %s%s.", name,   " Memory Allocated:" + context.getMemoryLimitInMB());
 }

}