noob
noob

Reputation: 23

This in a default method in interface

In my understanding the way lambdas work is similar to creating instance of an anonymous class and providing the implementation of an abstract method - please feel free to comment on this

I have also been looking into combinator pattern in Java and getting confused by "this" in the and method of the below interface, in my understanding, this refers to a current instance of a class. When I am doing System.out.println(this) in the and method, it prints combinatorpatttern.CustomerRegistrationValidator$$Lambda$4/0x0000000800067440@12f40c25, which is not making sense as to what class this is referring to.

public interface CustomerRegistrationValidator
        extends Function<Customer, ValidationResult> {
  
   static CustomerRegistrationValidator isEmailValid() {
        return customer -> {
            System.out.println("running email validation");
            return customer.getEmail().contains("@") ?
                    SUCCESS : EMAIL_NOT_VALID;
        };
    }

    static CustomerRegistrationValidator isPhoneNumberValid() {
        return customer -> customer.getPhoneNumber().startsWith("+0") ?
                SUCCESS : PHONE_NUMBER_NOT_VALID;
    }

    static CustomerRegistrationValidator isAnAdult() {
        return customer ->
                Period.between(customer.getDob(), LocalDate.now()).getYears() > 16 ?
                        SUCCESS : IS_NOT_AN_ADULT;
    }
    
    default CustomerRegistrationValidator and (CustomerRegistrationValidator other) {
        return customer -> {
            
            ValidationResult result = this.apply(customer);
            return result.equals(SUCCESS) ? other.apply(customer) : result;
        };
    }

    enum ValidationResult {
        SUCCESS,
        PHONE_NUMBER_NOT_VALID,
        EMAIL_NOT_VALID,
        IS_NOT_AN_ADULT
    }
}


public class Main {

    public static void main(String[] args) {
        Customer customer = new Customer(
                "Alice",
                "[email protected]",
                "+0898787879878",
                LocalDate.of(2015, 1,1)
        );
        
        ValidationResult result = isEmailValid()
                .and(isPhoneNumberValid())
                .and(isAnAdult())
                .apply(customer);

        System.out.println(result);
    }
}

Upvotes: 2

Views: 94

Answers (1)

Sweeper
Sweeper

Reputation: 273530

In the first and call:

isEmailValid().and(isPhoneNumberValid())

this refers to the object returned by isEmailValid().

In the second and call:

isEmailValid().and(isPhoneNumberValid()).and(isAnAdult())
                                         ^^^

this refers to the object returned by the first and call. If that is not very clear, you can think of this as two steps:

CustomerRegistrationValidator isEmailAndPhoneValid = 
    isEmailValid().and(isPhoneNumberValid());

// "this" refers to "isEmailAndPhoneValid"
isEmailAndPhoneValid.and(isAnAdult());

You should now see the pattern, that this refers to whatever is immediately before the and. The fact that it's in an lambda expression doesn't make much of a difference. It's the method that it is in, that matters.

What are the objects returned by isEmailValid() and and then? As you can see from the source code, both are declared to return an instance of a class that implements the interface CustomerRegistrationValidator, so those lambda expressions must evaluate to such objects. What is the class of those objects? Well, they are automatically generated, and have names like this:

combinatorpatttern.CustomerRegistrationValidator$$Lambda$4/0x0000000800067440@12f40c25

Hence the output when you print this.

Upvotes: 1

Related Questions