DISCLAIMER: I'm sorry but I couldn't get your question, still I think I could be in favor with adding my toughts. Hopefully not so many "downs" for it :)
It's all about perspective. If I have to explain what a lambda is and how to use it, than I will use the following abstraction:
- Functional interface:
- Single abstract method signature(stucked with public as it's an interface member -> generics, return type, argument types, throws clause ->
public <T> void processT(T t)
, public <T,R> R evalT(T t)
etc.)
- Could have zero or more non abstract methods (default/static).
- Abstract method has no access to other instance members at any point!
- Lambdas:
- Pure method implementations(or as I call them anonymous method implementations for known functional interfaces). In order for compiler to recognize lambda statement as a valid one it should meet a method singature from any known functional interface at compile time(The target tape could be not annotated with @FunctionalInterface rather than having a single abstract method and being interface itself(ref for abstract classes).
Now, lets take closer look for your particular example:
Consumer -> a void method that accepts one argument(generic, specified type) and does some processing based on the input.
Let's consider your code now, and small showcases that I've added there for you.
import java.util.function.Consumer;
public class ConsumerTest {
@Data
public static class Person{
private Integer id;
private String name;
private String surName;
}
@Data
public static class Student{
private Integer id;
private Person person;
}
public static void main(String args[])
{
Student student = new Student();
student.setId(1);
Person person = new Person();
person.setName("Ali");
person.setSurName("Veli");
person.setId(2);
student.setPerson(person);
/* shorthand definition for anonymous implementation in place, recognisable signature */
Consumer<Student> displayLambda = s -> s.getPerson().setSurName("Gülsoy");
/* full definition for anonymous implementation in place, allows annotations */
Consumer<Student> anotherDisplayLambda = new Consumer<Student>() {
@Override
public void accept(Student student) {
student.getPerson().setSurName("Gülsoy");
}
};
// And finally:
/* acquires reference to anonymous implementation with recognisable signature */
Consumer<Student> yetAnotherDisplayLambda = ConsumerTest::thisIsAMethodButAlsoAConsumer;
/* invokes the implementations, a.k.a. method call, method invocation */
displayLambda.accept(student);
anotherDisplayLambda.accept(student);
yetAnotherDisplayLambda.accept(student);
/* also valid statements, but this time it captures instance member, so make sure how it works under the hood */
displayLambda = anotherDisplayLambda::accept; // same as `displayLambda = anotherDisplayLambda`
}
// if you can "retrieve that function" here than you should be able to answer your question as well...
private static void thisIsAMethodButAlsoAConsumer(Student student) {
student.getPerson().setSurName("Gülsoy");
}
}
Now, lets keep digging:
import java.util.function.Consumer;
public class ConsumerTest {
@Data
public static class Person{
private Integer id;
private String name;
private String surName;
}
@Data
public static class Student{
private Integer id;
private Person person;
}
private interface AnotherTypeOfInterface /* extends Consumer<Student> */
{
// if you can "retrieve that function" here than you should be able to answer your question as well...
void consumeStudentObject(Student student);
}
public static void main(String args[])
{
Student student = new Student();
student.setId(1);
Person person = new Person();
person.setName("Ali");
person.setSurName("Veli");
person.setId(2);
student.setPerson(person);
/* Target interface is not annotated as functional, still we got things done :)
* If you comment out the extend clause in AnotherTypeOfInterface then @FunctionalInterface annotation will be required */
AnotherTypeOfInterface anotherTypeOfConsumer = ConsumerTest::thisIsAMethodButAlsoAConsumer;
/* throwsException in thread "main" java.lang.ClassCastException: ConsumerTest$$Lambda$3/2093631819 cannot be cast to
* java.util.function.Consumer, unless you comment out the extend clause in interface definition */
// Consumer<Student> interfacesAreStillTypes = anotherTypeOfConsumer;
/* but this one doesn't throw as it parses all it needs -> anonymous method signature and definition... */
Consumer<Student> yetAnotherTypeOfConsumer = anotherTypeOfConsumer::consumeStudentObject
/* invokes the implementation */
anotherTypeOfConsumer.consumeStudentObject(student);
// interfacesAreStillTypes.accept(student);
yetAnotherTypeOfConsumer.accept(student);
}
}
In the latter example, AnotherTypeOfInterface would have a single method called consumeStudentObject
which will match Consumer::accept
yet, Consumer instances comes with their own set of members, like Consumer::andThen
.