Lambda functions in Java

Lambda functions in Java

Search for: Lambda functions in Java

When are they introduced? Java 8

They provide a clear and concise way to represent one method interface using an expression

Lambda expressions also improve the Collection libraries making it easier to iterate through, filter, and extract data from a Collection.

In addition, new concurrency features improve performance in multicore environments.


java.util.function
Predicate
Function

JButton testButton = new JButton("Test Button");
testButton.addActionListener(new ActionListener(){
    @Override public void actionPerformed(ActionEvent ae){
          System.out.println("Click Detected by Anon Class");
    }
});

The class born out of new ActionListener() has no name. So it does not get into the namespace issues.

It is inner to the parent class in which this code appears. That means the method body has access to the instance variables defined in the parent class where this code appears. (I think).

The rules of inner classes and static inner classes throw me off! Hope languages make these a bit more explicit and not hidden rules and exceptions.

The ActionListener example is an interface with only one method. With Java SE 8, an interface that follows this pattern is known as a "functional interface."

This type of interface, was previously known as a Single Abstract Method type (SAM).

Using functional interfaces with anonymous inner classes are a common pattern in Java.

In addition to the EventListener classes, interfaces like Runnable and Comparator are used in a similar manner. Therefore, functional interfaces are leveraged for use with lambda expressions.

A lambda expression is (appears to be) a syntactical shortcut to defining an anonymous inner class just like the one above

Being a shortcut, more than one is possible to arrive at an implementation of a single method as required by the functional interfaces like Runnable.

It seem to come in 2 key flavors: a) An expression and b) a block

This is equivalent to an object of the instantiation of an anonymous inner class


new SomeFunctionalInterface()
{
    @Override int somesingleMethod(int x, int y)
    {
        return (x+y);
    }
}

Going forward I will not show you this equivalency but it is the same for all shortcuts.

In the expression form (single statement) the expression is evaluated and returned.

No return statement is necessary. It is not the case with block which you will see next.

In this example, the method takes an input of string and prints it.

There is no return statement so nothing is returned.

In a block form you have to have a return statement if something needs to be returned

In a block form break and and continue are not allowed at the main line while allowed in loops.

A function that returns a number 42. Again a shortcut. Concept is same.


//Expression forms
(x,y) -> x + y //notice no semicolon
() -> 42

//A block form
(string s) { System.out.println(s); } //proper code block

() -> 42

Any lambda expression means, create me an object which confirms to the interface and whose method implementation is as I say here.


Runnable x = () -> System.out.println("hello");

//or you could have said

Runnable x = new SomeSuitableRunnableClass();

So it is a syntax to create object instances of anonymous inner classes. Wherever an object reference can be passed in what ever language context you can use this syntax.


Collections.sort(personList, 
  (Person p1, Person p2) -> 
     p1.getSurName().compareTo(p2.getSurName())
);

The second argument to sort is an object reference whose compare method takes 2 persons and returns an int based on their comparison. The list will then be sorted by that order.

What is target typing in Java?

Search for: What is target typing in Java?


public interface Predicate {
   public boolean test(T t);
}

Generics are quite sneaky. This predicate is a contract to say I will test something on the object you pass and tell you true or false. What I test i will tell you later.

What object get passed is also not known at this time. I will leave that to the future implementations.

Not only the method is specialized later, the type itself is unknown at this time.

Generics and the patterns they allow is a book by itself. But in this case this is a fairly simple "generic" interface.


Predicate allDrivers = p -> p.getAge() >= 16;
Predicate LionPredicate = animal -> animal.hasMane();

Now any normal java class can use the object references "allDrivers" and "LionPredicate" to test if a "Person" object is a driver or an "Animal" object is a lion.


Function westernStyle = p -> {
       return "\nName: " + p.getGivenName() + " " + p.getSurName() + "\n" +
              "Age: " + p.getAge() + "  " + "Gender: " + p.getGender() + "\n" +
              "EMail: " + p.getEmail() + "\n" + 
              "Phone: " + p.getPhone() + "\n" +
              "Address: " + p.getAddress();
     };
     
Function easternStyle =  p -> "\nName: " + p.getSurName() + " " 
             + p.getGivenName() + "\n" + "Age: " + p.getAge() + "  " + 
             "Gender: " + p.getGender() + "\n" +
             "EMail: " + p.getEmail() + "\n" + 
             "Phone: " + p.getPhone() + "\n" +
             "Address: " + p.getAddress(); 

Function is an interface that takes object of one type and converts it to another type.

As with generics the types can be any input type and any output type.

In this case a person object is taken and a properly formatted string is returned.

How does it know by looking at the code above if the input is a person and the output is a string. No such information is present in the above valid java segment.

Well, when the reference easternStyle and westernStyle are of type "Function". So the type information is accurately read from the definition of Function and also the method of the Function.

Although Function is a generic with 2 type arguments, it becomes de-genericized based on where these object references are used. The method in to which this object is passed will declare a Function object correctly.


//An example
Class Person
{
  doSomething(Function transformer)
  {
    //Generics know the apply method takes a Person
    //return transformer.apply(this);
  }
}

Predicate: A property of the object passed as argument

Consumer: An action to be performed with the object passed as argument

Function: Transform a T to a U

Supplier: Provide an instance of a T (such as a factory)

UnaryOperator: A unary operator from T -> T

BinaryOperator: A binary operator from (T, T) -> T

 public class Test03toList {
   
   public static void main(String[] args) {
     
     List pl = Person.createShortList();
     
     SearchCriteria search = SearchCriteria.getInstance();
     
     // Make a new list after filtering.
     List pilotList = pl
             .stream()
             .filter(search.getCriteria("allPilots"))
             .collect(Collectors.toList());
     
     System.out.println("\n=== Western Pilot Phone List ===");
     pilotList.forEach(Person::printWesternName);
 
   }
 
 }

Start with a collection and get a stream out of it. Apply filter to get another stream, then collect the resulting stream into a list.

Input streams are undisturbed. In that sense they are immutable as they go through processing like unix pipes.

Streams are lazy loaded

Parallel streams in Java 8

Search for: Parallel streams in Java 8

Project Lambda Website

Real background into the design approaches of lamdas in java

There is a lot of material here to go over to fully understand intricacies

A similar meaty discussion on streams

what is modeling code as data paradigm?

Search for: what is modeling code as data paradigm?

Refers to the verbose nature of specializing a single method and derive a new class and the number of lines it takes "vertically" taking space in your java file.

Read about Target typing here

the name of a functional interface is not part of the lambda expression syntax. So what kind of object does a lambda expression represent? Its type is inferred from the surrounding context

The compiler is responsible for inferring the type of each lambda expression. It uses the type expected in the context in which the expression appears; this type is called the target type. A lambda expression can only appear in a context that has a target type.

Of course, no lambda expression will be compatible with every possible target type. The compiler checks that the types used by the lambda expression are consistent with the target type's method signature.

T is a functional interface type

The lambda expression has the same number of parameters as T's method, and those parameters' types are the same

Each expression returned by the lambda body is compatible with T's method's return type

Each exception thrown by the lambda body is allowed by T's method's throws clause

Don't turn a vertical problem into a horizontal problem :)

Variable declarations

Assignments

Return statements

Array initializers

Method or constructor arguments

Lambda expression bodies

Conditional expressions ?:

Cast expressions

Determining the meaning of names (and this) in inner classes is significantly more difficult and error-prone than when classes are limited to the top level. Inherited members?including methods of class Object?can accidentally shadow outer declarations, and unqualified references to this always refer to the inner class itself.

Lambda expressions are much simpler: they do not inherit any names from a supertype, nor do they introduce a new level of scoping. Instead, they are lexically scoped, meaning names in the body are interpreted just as they are in the enclosing environment (with the addition of new names for the lambda expression's formal parameters). As a natural extension, the this keyword and references to its members have the same meaning as they would immediately outside the lambda expression.

Of course, if this inside a lambda expression refers to the enclosing class, it cannot also be used to refer to the function value described by the lambda expression. It is not usually necessary to do so, but on some occasions?say, when defining a recursive function?it is important.

Consistent with the lexical-scoping approach, and following the pattern set by other local parameterized constructs like for loops and catch clauses, the parameters of a lambda expression must not shadow any local variables in the enclosing context.

Java reduce function

Search for: Java reduce function

A tutorial on aggregate functions in Java


foreach()
  cur = reduce(cur,next);

It is a way to simulate functions, the ordinary, run of the mill type, in an OO language like java

It is a way to instantiate [materialized] interfaces

An object instantiated thus from a lambda expression is like a singleton object with no state [instance variables]

Any number of clients can call such an object with "no" effect due to parallelism.

Objects with instance variables cannot be paralleled, so an object born out of lambda expression not having any instance variables [leave aside read-only] can be used by anyone and doesn't have to be "new" ed for every usage. In other words it acts like a "function"

Signature of a lambda expression is defined by a single method interface. java.util.function package defines templates for a number of these reusable functions.

Role of method references in java lambda expressions

Search for: Role of method references in java lambda expressions

Role of default methods in java interfaces

Search for: Role of default methods in java interfaces

Formal definition of functional interfaces in Java

Search for: Formal definition of functional interfaces in Java


static methods
static variables

//These used to be in abstract classes
//now can be in interfaces itself
default functions

default methods in java interfaces

Search for: default methods in java interfaces

That means clients compiled with older interface still works when the interface is modified by adding new methods that are default.

This is a key distinction with abstract classes which can have a constructor and an implemented object state.

These default methods are more like templates in hook and template pattern where the template defines the semantics of calling while the hooks define the work.

PDF: Evolving interfaces, Brian Goetz

From the perspective of a client of the interface, extension methods are no different from ordinary interface methods. They are invoked via invokeinterface, they can be discovered and invoked reflectively, and the client does not care where the implementation comes from.

what are covariants?

Search for: what are covariants?

covariants and contravariants in programming languages

Search for: covariants and contravariants in programming languages

Here is an SOF article on this

This looks like a deep dive into generics leading to covariants and their contra versions

Worth reading Tomas Petricek

Relationship between mutability and covariance

Search for: Relationship between mutability and covariance

True type substitution, mutability and covariance

Search for: True type substitution, mutability and covariance

Banana is an object

Banana is a fruit

You can see banana as a fruit but still underneath it is a banana

when you see banana as a "fruit" there are no methods on "fruit" that will violate the contract that the underneath object is a banana.

So a banana is truly type compatible and substitutable as a fruit

A bucket of bananas are a bucket of fruits

Or is it, when you strictly look at it?

Follow me ....

You are blind folded

You got a gift of a bucket of bananas

Someone said you got a gift of a bucket of fruits

You open it, pick one and you eat it. Yes it is a fruit

You have an apple in your pocket

Apple is a fruit

You take the apple and drop it into the bucket (still blind folded) because you know it is not a bucket of chicken but a bucket of fruits, apple is a fruit, so you drop it.

Kaboom, the bucket BLOWS UP!! Because the sender put a JINX on it that anytime a NON BANANA comes into it, explode itself!

So by looking at a bucket of bananas ALL THE TIME as a bucket of fruits violated the initial contract that IT MUST BE ONLY A BUCKET OF BANANAs.

However there are cases when the bucket of bananas can be seen as a bucket of fruits as long as this special SPECIAL_LIST of fruits don't allow you to change (mutable) what is in the bucket GLOBALLY or (figure out - my extension - how to add only bananas!!!)

This is where immutable collection interfaces can keep type substitutability intact and hence called covariance.


List<Bananas> CANNOT BE SEEN as a List<Fruits>
But
List<Bananas> CAN BE SEEN as a Readonly_List_Of<Fruits>

:)

A compiler can then allow correctly the second case if there is a way for the compiler to know that.

I get it. By being immutable the methods have ensured it stays. But what if I find a sneaky way to add a banana, then it has changed and yet still holds.

For example there may be another client that keeps adding bananas to that bucket while the other client reading it.

Or perhaps the syntax of generics is in someways generalized that "no update" means "type stays the same".

This whole thing is closely tied to the rules of generics!

A List is a type. A Fruit is a type. So a List of Fruits is a "Type of Types"

So this idea may extend to any Type of Types and not just collections

Call them Parent Type and Child Type

All the methods on the parent type like the "list" must be valid for ALL derived types of child type (fruit for example)

Then the parent and child types seem to sing the same tune or they are said to be covariants!!

Because BananaList will have a method that says getBanana() and putBanana().

A FruitList will say getFruit() and putFruit()

You just can't cast it at all!

For all the nice things they do, the woes the types bring... You speak with lisp :)


If (Y is a sub type of X)
   (Apple is a Fruit)
and
if (T(Y) is a syb type of T(X))
   (List(Apples) is a List(Fruits))

Then types "X" and "T" are covariants

X -> Y
T(X) -> T(Y)

The fruit lens let you browse through a banana as if it is a fruit

Except if the fruit lens allows you slip a fruit through it won't work because the banana will not accept any fruit but only a banana


//Take this function
somefunction(Banana)
{
   //Perform operations involvign a banana
   Banana... getABanana();
   void ..setABanana(Banana)
}

//Clearly I can not pass a fruit
//compiler will not allow
//example
somefunction(fruit);

//sorry fruit is not a banana

Except, we promise in the function that we only use functions that are available with "fruit" and never invoke "banana" functions. Will it work then?

Say we do that. Even then the "get" function of a fruit will return a fruit, and if the someFunction is done through generics, then the compiler will expect a "banana" as the return type. So compiler will fail.

What if the function of the "fruit" is some kind of a set with a number of arguments that take fruits, but now gets passed bananas. This is acceptable for the compiler because the banana type is downcastable to a fruit.

This is contravariance, where we are able to pass functionality that is meant for base classes where a derived class is expected

Seeing Banana as a fruit: Covariant

Seeing fruit as a banana: Contravariance

If a function for a fruit is such that it can be used for a banana in a type safe way that is contravariance

So contravariance is upcasting where (Banana)(Any generic fruit)

Covariance is downcasting where (Fruit)(Banana)

Read only interfaces of underlying base classes results in covariance

Write only interfaces of underlying base clases results in contravariance

Java is an OO language. It has classes and objects. functions are not stand alone. they only exist in the context of a class.

Functions, the good old ones, don't carry state. A function CAN choose to update a state outside of its scope, which is usually not very good, but otherwise should return a value like any mathematical function.

An object on the other hand carries state through instance variables. Methods can use that state to accumulate over time or merely use as transitional data between method calls. Either approach makes the object single threaded. Such an object cannot be shared by multiple threads without controlling access to it by taking turns.

Sometimes all we need is a function that can be used a million times without recreating it again and again.

Lambda expressions provide a way to see a single method interfaces as functions. thats it. Everything else is gravy.

Now generics throws another abstraction on top of functions and colors with type safety for reuse etc.

You know that interfaces cannot be instantiated and have variables hold the the reference to such instantiated interfaces.

Because an interface has no body to execute code. So it needs a body. Typically this is done through a formal inheritance and only such implementation classes can then be instantiated in place of those interfaces.

Lambda expressions can be seen as materializing an interface on the fly by providing a body in line exactly in the same place where instantiation happens.

So one can see lambda expressions as instantiating interfaces!! :)