我正在尝试定义以下匿名Google Guava Function实例:
Function<E extends Enum<E>, String> ENUM_TO_STRING = new Function<E extends Enum<E>, String>() {
@Override
public String apply(E enumValue) {
String result = null;
if (enumValue != null) {
result = enumValue.toString();
}
return result;
}
};
这个想法是一个简单的转换函数实例,带有apply方法,如果不为null,则对任何枚举值调用toString;如果值为null,则返回null。
不幸的是,编译器抱怨通用引用E扩展Enum。我知道这个表达式可以在非匿名上下文中使用,例如:
public static <E extends Enum<E>> String enumToString(E enumValue) {
String result = null;
if (enumValue != null) {
result = enumValue.toString();
}
return result;
}
第一个,匿名类定义不行。第二个非匿名方法定义是OK。
无论如何使用Enums定义匿名类?
由于
答案 0 :(得分:4)
作为Sotirios points out,泛型类型参数只能为类或方法而不是字段声明。事实上,声明E
可能是不必要的 - Function<Enum<?>, String>
可以没问题:
Function<Enum<?>, String> ENUM_TO_STRING = new Function<Enum<?>, String>() {
@Override
public String apply(Enum<?> enumValue) {
if (enumValue != null) {
return enumValue.toString();
}
return null;
}
};
遵循这一思路,toString
由Object
宣布,而不是Enum
,因此一般Function<Object, String>
更有意义:
Function<Object, String> NULLABLE_TO_STRING = new Function<Object, String>() {
@Override
public String apply(Object obj) {
if (obj != null) {
return obj.toString();
}
return null;
}
};
通常,最好隐藏工厂方法背后的实现细节,以便将来更改更容易,例如:
private static final Function<Object, String> NULLABLE_TO_STRING = ...
public static Function<Object, String> nullableToString() {
return NULLABLE_TO_STRING;
}
请注意,仍然会返回Function<Object, String>
。只要您的API使用PECS(例如接受Function<? super Foo, ? extends Bar>
),这应该没问题,但我们也可以通过使方法通用来进一步提供特定的输入类型:
private static final Function<Object, String> NULLABLE_TO_STRING = ...
public static <T> Function<T, String> nullableToString() {
@SuppressWarnings("unchecked") // safe contravariant cast
final Function<T, String> withNarrowedType =
(Function<T, String>)(Function<?, String>)NULLABLE_TO_STRING;
return withNarrowedType;
}
请注意,它使用相同的Function
实例,并使用未经检查的强制转换来缩小其输入类型。演员是安全的,因为NULLABLE_TO_STRING
接受任何对象并且是无国籍的。这种模式在Joshua Bloch的Effective Java第27项“赞成泛型方法”中得到了证明。
答案 1 :(得分:2)
您不能在任何地方使用泛型类型变量。您必须处于可以声明且可访问的上下文中。
在第二个示例中,它们在方法签名中声明。
在您的第一个示例中,似乎E
在任何地方都没有声明。换句话说,您不能将类型变量声明为变量声明的一部分。如果代码片段中出现的方法或类声明了类型变量E
本身,那么你可以做你正在尝试的事情。
答案 2 :(得分:0)
你可能根本不需要泛型,因为你实际上并没有使用类型信息,而且它在运行时也会丢失。首先使用old-school Function apply(Enum enumValue)开始。如果你真的不想压制警告并需要进行类型检查,那么你可以从那里进一步调查。