从java中的供应商枚举中获取字符串值

时间:2017-10-03 11:44:37

标签: java lambda enums

我有一个实现供应商的枚举,例如:

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());
}

哪个都编译但不起作用, 我应该如何建立这种方法?

1 个答案:

答案 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());
    }

我没有测试过,让我知道它是否有效。