Can lambda expressions be the alternative of polymorphism?

Multi tool use


Can lambda expressions be the alternative of polymorphism?
I am learning lambda expressions and functional interfaces. We can directly write an implementation of the interface by the lambda expression. So I think, it could be the alternative for polymorphism.
I have some code using polymorphism,
interface Drawable {
public void draw();
}
class Shape {
protected String name;
public Shape(String name) {
this.name = name;
}
}
class Rectangle extends Shape implements Drawable {
public Rectangle(String name) {
super(name);
}
@Override
public void draw() {
System.out.println("I am "+this.name);
System.out.println("Drawing rectangle with 2 equal sides.");
}
}
class Square extends Shape implements Drawable {
public Square(String name) {
super(name);
}
@Override
public void draw() {
System.out.println("I am "+this.name);
System.out.println("Drawing square with 4 equal sides.");
}
}
public class DrawShape {
public static void main(String ar) {
Drawable rectangle = new Rectangle("Rectangle");
rectangle.draw();
Drawable square = new Square("Square");
square.draw();
}
}
I have written above code using lambda expressions and functional interface,
@FunctionalInterface
interface Drawable {
public void draw();
}
class Shape {
private String name;
public Shape(String name) {
this.name = name;
}
public void draw(Drawable d1) {
System.out.println("I am "+this.name);
d1.draw();
}
}
public class DrawShape {
public static void main(String args) {
Shape s1 = new Shape("Rectangle");
Drawable rectangle = () -> System.out.println("Drawing rectangle with 2 equal sides.");
s1.draw(rectangle);
Shape s2 = new Shape("Square");
Drawable sqaure = () -> System.out.println("Drawing square with 4 equal sides.");
s2.draw(sqaure);
}
}
Which is the better approach?
What about other aspects like code reusability, code maintenance and modification, coupling and cohesion etc for lambda?
@cricket_007 Yes. you are right, but if we try to simplify object creation it's draw implementation using factory or another design pattern?
– Kaustubh Khare
6 hours ago
Your second implementation, I don't think it is polymorphism, it's a normal function call. In general case, rectangle and square should have their own properties, you need two classes to represent these two types. What if you want two rectangle objects? Lambda is just a simple way to write anonymous inner class.
– zhh
6 hours ago
lambda expression should be used for functionality like anonymous inner class because it does like a function and doesn't need a name. In your example, Square, Shape is real object so declare new class will be preferable
– You're awesome
6 hours ago
They can’t be used “as an alternative to polymorphism”, in fact this doesn’t make any sense. But they can be used to achieve polymorphism. You seem to confuse polymorphism with one specific way of implementing it, namely subtype based polymorphism. What’s more, this is OOP in its original form, before Java misappropriated the term.
– Konrad Rudolph
58 mins ago
4 Answers
4
I would argue that lambda expressions allow developers to write fully polymorphic types, the way full class implementations do.
Polymorphism is often seen in two ways:
Drawable drawable = new Rectangle("name");
drawable.draw();
Shape shape = (Shape) drawable; //same object, multiple types.
And:
Drawable drawable2 = new Rectangle("name");
drawable2.draw(); //Rectangle.draw() implementation invoked
drawable2 = new Square("name");
drawable2.draw(); //Square.draw() implementation
Neither of these two is perfectly allowed for by lambda expressions:
Although one can do this:
Drawable drawable = () -> System.out.println("drawing rectangle");
drawable = () -> System.out.println("drawing square");
This is not strictly the same thing as the second code snippet above (in a more complex example, one would be able to provide a basic implementation in Shape
, and have it overridden in Rectangle
and Square
; and that wouldn't be possible with lambdas). Also, one would be correct to argue that the two assignments above use different source code.
Shape
Rectangle
Square
One can't just "cast" types as with classes:
Drawable drawable3 = () -> System.out.println("Drawing something");
Shape shape3 = (Shape) drawable3; //Class cast exception.
In other words, lambda expressions are a good fit for functional programming coding, not a substitute for good Object-Oriented design.
“The class version uses dynamic binding, whereas the lambda expressions depend on the compiler.”. This sentence makes no sense. Regardless of how the compiler implements them, the method call to
draw()
will use dynamic binding, and it will be exactly the same kind of dynamic binding, if Drawable
is an interface, as for calling an interface method, it is entirely irrelevant whether the implementation is an ordinary class or generated for a lambda expression.– Holger
28 mins ago
draw()
Drawable
@Holger Thanks for the remark. I suppose the point I want to make is that lambda expressions don't give the same possibilities as classes when it comes to virtual method invocations. This interface/implementation relationship makes my point less important, but polymorphism extends to classes as well.
– ernest_k
1 min ago
I am agree with @yelliver & @cricket_007, what you did is just using anonymous class instead of subclass.
You wrote
Shape s1 = new Shape("Rectangle");
Drawable rectangle = () -> System.out.println("Drawing rectangle with 2 equal sides.");
s1.draw(rectangle);
It is same like
Shape s1 = new Shape("Rectangle");
Drawable rectangle = new Drawable() {
@Override
public void draw() {
System.out.println("Drawing rectangle with 2 equal sides.");
}
};
s1.draw(rectangle);
So the two examples you created are not same. Your first example uses a subclass whereas the second one is using an anonymous class.
So I think, it could be the alternative for polymorphism
Clearly it is not an alternative, it is just another way to implement.
Benefits of lambda expression
in Java.
lambda expression
1. Fewer Lines of Code
In above example you can see anonymous class is changed by just ->.
2. Sequential and Parallel Execution Support by passing behavior in methods
You can iterate any collection by just using foreach()
. (example)
foreach()
list.forEach(item->System.out.println(item));
3. Lambda Expression and Objects
In Java, any lambda expression is an object as is an instance of a functional interface. We can assign a lambda expression to any variable and pass it like any other object (example) . like
list.sort((Developer o1, Developer o2)->o1.getAge()-o2.getAge());
Both the imperative style and the functional style has its own pros and cons. in this specific case using the functional style approach is better simply because you don't need to create a class for every case where you needed to encapsulate a single piece of functionality.
As one can quickly notice creating a class for every case where you needed to encapsulate a single piece of functionality leads to unnecessary boilerplate code
With the imperative approach, one could write code and make it up as you go. one may even end up writing classes upon classes without fully understanding what the implementation will be which may result in a large and unsustainable code base.
On the other hand, the functional approach forces one to better understand their implementation before & while we're coding.
That said, it’s very important to understand that functional programming itself should not be thought of as a "replacement" for object-oriented programming.
You may actually find your self-going back to the OOP approach when the business logic gets more complex.
lambda-expressions in Java 8 represents the instance of a functional interface (interface with only 1 method). In your 2nd approach, you just create a anonymous class. It does not make sense if you want to re-use code. For more information, you can refer to why/when to use anonymous class: How are Anonymous (inner) classes used in Java?
public static void main(String args) {
Shape s1 = new Shape("Rectangle");
Drawable rectangle = new Drawable() {
@Override
public void draw() {
System.out.println("Drawing rectangle with 2 equal sides.");
}
};
s1.draw(rectangle);
Shape s2 = new Shape("Square");
Drawable sqaure = new Drawable() {
@Override
public void draw() {
System.out.println("Drawing square with 4 equal sides.");
}
};
s2.draw(sqaure);
}
No, a lambda expression is not an interface with 1 method, that's called a functional interface.
– Wow
6 hours ago
@Wow lambda-expressions in Java 8 represents the instance of a functional interface
– yelliver
2 hours ago
Yes, please correct this in your answer.
– Wow
2 hours ago
…an interface with one
abstract
method which does not match a public
method of java.lang.Object
. Look at the Comparator
interface. It has lots of methods. After sorting out the default
and static
methods, there are still two abtract
methods left, but one matches a public
method of java.lang.Object
, so Comparator
is a functional interface…– Holger
23 mins ago
abstract
public
java.lang.Object
Comparator
default
static
abtract
public
java.lang.Object
Comparator
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Not every polymorphism example can be written this simply, though, so I feel like you're generalizing here. This is just deferring an action from a subclass to an anonymous one
– cricket_007
6 hours ago