Introduction
Lambda expressions were introduced in Java 8, and the concept is little bit different than in C#. We'll go through how these things are implemented in C# and in Java. I'll write about related things as delegates and events which are not in Java, however, the observer and strategy pattern is also implemented in a different way.
C#
Delegates
Lambda expressions in C# are just a syntactic sugar to pass parameters to an anonymous method. Before lambdas delegate
keyword could be used to achieve the same thing. Delegate
s has a couple of benefits, e.g. we can invoke multiple methods via a delegate
and the important part is here, they behaves as a "method interface". Delegate
s provides the signature of methods which can be encapsulated. Delegate
s can be implemented as an anonymous method:
delegate double CalculatorMethod(int a, int b);
public void Execute()
{
CalculatorMethod multiply = delegate(int multiplicand, int multiplier)
{
return multiplicand * multiplier;
};
multiply(4, 8);
}
by lambda expression:
CalculatorMethod multiply = (multiplicand, multiplier) =>
{
return multiplicand * multiplier;
};
Almost the same syntax, just more simple.
What is the Real Benefit of Lambdas?
The most popular and useful utilization of Lambda expressions are related to Linq extension methods.
Consider this code:
var query = phoneBook.Where(p => p.Name.Contains("Jon"));
Here, we provided the strategy (by lambda) as an input parameter of "Where
" method.
What does "Where
" method do?
It does something like this, this is a simplified implementation (Linq to Objects):
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
foreach (TSource item in source)
{
if (predicate(item))
{
yield return item;
}
}
}
This method is an extension method of IEnumerable<TSource>
and accepts one input parameter:
Func<TSource, bool> predicate
This is a delegate
which provides a method signature: Accepts object
which type is TSource
and returns a bool
value. So when we previously provided that lambda, we have written an implementation for this delegate
.
The "Where
" method loops through the collection, and executes our lambda whatever it is and then returns only that records which meets the criteria.
Note: The implementation uses deferred execution, but that's not the point now.
Now we can see, that is a powerful tool to provide strategies easy way in action.
Java
Now there are Lambda expressions in Java too, however the delegate
concept still does not exist.
So how does it work?
Anonymous classes
In Java, we can use anonymous classes, which is a similar concept, because the delegates were method interfaces and here we have class interfaces. So we can implement methods via a simple interface.
Interface which contains a simple method:
public interface ListMethods {
List<String> SortFruits(List<String> original);
}
Here is a method which accepts the interface and then it will use its method to sort.
(Strategy pattern).
Our job is to provide the method of sort.
public List<String> StrategyTest(ListMethods strategy) {
List<String> fruits = Arrays.asList("Apple", "Tomato", "Currant",
"Cranberry");
return strategy.SortFruits(fruits);
}
We can implement the method with an anonymous class:
public List<String> getFuitsAnotherWay() {
ListMethods anonymMethods = new ListMethods() {
public List<String> SortFruits(List<String> original) {
Collections.sort(original);
return original;
}
};
return StrategyTest(anonyMethods);
}
Lambda Expressions
In Java 8, we can use lambda expression and as we can see the syntax is more simple than using an anonymous class.
public List<String> getFuitsAnotherWay() {
return StrategyTest((fruitList) -> {
Collections.sort(fruitList);
return fruitList;
});
}
Limitation of Lambda Expression
Consider this interface:
public interface ListMethods {
List<String> SortFruits(List<String> original);
List<String> FilterFruits(List<String> original);
}
We can no longer implement this interface by lambda, because it can implement only functional interfaces. That is reasonable because the compiler can't decide which method is implemented exactly by the lambda.
This approach is quite similar to delegates in C#.
However, we can implement this interface by an anonymous class:
public List<String> getFuitsAnotherWay() {
ListMethods anonyMethods = new ListMethods() {
public List<String> SortFruits(List<String> original) {
Collections.sort(original);
return original;
}
public List<String> FilterFruits(List<String> original) {
if (original.size() > 2)
original.remove(2);
return original;
}
};
return StrategyTest(anonyMethods);
}
Another interesting pattern which is related to this topic is observer pattern.
The observer pattern can be implemented by class interfaces, and there are many Java or C# examples about that, but in .NET framework, the observer pattern is implemented in Events and Eventhandlers by delegates.
Related article (Exploring the Observer Design Pattern) can be found at http://msdn.microsoft.com/en-us/library/ee817669.aspx.