5

If I have:

public class MyClass{
    MyClass(Object b){
        //Some code here
    }
}

And I do:

MyClass X = new MyClass(new SomeOtherClass());

It works just fine, im assuming, because every class has Object as a superclass.

But, if I do:

import java.util.function.Predicate;
public class MyClass{
    MyClass(Predicate<Object> b){
        //Some more code here
    }
}

And then:

MyClass X = new MyClass((SomeOtherClass s) -> {
    //Even more code
    return true;
});

I get an error saying:

Incompatible parameter types in lambda expression: expected Object but found SomeOtherClass

Shouldn't I be able to send a SomeOtherClass object in that lambda expression? I'm using the Object class because i wanna be able to recieve not only SomeOtherClass, but also SomeOtherClassXPTO. I tried looking this up and found nothing so far, so my apologies in advance if this has been asked before.

Joao
  • 41
  • 1
  • 3
  • 12

3 Answers3

3

Well, when you defined your predicate as Predicate<Object> it's restricted to only accept objects which getClass() method returns Object.

For this method to work you would be doing something like Predicate<? extends Object> but this does not make much sense. Use Predicate<?> alone then.

Otherwise, another way to solve this is to find the common denominator of your two classes, probably a parent class and use Predicate<? extends ParentClass>.

A final solution would be to create, depending on your application logic, an interface and implementing the interface by both objects to be able to something like the following Predicate<? extends YourInterface>

Yassin Hajaj
  • 21,337
  • 9
  • 51
  • 89
  • Seeing that `java.util.function.Predicate` is a "consumer" type, it doesn't make much sense to use `extends`-bounded wildcards in any case. – newacct May 28 '18 at 01:22
  • @newacct I dont know what you mean about this sentence. It makes total sense to me. Can you expand? – Yassin Hajaj May 28 '18 at 04:15
  • In Java there is a mnemonic: PECS -- "producer `extends`, consumer `super`". Basically, a class that only uses `T` by returning it is a "producer" of `T`, and should always be used with `? extends` bounds; whereas a class that only uses `T` by taking it as a parameter is a "consumer" of `T`, and should always be used with `? super` bounds. `Predicate` mainly takes `T` as a parameter in its `test` method, so is a consumer, and should be used with `? super` bounds. – newacct May 28 '18 at 05:50
  • If you think about it, a value of type `Predicate extends Something>` isn't useful, because you cannot pass anything but `null` to its `test` method. – newacct May 28 '18 at 05:50
1

Inheritance does not work for Generic parameter, the official doc about can be found here


You need to

MyClass(Predicate<? extends Object> b) {
    //Some more code here
}

or

MyClass(Predicate<?> b) {
    //Some more code here
}
azro
  • 53,056
  • 7
  • 34
  • 70
1

As you know, the following is valid:

Object o = new SomeOtherClass();

But, this doesn't apply to generics, because generics are not covariant:

Predicate<Object> p;

p = (SomeOtherClass s) -> false; // compiler error - incompatible parameter types...

The only possible assignment to the Predicate<Object> is:

Predicate<Object> p = object -> ... ;

At the same time, the input to this predicate can be of any type:

p.test(new Object());
p.test("");
p.test(99);

As stated in the Yassin's answer, consider Predicate<? extends Type> in order to gain flexibility.

Oleksandr Pyrohov
  • 14,685
  • 6
  • 61
  • 90