1
    package com.test.lambda;

    import java.util.function.Supplier;

    class Document {
        void printAuthor() {
            System.out.println("Document-Author");
        }
    }

    class RFP extends Document {
        @Override
        void printAuthor() {
            System.out.println("RFP-Author");
        }
    }

    public class TestLambda1 {
        public static void function21() {
            Supplier<Document> s1 = Document::new; // working
            Supplier<Document> s2 = RFP::new; // (1)

            Supplier<? extends Document> s3 = Document::new; // working
            Supplier<? extends Document> s4 = RFP::new; // working

            Supplier<? super Document> s5 = Document::new; // working
            Supplier<? super Document> s6 = RFP::new; // (2)

            Supplier<? super RFP> s7 = Document::new; // (3)
            Supplier<? super RFP> s8 = RFP::new; // working

        }

        public static void main(String[] args) throws Exception {
            function21();
        }

    }

Problem in (1) (2) & (3) is that, it should work as java 1.7 (1) : it should give error as only Document type should be accepted. (2) : it should give error as only super type of Document should be accepted. (3) : it should be working as super of RFP can hold Document object. Difference between <? super T> and <? extends T> in Java

Naman
  • 27,789
  • 26
  • 218
  • 353
  • 2
    What part of the linked answer can you not correlate? Since those answers are quite detailed already. – Naman Sep 19 '19 at 03:38
  • Obviously, type inference is pretty complex, but I would expect (1) and (2) to work. `RFP::new` certainly does produce a Document object, after all. I agree that (3) should work. You can actually cast it, `(Supplier) Document::new`, and it will compile without any errors or warnings. – VGR Sep 19 '19 at 04:04
  • @VGR in this case, it’s not that complex. That’s due to the deliberate cuts the language designers made precisely to avoid (an even higher) complexity. – Holger Sep 19 '19 at 11:43

1 Answers1

3

It’s weird to insist on “it should work as java 1.7”, when in Java 1.7 resp. Java 7 there were no method references at all.

When you write a statement like

Supplier<Document> s2 = RFP::new;

You have to make a distinction between the type of the variable, the type of the function, and the actual implementation. You can easily write the equivalent

Supplier<Document> s2 = new Supplier<Document>() {
    public Document get() {
        return new RFP();
    }
}; // (1)

due to covariant return types, you can also write

Supplier<Document> s2 = new Supplier<Document>() {
    public RFP get() {
        return new RFP();
    }
}; // (1)

So the type of the variable matches the type of the function, whereas the implementation returns an instance of a more specific type.

When you write

Supplier<? extends Document> s3 = Document::new; // working
Supplier<? extends Document> s4 = RFP::new; // working

Supplier<? super Document> s5 = Document::new; // working
Supplier<? super Document> s6 = RFP::new; // (2)

the type of the function will differ. You can not write new Supplier<? extends Document>() { … } nor new Supplier<? super Document>() { … } and so the compiler will infer a type that can be instantiated, which simply is the target type type without ? extends or ? super. So it’s equivalent to

Supplier<? extends Document> s3 = (Supplier<Document>)Document::new; // working
Supplier<? extends Document> s4 = (Supplier<Document>)RFP::new; // working

Supplier<? super Document> s5 = (Supplier<Document>)Document::new; // working
Supplier<? super Document> s6 = (Supplier<Document>)RFP::new; // (2) just like (1)

which are valid instantiations (like in the first block), followed by legal assignments.

The problem with

Supplier<? super RFP> s7 = Document::new; // (3)

lies exactly in the type inference logic described above. The type inference will use the type without ? super, and (Supplier<RFP>)Document::new is not valid. So here, we have to provide an explicit type to make it valid:

Supplier<? super RFP> s7 = (Supplier<Document>)Document::new; // (3)

which follows the same pattern as the second block.
You can not implement a Supplier<? super RFP>. You can implement a supplier like Supplier<Document> which is assignable to Supplier<? super RFP>. When the target type has wildcards, the strategy to just strip off the wildcards often helps but sometimes doesn’t.

Holger
  • 285,553
  • 42
  • 434
  • 765