【问题标题】:Get String values from supplier enum in java从java中的供应商枚举中获取字符串值
【发布时间】:2017-10-03 11:44:36
【问题描述】:

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

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

两者都编译但不起作用, 我应该如何构建这个方法?

【问题讨论】:

  • “不工作”是什么意思?你期望得到什么输出,而你得到了什么?
  • 你为什么不把你的枚举实例命名为ProductTypeMinNumberOfParts等,然后你可以使用values().name()
  • 刚刚添加并回答我相信可以解决您的问题。为了找到它的原因,我不得不复制你的代码(带有一些模块)并获取运行时堆栈跟踪。然后我只需要谷歌异常类和错误消息来找到解决方案。这么说只是为了指出在您的问题中包含/发布您收到的错误消息有多重要,而不是说它不起作用。

标签: java lambda enums


【解决方案1】:

我猜你遇到的问题是运行时问题 在 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&lt;T&gt; &amp; Supplier&lt;? extends String&gt;。似乎编译器生成的代码在交集的第二个元素丢失的地方,所以在运行时,就好像你试图为 lambda 使用一个不能保证实现 Supplier 但只是 @ 987654325@。

由于getEnumConstant 可用于所有Class&lt;X&gt;,无论X 是否为枚举,您都可以简单地从参数类型绑定中丢弃该部分并将其保留为Supplier&lt;String&gt;

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

我没有测试过,告诉我它是否有效。

【讨论】:

    猜你喜欢
    • 2013-07-18
    • 2010-10-10
    • 1970-01-01
    • 2020-07-11
    • 2021-04-04
    • 2017-08-01
    • 2010-12-07
    • 2016-12-22
    相关资源
    最近更新 更多