我正在寻找满足以下两个要求的功能界面:
如果要求刚刚成为第一个,我可以创建一个简单的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());
}
我如何实现这样的目标?
答案 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() );