Hugugagegi
Hugugagegi

Reputation: 55

Explanation for v-> v>5

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

Answers (4)

Peter Lawrey
Peter Lawrey

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

davidxxx
davidxxx

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

Andrew
Andrew

Reputation: 49656

v -> v > 5 can mean different things. It depends on context.

  1. 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);
    
  2. 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);
    
  3. 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

Karol Dowbecki
Karol Dowbecki

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

Related Questions