Java lambda expression - how interface name was omitted?

Alexei Martianov :

I'm reading oracle tutorial on lambda expressions: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

To specify the search criteria, you implement the CheckPerson interface:

interface CheckPerson {
    boolean test(Person p); }    

then use it

printPersons(
    roster,
    new CheckPerson() {
        public boolean test(Person p) {
            return p.getGender() == Person.Sex.MALE
                && p.getAge() >= 18
                && p.getAge() <= 25;
        }
    }
);

then

The CheckPerson interface is a functional interface. A functional interface is any interface that contains only one abstract method. (A functional interface may contain one or more default methods or static methods.) Because a functional interface contains only one abstract method, you can omit the name of that method when you implement it. To do this, instead of using an anonymous class expression, you use a lambda expression, which is highlighted in the following method invocation:

printPersons(
    roster,
    (Person p) -> p.getGender() == Person.Sex.MALE
        && p.getAge() >= 18
        && p.getAge() <= 25
);

They say they omit the method, I see no test in lambda - that is clear. But they also dropped name of interface CheckPerson. Why is it not mentioned in explanation? Do we use the CheckPerson interface in lambda or not?

ADDED on 2019/08/29:
Thank you Alexey Soshin, Andrew Tobilko, Andreas (in the time order of answering), for your answers! I see your answers as complimenting each other to give full picture and therefore I cannot choose only one as accepted.

Andreas :

For all intents and purposes, a lambda expression is syntactic sugar for simplifying how you write an anonymous class.

That's not entirely true, because the compiler doesn't actually generate an anonymous class (though it could have), and things like keyword this changes meaning, but otherwise it really is very similar.

So, the code using anonymous class is:

new CheckPerson() {
    public boolean test(Person p) {
        return p.getGender() == Person.Sex.MALE
            && p.getAge() >= 18
            && p.getAge() <= 25;
    }
}

Now, since the compiler knows that the second parameter of printPersons must be a CheckPerson object, it can infer that when it sees a lambda expression. Since the interface only has one method, it can also infer that you need to implement such a method.

You must however still list the parameters, which means if you remove everything that can be inferred from the first two lines:

new CheckPerson() {
    public boolean test(Person p) {

you get:

(Person p) -> {

where the -> is the lambda expression syntax telling the compiler to infer the rest.

So far we've reduced:

new CheckPerson() {
    public boolean test(Person p) {
        return p.getGender() == Person.Sex.MALE
            && p.getAge() >= 18
            && p.getAge() <= 25;
    }
}

to:

(Person p) -> {
    return p.getGender() == Person.Sex.MALE
        && p.getAge() >= 18
        && p.getAge() <= 25;
}

Now we apply more syntactic sugar, i.e. let the compiler do more of the work, to remove "template" stuff.

  • The parameter type can be inferred, so no need to give it.

  • If there is only one parameter, no need for () parentheses.

  • If the only statement in the method is a return statement, remove the {} braces, the return keyword, and the ; semi-colon, leaving just a normal expression.

The result:

p -> p.getGender() == Person.Sex.MALE
  && p.getAge() >= 18
  && p.getAge() <= 25

That is the short-hand lambda expression (syntactic sugar) for doing the same as the original anonymous class.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=141779&siteId=1