OCP Question 42, Explanation

Given:

class Browser {
    public void surf() {
        System.out.print("See me surf!");
    }
}
class Tor extends Browser {
    public void surf() {
        System.out.print("Stealth mode engaged.");
    }
}

and the code fragment:

class Tails {
    public static void main(String[] args) {
        surf(() -> new Browser());
        surf(Tor::new);
    }
    /* line n1 */
}

Which code fragment, when inserted at line n1, enables the Tails class to compile?

A. static void surf(Consumer<Browser> browser) { browser::surf(); }
B. static void surf(Consumer<? extends Browser> browser) { browser.accept().surf(); }
C. static void surf(Supplier<Browser> browser) { browser.get().surf(); }
D. static void surf(Supplier<? extends Browser> browser) { browser::surf(); }

 

The correct answer is C.

 

The key to solving this Problem is the lambda expression in Tails: its paramlist is empty, which immediately eliminates options A and B because Consumer’s functional method needs an arg.

Duly noted; now, how to choose between C and D? Option C has everything the code requires: Supplier’s get() produces an object of type Browser and then we call surf() on this object.

At the Review stage we also have to check if option D is indeed incorrect. Okay, Supplier generates an object whose type can be either Browser or Object, then we invoke the metref browser::surf()… Do you notice anything out of the ordinary here? You should. Because metrefs never make use of parens. Which instantly gets rid of option D (or A, for that matter).

But what if this was just a silly typo on the part of the exam creators? We’ve already seen on multiple occasions that the questions may be formulated incorrectly or, at the very least, ambiguously. What if option D had browser::surf in it? Would it work?

No, it wouldn’t. Because this notation – { browser::surf; } – is nonsensical. No meaning whatsoever. It’s gibberish, pure and simple. Why? Well, metrefs are single-liners that are meant as tidy, compact replacements for lambdas. They are lumps of syntactical sugar, nothing more. Now please tell me, how can we make use of a lambda in a method body? Basically, we’ve got only two ways to do so:

– define a var whose type is a functional interface, like this:

static void surf(Supplier<Browser> browser) {
    Supplier<Browser> supp = () -> new Browser();
    supp.get().surf();
}

and, should we desire so, restyle it to flaunt a metref:

static void surf(Supplier<Browser> browser) {
    Supplier<Browser> supp = Browser::new;
    supp.get().surf();
}

– or call a functional method, and since interfaces can’t be instantiated, we might do it via an anonymous class, like this:

static void surf(Supplier<Browser> browser) {
    (new Supplier<Browser>(){
        public Browser get(){ return new Browser();}
    }).get().surf();
}

Yeah, what a horror… Anyway, option D in its unmodified form simply does not provide an appropriate spot to place a lambda or metref. On a side note please observe that re-parameterizing Supplier in option C to <? extends Browser> works without a hitch since the extends keyword here also includes the lower bound, which is Browser.

Leave Comment

Your email address will not be published.