2

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.

Alex Martian
  • 3,423
  • 7
  • 36
  • 71
  • 2
    Check signature of `printPersons` method. Its second parameter is of `CheckPerson` type. There's no need to specify it so in lamda expression its omitted. – bhusak Aug 28 '19 at 16:51

3 Answers3

4

Do we use the CheckPerson interface in lambda or not?

We don't use it, we define it. We give it an implementation. We implement that interface by writing a lambda expression.

"in lambda" is your misunderstanding, because the lambda is an instance of that interface.

They say they omit the method, I see no test in lambda - that is clear. But they also dropped name of interface CheckPerson.

It's not about "dropping" or "omitting" something. It's about replacing one syntactical construction with another. You replace an anonymous class with a lambda expression to make your code more expressive and less verbose.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • thank you, I missed it's invocation not declaration. – Alex Martian Aug 28 '19 at 17:02
  • 2
    Lambda isn't strictly an instance in itself, because it can't reference its own identity. You wouldn't be able to call its `default` methods from lambda body, like you would be able to if you implement the same body using anonymous class. – M. Prokhorov Aug 28 '19 at 17:02
  • 1
    @M. Prokhorov, "Lambda isn't strictly an instance in itself, because it can't reference its own identity" - that is interesting. can you provide a link where I can read more details? – Alex Martian Aug 28 '19 at 17:06
  • @AlexeiMartianov actually, it's a declaration. An invocation will be somewhere in the method `printPersons ` – Andrew Tobilko Aug 28 '19 at 17:09
  • from tutorial: 'To do this, instead of using an anonymous class expression, you use a lambda expression, which is highlighted in the following method **invocation**:' - so it is invocation of printPersons with declaration of lambda, is it correct to put that way? – Alex Martian Aug 28 '19 at 17:15
  • 2
    @AlexeiMartianov "the following invocation" **of the method printPersons**, not of the lambda you are passing in – Andrew Tobilko Aug 28 '19 at 17:17
  • @AlexeiMartianov, See [here](https://stackoverflow.com/q/33108540/7470253) a comment by Brian Goetz. There are also some other links in there. – M. Prokhorov Aug 29 '19 at 15:14
3

It's called SAM (single abstract method) type in Java, and yes, interface is still used.

Let's look the signature of printPersons:

public static void printPersons(List<Person> roster, CheckPerson tester)

So, Java compiler knows that if you provide it with a lambda, this lambda should comply to single method CheckPerson provides.

Alex Martian
  • 3,423
  • 7
  • 36
  • 71
Alexey Soshin
  • 16,718
  • 2
  • 31
  • 40
1

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.

Andreas
  • 154,647
  • 11
  • 152
  • 247