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

问题描述 投票:0回答:4

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

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

我如何实现这样的目标?

java function lambda functional-interface
4个回答
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());

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()时会发生同样的事情。


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相对容易。


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() );
© www.soinside.com 2019 - 2024. All rights reserved.