Reputation: 55
I have a given function call and java gives me an error because Objects are not comparable to ints (of course...). Can someone explain to me what I have to change?
I tried to brace the lambda expression differently but with no useful result. I think, that the lambda expression is correct and the filter-function is slightly wrong, but I'm not able to find out my mistake...
// function call
filter(v -> v > 5)
// function
public Optional<T> filter(Predicate<T> tester) {
if(isPresent() && tester.test(get())) {
return this;
} else {
return Optional.empty();
}
}
I would expect a Optional.empty-Object but I get a java-error because v > 5
Object v is not comparable to an int.
Upvotes: 3
Views: 125
Reputation: 533870
You have to make T
a wrapper class which is comparable with an int. e.g.
IntStream.range(0, 10)
.filter(v -> v > 5)
.forEach(System.out::println);
is fine because v
is an int
.
You can't use this expression when T
is unknown.
What you can do is assume the T
must be a number e.g.
filter( v -> ((Number) v).doubleValue() > 5)
however this will produce a ClassCastExpection is T
is another type.
The real solution is to make T
a Number
e.g.
class MyClass<T extends Number> {
public Optional<T> filter(Predicate<T> test) {
or make it a specific type like int
class MyClass {
public IntOptional filter(IntPredicate test) {
Upvotes: 4
Reputation: 131526
I think, that the lambda expression is correct and the filter-function is slightly wrong, but I'm not able to find out my mistake...
You are right.
Your method seems to defeat the generic type declared for the class as first of all your method is defined inside a generic class.
Supposing your class is named Foo
, here the filter()
method relies on the generic T
type as return/parameter type :
public class Foo<T>{
// ...
public Optional<T> filter(Predicate<T> tester) {
// ...
}
}
It works with inference.
So you get Predicate
of T
. But the T
depends on the generic type defined in the class and also from the way which you declared the instance of the Foo
class.
And it appears that here T
is not a Number
.
As alternative you could also rely on inference from the declared Foo variable.
If you do that :
Foo<Integer> foo = new Foo<>();
Optional<Integer> optInt = foo.filter(v -> v > 5);
it will compile fine as Integer
will be inferred from Foo<Integer>
.
So I think that to solve your issue, you should either declare Number or Integer as base class of the generic type :
public class Foo<T extends Integer>{
// ...
public Optional<T> filter(Predicate<T> tester) {
// ...
}
}
or rely on the inference of the client as in the previous example.
Upvotes: 2
Reputation: 49656
v -> v > 5
can mean different things. It depends on context.
It could be a (Object v) -> v > 5
causing a compilation error since >
can't be applied to an Object
:
Stream.<Object>of("123", 123).filter(v -> v > 5);
It could be a (Integer v) -> v > 5
meaning that unboxing and autoboxing will be performed in order to do the comparison and to return the result:
Stream.<Integer>of(123, 123).filter(v -> v > 5);
It could be a (int v) -> v > 5
meaning that it's an instance of IntPredicate
and things will go smoothly here:
IntStream.of(123, 123).filter(v -> v > 5);
Upvotes: 3
Reputation: 44980
In Java primitives types (e.g. int
) and objects (e.g. Object
) don't have a common ancestor in the type hierarchy. Due to that predicates and other stream constructs come in two flavors e.g. there is IntPredicate
that you have to use when working with int
and Predicate
that you have to use when working with Object
.
On way to write your filter function would be to use OptionalInt
and IntPredicate
:
public OptionalInt filter(IntPredicate tester) {
if (isPresent() && tester.test(get())) {
return ...
} else {
return OptionalInt.empty();
}
}
Upvotes: 3