我有一个实现供应商的枚举,例如:
public enum QUERY_FIELD implements Supplier<String> {
PRODUCT_TYPE("ProductType"),
MIN_NUMBER_OF_PARTS("MinNumberOfParts"),
MAX_NUMBER_OF_PARTS("MaxNumberOfParts");
private final String id;
QUERY_FIELD(final String id) {
this.id = id;
}
@Override
public final String get() {
return id;
}
}
我有不同的实用程序方法,可以根据查询找到我搜索的枚举
public static <T extends Enum<T> & Supplier<String>> Optional<T> findById(final Class<T> enumClass, final String id) {
return Arrays.stream(enumClass.getEnumConstants()).filter(p -> id.equalsIgnoreCase(p.get())).findFirst();
}
public static <T extends Enum<T> & Supplier<? extends Number>> Optional<T> findById(final Class<T> enumClass, final Number id) {
return Arrays.stream(enumClass.getEnumConstants()).filter(p -> id.equals(p.get())).findFirst();
}
现在我想调整这个想法来创建一个实用程序方法,它只返回所有值的列表,具体取决于供应商类型。
我尝试过:
public static <T extends Enum<T> & Supplier<? extends String>> List<String> getValueList(final Class<T> enumClass) {
return Arrays.stream(enumClass.getEnumConstants()).map(Supplier::get).collect(Collectors.toList());
}
或
public static <U, T extends Enum<T> & Supplier<? extends U>> List<U> getValueList(final Class<T> enumClass) {
return Arrays.stream(enumClass.getEnumConstants()).map(Supplier::get).collect(Collectors.toList());
}
哪个都编译但不起作用, 我应该如何建立这种方法?
答案 0 :(得分:3)
我猜你在运行时问题中遇到的问题 在Enum, interfaces and (Java 8) lambdas: code compiles but fails at runtime; is this expected?中描述,并且是由Java-8 https://bugs.openjdk.java.net/browse/JDK-8141508中的已知错误引起的。
问题在于交叉点Enum<T> & Supplier<? extends String>
。似乎编译器生成代码,其中交集中的第二个元素丢失,因此在运行时,就好像您尝试将lambda用作不保证实现Supplier
的类的对象。只是Enum
。
由于getEnumConstant
适用于所有Class<X>
,无论是否为枚举,您都可以从param-type界限中丢弃该部分并将其保留为Supplier<String>
:
import java.util.function.*;
import java.util.*;
import java.util.stream.*;
enum Test implements Supplier<String> {
A, B, C;
public String get() { return name(); }
}
class Main {
public static <T extends Supplier<String>> List<String> getValueList(final Class<T> enumClass) {
return Arrays.stream(enumClass.getEnumConstants())
.map(Supplier::get)
.collect(Collectors.toList());
}
public static final void main(String[] args) {
System.out.println(getValueList(Test.class).stream()
.collect(Collectors.joining(",")));
}
}
然而,这样做的缺点是,如果有人提供的类不是枚举,编译器不会失败....为了防止你可以保持交集边界并添加额外的map
明确地将枚举常量强制转换为供应商:
public static <T extends Enum<T> & Supplier<String>> List<String> getValueList(final Class<T> enumClass) {
return Arrays.stream(enumClass.getEnumConstants())
.map(x -> (Supplier<String>) x) // not needed to compile but needed for run-time.
.map(Supplier::get)
.collect(Collectors.toList());
}
<强>更新强>
第二种选择有更好的解决方案。您可以在流外部执行一次转换,这可以节省您的计算:
public static <T extends Enum<T> & Supplier<String>> List<String> getValueList(final Class<T> enumClass) {
final Class<Supplier<String>> asSupplierClass = enumClass;
return Arrays.stream(asSupplierClass.getEnumConstants())
.map(Supplier::get)
.collect(Collectors.toList());
}
我没有测试过,让我知道它是否有效。