【发布时间】:2018-12-20 21:48:22
【问题描述】:
我偶然发现了这个。这是短篇小说。在一些代码库中有一堆遵循相同模式的枚举,这里有一个大大简化的:
enum Letters {
A("a"),
Z("z");
private String value;
Letters(String value) {
this.value = value;
}
private static final Map<String, Letters> MAP;
public String getValue() {
return value;
}
static {
MAP = Arrays.stream(values())
.collect(Collectors.collectingAndThen(
Collectors.toMap(
Letters::getValue,
Function.identity()
),
ImmutableMap::copyOf
));
}
public static Optional<Letters> fromValue(String value) {
return Optional.ofNullable(MAP.get(value));
}
}
这是一个跨越数十个枚举的模式,从字面上看,这是无法更改的。我考虑过更改此代码重复,因为它很多。
我的想法是从一个枚举接口开始,所有接口都会实现:
interface GetValueInterface {
String getValue();
}
还有一些将处理此 MAP 创建的通用代码(fromValue 也将在那里处理,但让我们把它放在一边)。所以,是这样的:
static class EnumsCommon {
public static <T extends Enum<T> & GetValueInterface> Map<String, T> getAsMap(Class<T> clazz) {
T[] values = clazz.getEnumConstants();
return Arrays.stream(values)
.collect(Collectors.collectingAndThen(
Collectors.toMap(
T::getValue,
Function.identity()
),
ImmutableMap::copyOf
));
}
}
所以代码现在看起来像这样:
enum Letters implements GetValueInterface {
// everything else stays the same
static {
MAP = EnumsCommon.getAsMap(Letters.class);
}
}
这编译得很好,但是当我在java-8下运行它时,抛出了一个异常:
原因:java.lang.invoke.LambdaConversionException: Invalid receiver type class java.lang.Enum;不是实现类型接口GetValueInterface的子类型
在java-11 下运行相同的代码可以正常工作...
【问题讨论】:
-
为什么是
T::getValue而不仅仅是GetValueInterface::getValue? -
@FedericoPeraltaSchaffner 我最初也尝试过,但结果相同
-
好的,看来这是一个已修复的类型推断错误。解决方案(正如您在自己的回答中所展示的)是不使用方法引用并为 lambda 表达式提供具有显式类型的参数。
-
@FedericoPeraltaSchaffner 我不认为这是一个类型推断错误顺便说一句,但更多的内容被删除以及如何删除,它应该被删除到
GetValueInterface,而不是枚举,如果会有两个接口,简单地交换它们也可以解决它,似乎
标签: generics lambda enums java-8 java-stream