Search code examples
javarunnable

Java runnable object expected but passed in a method


I don't quite understand this line:

article.getMoneyBackGuarantee().on(today).claim(this::offerMoneyBack);

in the below code:

public class Demo {
private void offerMoneyBack() {
    System.out.println("Offer money back.");
}

private void offerRepair() {
    System.out.println("Offer repair.");
}

public void claimWarranty(Article article) {
    LocalDate today = LocalDate.now();

    article.getMoneyBackGuarantee().on(today).claim(this::offerMoneyBack);
    article.getExpressWarranty().on(today).claim(this::offerRepair);

    System.out.println("-----------------");
}

public void run() {
    LocalDate sellingDate = LocalDate.now().minus(40, ChronoUnit.DAYS);
    Warranty moneyBack1 = new TimeLimitedWarranty(sellingDate, Duration.ofDays(60));
    Warranty warranty1 = new TimeLimitedWarranty(sellingDate, Duration.ofDays(365));

    Article item1 = new Article(moneyBack1, warranty1);

    this.claimWarranty(item1);
    this.claimWarranty(item1.withVisibleDamage());
    this.claimWarranty(item1.notOperational().withVisibleDamage());
    this.claimWarranty(item1.notOperational());

    Article item2 = new Article(Warranty.VOID, Warranty.lifetime(sellingDate));
    this.claimWarranty(item2.withVisibleDamage().notOperational());
}


public interface Warranty {
    Warranty on(LocalDate date);
    default void claim(Runnable action) { action.run(); }

    Warranty VOID = new VoidWarranty();

    static Warranty lifetime(LocalDate issuedOn) {
        return new LifetimeWarranty(issuedOn);
    }
}

The getMoneyBackGuarantee() and on() methods both return a Warranty object, and the implementation of all Warranty objects has the same claim() method. My question is, how does this run? The claim method is expecting a runnable object, but we pass it a method reference instead? (e.g. this::offerMoneyBack)


Solution

  • Runnable is a functional interface, as such, it can be replaced by a lambda expression or a method reference.
    This is what you got here - claim(Runnable action) can get any lambda or method reference to a method that meets the Runnable#run signature - getting zero parameters and return void, regardless if this method is called run or if the class implements the interface - if the signature fits - it can work as functional interface.