繁体   English   中英

接受并返回相同类型的通用功能接口

[英]Generic Functional Interface that accepts and returns same type

我正在寻找一个满足以下两个要求的功能接口:

  • 应该接受并返回相同的类型
  • 在FunctionalInterface上调用方法时应推断类型

如果只是最初的要求,我可以创建一个简单的FunctionalInterface,如下所示:

@FunctionalInterface 
public interface MonoFunction<T> {
    T apply (T arg);
}

但是,这将需要在使用接口时指定类型。 但是,我想推断类型。 类似于下面的伪代码:

class A {
    int a;
}

class B {
    int b;
}

public static void main (String[] args) {
    A a;
    B b;

    MonoFunction foo = (obj) -> {
        system.out.println (obj)
        return obj;
    };

    a = foo.apply (new A());
    b = foo.apply (new B());
}

我如何实现这样的目标?

您可以使用UnaryOperator<T>但必须预先定义所需的类型。

UnaryOperator<A> foo = a -> {
    system.out.println(a);
    return a;
};

否则,只需将结果转换为变量类型:

a = (A) foo.apply (new A());
b = (B) foo.apply (new B());

使用通用工厂方法返回函数:

static <T> UnaryOperator<T> getFooFunction() {
    return obj -> {
        System.out.println(obj);
        return obj;
    };
}

public static void main (String[] args) {
    A a;
    B b;

    UnaryOperator<A> fooA = getFooFunction();
    a = fooA.apply(new A());
    UnaryOperator<B> fooB = getFooFunction();
    b = fooB.apply(new B());
    System.out.println(fooA==(Object)fooB);
}

请注意, getFooFunction()给定的当前实现(HotSpot / OpenJDK), getFooFunction()不仅在语义上返回相同的函数,甚至会是相同的对象,因为您可以通过fooA==(Object)fooB轻松进行测试,因此没有牺牲通用类型安全性的原因。

使用UnaryOperator.identity()时会发生相同的事情。

其他答案已经讨论了如何使用UnaryOperator<T> 尽管该方法提供了Java泛型的类型安全性,但是您仍然必须在创​​建UnaryOperator时指定类型。 尽管我会在大多数情况下建议使用UnaryOperator方法,但您特别地(在评论中)询问,即使必须放弃类型安全性,如何避免指定类型<T>

您可以按以下MonoFunction实现MonoFunction实现(不安全,通常不建议这样做):

public class MonoFunction {
    private UnaryOperator<Object> func;

    @SuppressWarnings("unchecked")
    public <T> MonoFunction(UnaryOperator<T> func) {
        this.func = (UnaryOperator<Object>) func;
    }

    @SuppressWarnings("unchecked")
    public <T> T apply(T obj) {
        return (T) func.apply(obj);
    }
}

请注意,这不是 @FunctionalInterface ,因此必须将lambda表达式放入new MonoFunction(...)调用中,如下所示:

public class MonoFunctionTest {
    public static void main(String[] args) {
        A a;
        B b;

        MonoFunction foo = new MonoFunction((obj) -> {
            System.out.println(obj);
            return obj;
        });

        a = foo.apply(new A()); // toString in A
        b = foo.apply(new B()); // toString in B

        MonoFunction bad = new MonoFunction((A obj) -> {
            System.out.println(obj);
            return obj;
        });

        a = bad.apply(a); // toString in A
        b = bad.apply(b); // ClassCastException: B cannot be cast to A
    }
}

class A {
    public String toString() { return "toString in A"; }
}
class B {
    public String toString() { return "toString in B"; }
}

我再次强调,这是不安全的,而且如所示,获得ClassCastException也相对容易。

在功能接口内使用通用方法可以实现:

@FunctionalInterface
interface Identity {
    < T > T apply( T input );
}

不幸的是,不能使用lambda函数实现这样定义的接口。 取而代之的是,它必须使用类以旧的方式完成,而最简洁的方法是使用匿名类:

Identity id = new Identity() {
    public < T > T apply( T anyInput ){
        // do something
        return anyInput;
    }
};

然后适用于任何输入:

class A {
    int a = 1;
}

String outputString = id.apply( "one" );
int outputInteger = id.apply( 1 );
A outputClass = id.apply( new A() );

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM