There will be few new features included in Java 8. Lambda expressions are one of them. They provide a concise and clear way to represent method interface using an expression. Labda represents an anonymous function like anonymous classes well known from previous java releases, but with clean and simple syntax.
Lambda expression is a block of code with parameters, you can use it whenever you want, a block of code is executed at later point of time.
Up to now, giving someone a block of code hasn’t been easy in Java. Java is an object-oriented language, so you had to construct an object belonging to a class that has a method with the desied code.
The syntax of lambda expression
1 2 |
(String first, String second) -> {Integer.compare(first.length(), second.length()); } |
What is that? The code above is build from three parts:
– parameters,
– an arrow sign,
– the expression
If a lambda expression has no parameters, you still supply empty parentheses:
1 2 3 4 |
() -> { for( int i = 0; i < 1000; i++) doSomething(); } |
You can skip parameter types of a lambda expression if it can be inferred
1 2 |
Comparator<String> computation = (first, second) -> Integer.compare(first.length(), second.length()); |
As you see above you can also skip curly braces if you use single expression for computation only. In example above compiler can deduce that first
and second
must be strings because the lambda expression is assigned to a string comparator.
If a method has a single parameter with inferred type, you can even omit the parentheses:
1 2 3 |
EventHandler<ActionEvent> listener = event -> Logger.debug("Button clicked!"); //Instead of (event) -> or (ActionEvent event) |
Parameters can be declared as final
or with annotations:
1 2 |
(final String name, @NotNull String email) -> ... |
Result type is never defined. It is always inferred from context.
Functional Interfaces
There are many existing interfaces in Java that encapsulate blocks of code. Good examples are: Comparator
, Callable
, Runnable
or EventHandler
.
Lambdas are backward compatible with these interfaces.
Functional Interfaces are interfaces with single abstract method. You can supply a lambda expression whenever an object of such interface is expected.
To demonstrate the conversion to functional interface look at Array.sort
method. Its second parameter requires an instance of Comparator
. Comparator
is single method interface as I told above. Example how it works:
1 2 |
Arrays.sort( words, (first, second) -> Integer.compare(first.length(), second.length())); |
What was made behind the scenes? The Arrays.sort
receives an object of some class that implements Comparator<String>
. Invoking the compare
method on that object executes the body of the lambda expression. The management of these objects and classes is completely implementation dependent, and it can be much more efficient than using traditional expression as a function, not an object, and to accept that it can be passed to a functional interface.
In fact, conversion to a functional interface is the only thing you can do with a lambda expression in Java. In other programming languages that support function literals, you can declare function types such as (String, String) -> int
, declare variables of those types, and use the variables to save function expressions.
The java.util.function
package
The Java API defines a number of very generic functional interfaces in the java.util.function
package. Take a look on few of them:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public interface Predicate<T>{ boolean test(T t); } public interface Function<T, R>{ R apply(T t); } public interface binaryOperator<T>{ T apply(T left, T right); } public interface Consumer<T>{ void accept(T t); } public interface Supplier<T>{ T get(); } |
You can use it with your own code when work with lambdas
Example:
Supposing we had a functional interface named Predicate
declared as follows:
1 2 3 4 |
public inteface Predicate<T>{ boolean test(T t); } |
And we have Person
entity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class Person { public enum Gender { MALE, FEMALE } private String name; private Gender gender; private int age; //getters and setters } |
We can write utility method that filter an array of Person
entities as we want. We use as first parametes list of entities, and as second Predicate
interface to check filtering conditions as follows:
1 2 3 4 5 6 7 8 9 10 |
public static filter(Collection<Person> community, Predicate<Person> predicate) { Collection<Person> result = new ArrayList<Person>(); for(Person p : community){ if(predicate.text(p)){ result.add(p); } } return result; } |
Now we can filter our collection as we want, for example:
1 2 3 |
Collection<Person> males = Person.filter(getPersonCollection(), person -> Person.Gender.MALE == person.getGender());//filtering only Males. Collection<Person> young = Person.filter(getPersonCollection(), person -> person.getAge() < 35);//filter by age lower than 35 |
In examples above getPersonCollection()
is method that return Collection<Person>
object.
.