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

时间:2018-05-12 08:18:06

标签: java function lambda functional-interface

我正在寻找满足以下两个要求的功能界面:

  • 应接受并返回相同类型
  • 在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());
}

我如何实现这样的目标?

4 个答案:

答案 0 :(得分:0)

您可以使用UnaryOperator<T>,但您必须事先定义您期望的类型。

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

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

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

答案 1 :(得分:0)

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

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)的情况下,它甚至会是同一个对象,因为您可以通过fooA==(Object)fooB轻松测试,所以没有理由牺牲Generic的类型安全性。

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

答案 2 :(得分:0)

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

您可以按如下方式进行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相对容易。

答案 3 :(得分:0)

这可以通过功能接口内的通用方法来实现:

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