我在很多地方都有Function<Foo,Foo>。我本质上想将其别名为FooTransformer。我的第一次尝试是。


interface FooTransformer extends Function<Foo,Foo>{}


当我尝试编写FooTransformer时,结果是来自类型类型系统的抱怨

class Foo {}

interface FooTransformer extends Function<Foo,Foo> {}


public void TestFoo(){
    //two differently named identity transforms
    FooTransformer t1 = foo -> foo;
    FooTransformer t2 = foo -> foo;

    FooTransformer t3 = t1.andThen(t2);
}


这失败了


  错误:(93,39)java:不兼容的类型:不存在类型为V的实例,因此java.util.function.Function符合org.broadinstitute.hellbender.tools.walkers.bqsr.ReadTransformerTest。 FooTransformer


通过修改FooTransformer重载andThen我的代码可以编译并运行。

interface FooTransformer extends Function<Foo,Foo> {
    default FooTransformer andThen(FooTransformer after){
        return Function.super.andThen(after)::apply;
    }
}


我现在虽然收到此警告(将Javac 1.8.0_25与--Xlint:all结合使用)


  警告:[FooTransformer中的[overloads] andThen(FooTransformer)is
  与andThen(Function)可能存在歧义
  功能
         默认FooTransformer andThen(FooTransformer之后){
                               ^
   其中V,R,T是类型变量:
     V扩展在方法andThen中声明的对象(函数扩展V>)
     R扩展接口函数中声明的对象
     T扩展了接口函数中声明的对象


我真正想要的是Function<Foo,Foo>的类型别名,这是我所能获得的最接近的别名。有没有更好的方式来完成此操作而不会发出警告?

最佳答案

我不知道您使用了哪个编译器,因此无法测试我提出的解决方案是否可以解决您的警告。收到警告的原因是因为您的andThen方法与继承的方法Function.andThen非常相似,但不会覆盖它。一种可能的解决方案是也显式重写方法Function.andThen

interface FooTransformer extends Function<Foo,Foo> {

    @Override
    public default <V> Function<Foo, V> andThen(Function<? super Foo, ? extends V> after) {
        return Function.super.andThen(after);
    }
    default FooTransformer andThen(FooTransformer after){
        Objects.requireNonNull(after);
        return foo -> after.apply(apply(foo));
    }
}


然后应该清楚知道您的andThen不会像其他方法那样覆盖该方法。但是,正如我所说,我无法测试这是否会使警告消失。

此警告可能尝试解决另一方面。如果您使用interface参数类型重载了方法,则对于有人尝试用实现两个interface的具体类型调用任一方法的情况,可能会造成歧义。这在这里不适用,因为一种参数类型是另一种参数的子类型,因此它永远不会模棱两可,但是javac似乎不够聪明,无法识别这一点。因此,您可以与javac开发人员进行讨论,希望以后的版本不发出警告,但是,在该方法中添加@SuppressWarnings("overloads")是更简单的解决方案……



请注意,我更改了实现,以不将Function.super.andThen的结果包装到FooTransformer中。尽管方法引用是将任意接口实例转换为另一个接口的一种好方法,但我认为,当已知实际实现且在这种情况下如此简单时,应避免将一个函数包装到另一个函数中的开销。



请注意,您可以考虑让FooTransformer扩展UnaryOperator<Foo>,这是Function<Foo,Foo>的子接口。所以一切都像以前一样工作,但是您可以选择将FooTransformer的实例与List.replaceAllStream.iterateAtomicReference.updateAndGet一起使用…

07-26 04:08