使用 Java 8 Stream API 查找枚举值

假设有一个名为 Type 的简单枚举,定义如下:

enum Type{
    X("S1"),
    Y("S2");

    private String s;

    private Type(String s) {
        this.s = s;
    }
}

使用带有for-loop的静态方法(假设该方法在枚举内定义),为给定找到正确的枚举是微不足道的,例如:s

private static Type find(String val) {
        for (Type e : Type.values()) {
            if (e.s.equals(val))
                return e;
        }
        throw new IllegalStateException(String.format("Unsupported type %s.", val));
}

我认为 Stream API 所表达的功能等效物是这样的:

private static Type find(String val) {
     return Arrays.stream(Type.values())
            .filter(e -> e.s.equals(val))
            .reduce((t1, t2) -> t1)
            .orElseThrow(() -> {throw new IllegalStateException(String.format("Unsupported type %s.", val));});
}

我们怎样才能写得更好、更简单呢?这个代码感觉是强制性的,不是很清楚。特别笨拙和滥用,因为它不会积累任何东西,不执行任何计算并且总是简单地返回(前提是过滤器返回一个值 - 如果不是,那显然是一场灾难),更不用说是否有多余的和令人困惑的。然而,我在Stream API中找不到任何只是以某种方式直接从.reduce()t1t2TStream<T>

有没有更好的方法?


答案 1

我会改用:findFirst

return Arrays.stream(Type.values())
            .filter(e -> e.s.equals(val))
            .findFirst()
            .orElseThrow(() -> new IllegalStateException(String.format("Unsupported type %s.", val)));


虽然在这种情况下可能会更好:Map
enum Type{
    X("S1"),
    Y("S2");

    private static class Holder {
        static Map<String, Type> MAP = new HashMap<>();
    }

    private Type(String s) {
        Holder.MAP.put(s, this);
    }

    public static Type find(String val) {
        Type t = Holder.MAP.get(val);
        if(t == null) {
            throw new IllegalStateException(String.format("Unsupported type %s.", val));
        }
        return t;
    }
}

我从这个答案中学到了这个技巧。基本上,类装入器在枚举类之前初始化静态类,这允许您填充枚举构造函数本身。非常方便!Map

希望它有帮助!:)


答案 2

接受的答案效果很好,但是如果要避免使用临时数组创建新流,则可以使用 。EnumSet.allOf()

EnumSet.allOf(Type.class)
       .stream()
       .filter(e -> e.s.equals(val))
       .findFirst()
       .orElseThrow(String.format("Unsupported type %s.", val));