v->v>5 的含义解释

3

我有一个给定的函数调用,Java给出了一个错误,因为对象与int不可比较(当然...)。有人能解释一下我需要改变什么吗?

我尝试以不同的方式括起lambda表达式,但没有任何有用的结果。我认为lambda表达式是正确的,过滤函数略有问题,但我无法找出我的错误...

// 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();
    }
}

我原以为会得到一个 Optional.empty-Object,但由于 Object v 不可与 int 进行比较,而导致了 java 错误。具体来说,是因为 v > 5


2
同时查看完整的代码块会更好。您在哪里使用了 filter,并且您试图推断出什么结果? - Naman
不可能。你返回了 this,这意味着你的类应该扩展 Optional,但它是 final 的。你有自己的 Optional 吗? - Andrew Tobilko
4个回答

4

您需要将T变成一个包装类,使其可以与int进行比较。例如:

IntStream.range(0, 10)
         .filter(v -> v > 5)
         .forEach(System.out::println);

因为v是一个int,所以这是没有问题的。

T未知时,您无法使用此表达式。

您可以假设T必须是一个数字,例如:

filter( v -> ((Number) v).doubleValue() > 5)

然而,如果T是另一种类型,这将会产生一个ClassCastException异常。

真正的解决方案是让T成为Number类型。

例如:

class MyClass<T extends Number> {
    public Optional<T> filter(Predicate<T> test) {

或者将其指定为特定类型,例如int

class MyClass {
    public IntOptional filter(IntPredicate test) {

3
这个类是一个通用类。将 v 强制转换为 Number 并使用 doubleValue() 来使其与 Predicate<T> 兼容看起来像是一种 hack。问题在于该类中的 T 声明。 - davidxxx

3
在Java中,基本类型(例如int)和对象(例如Object)在类型层次结构中没有共同的祖先。因此,谓词和其他流结构有两种类型,例如有IntPredicate,当使用int时必须使用该类型,而当使用Object时必须使用Predicate

编写您的过滤函数的一种方法是使用OptionalIntIntPredicate

public OptionalInt filter(IntPredicate tester) {
    if (isPresent() && tester.test(get())) {
        return ...
    } else {
        return OptionalInt.empty();
    }
}

注意:T extends NumberPredicate<T> 将是可以接受的。 - Peter Lawrey
@PeterLawrey,您说得完全正确,装箱是另一个选项。 - Karol Dowbecki
有没有一种方法可以在不更改函数头中的Optional<T>和Predicate<T>的情况下实现这一点?因为我真的不想改变函数头。 - Hugugagegi
@PeterLawrey使用public Optional<T> filter(Predicate<T extends Number> tester) {很遗憾不起作用。 - Hugugagegi
@Hugugagegi 当你第一次声明 <T extends Number> 时,可能是在 class Xxxx<T extends Number> 行上,你才能定义它。 - Peter Lawrey

3

v -> v > 5 可以有不同的含义,具体取决于上下文。

  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);
    

2
我认为,lambda表达式是正确的,而过滤函数略有问题,但我无法找出我的错误...
你是正确的。你的方法似乎打败了类中声明的通用类型,因为首先你的方法定义在一个通用类内。
假设你的类名为Foo,在这里filter()方法依赖于通用类型T作为返回/参数类型:
public class Foo<T>{
     // ...
    public Optional<T> filter(Predicate<T> tester) { 
      // ...
    }
}

它与推理一起工作。
因此,您会得到TPredicate。但是T取决于类中定义的泛型类型,也取决于您声明Foo类实例的方式。
并且看起来这里的T不是一个Number

作为替代方案,您还可以依靠从声明的Foo变量中推断的参数。
如果您这样做:

Foo<Integer> foo = new Foo<>();
Optional<Integer> optInt = foo.filter(v -> v > 5);

如果从Foo<Integer>中推断出Integer,那么编译将正常进行。

因此我认为,要解决你的问题,你应该将NumberInteger声明为泛型类型的基类:

public class Foo<T extends Integer>{
     // ...
    public Optional<T> filter(Predicate<T> tester) { 
      // ...
    }
}

或者像前面的例子一样,依赖于客户端的推断。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接