Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Java8流API查找枚举值_Java_Enums_Functional Programming_Java 8_Java Stream - Fatal编程技术网

使用Java8流API查找枚举值

使用Java8流API查找枚举值,java,enums,functional-programming,java-8,java-stream,Java,Enums,Functional Programming,Java 8,Java Stream,假设有一个名为Type的简单枚举定义如下: enum Type{ X("S1"), Y("S2"); private String s; private Type(String s) { this.s = s; } } private static Type find(String val) { return Arrays.stream(Type.values()) .filter(e -> e

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

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

    private String s;

    private Type(String s) {
        this.s = s;
    }
}
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));});
}
对于给定的
s
,使用带有for循环的静态方法(假设该方法是在enum中定义的)查找正确的enum非常简单,例如:

我认为用流API表示的功能等价物如下:

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

    private String s;

    private Type(String s) {
        this.s = s;
    }
}
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));});
}
我们怎样才能写得更好更简单呢?这段代码给人的感觉是强制性的,不是很清楚。
reduce()
看起来特别笨重和被滥用,因为它不积累任何东西,不执行任何计算,总是简单地返回
t1
(如果过滤器返回一个值-如果它不返回,那显然是一场灾难),更不用说
t2
是否有多余和混乱。然而,我在流API中找不到任何简单地直接从
流返回
t
的东西


有更好的方法吗?

我会使用
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;
    }
}
枚举类型{
X(“S1”),
Y(“S2”);
私有静态类持有者{
静态映射映射=新的HashMap();
}
私有类型(字符串s){
持有者。地图。放置(s,本);
}
公共静态类型查找(字符串val){
类型t=Holder.MAP.get(val);
如果(t==null){
抛出新的IllegalStateException(String.format(“不支持的类型%s.”,val));
}
返回t;
}
}
我从中学会了这个把戏。基本上,类加载器在枚举类之前初始化静态类,这允许您在枚举构造函数本身中填充
Map
。非常方便


希望有帮助!:)

findAny()
代替
reduce
怎么样

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

我还不能添加评论,所以我发布了一个答案来补充上述内容,只是遵循相同的想法,但使用java 8方法:

public static Type find(String val) {
    return Optional
            .ofNullable(Holder.MAP.get(val))
            .orElseThrow(() -> new IllegalStateException(String.format("Unsupported type %s.", val)));
}

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


你需要一个字符串s的getter。 在下面的示例中,此方法是
getDesc()


我知道这个问题很老,但我是从一个重复的问题来的。我的答案并不是严格地回答OP关于如何使用Java流解决问题的问题。相反,此答案扩展了中提出的基于
映射的解决方案,使其更易于管理(IMHO)

这里就是:我建议引入一个特殊的助手类,我将其命名为
EnumLookup

假设
类型
枚举编写得稍微好一点(有意义的字段名+getter),我将向它注入一个
枚举查找
常量,如下所示:

enum Type {

    X("S1"),
    Y("S2");

    private static final EnumLookup<Type, String> BY_CODE = EnumLookup.of(Type.class, Type::getCode, "code");

    private final String code;

    Type(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }

    public static EnumLookup<Type, String> byCode() {
        return BY_CODE;
    }
}
请注意:

  • 我在这里用了番石榴,但是可以用常规的
    HashMap
    LinkedHashMap
    来代替

  • 如果您不介意在上述方法中缺少延迟初始化,您可以延迟
    EnumLookup
    的构建,直到第一次调用
    byCode
    方法(例如,使用,如中的)


  • 我认为Alexis C.()的第二个答案在复杂性方面是好的。而不是每次使用

    return Arrays.stream(Type.values())
            .filter(e -> e.s.equals(val))
            .findFirst()
            .orElseThrow(() -> new IllegalStateException(String.format("Unsupported type %s.", val)));
    
    通过将所有元素放入映射,可以在加载类时使用O(n)时间,然后使用映射以恒定时间O(1)访问该类型的代码

    enum Type{
    X("S1"),
    Y("S2");
    
    private final String code;
    private static Map<String, Type> mapping = new HashMap<>();
    
    static {
        Arrays.stream(Type.values()).forEach(type-> mapping.put(type.getCode(), type));
    }
    
    Type(String code) {
        this.code = code;
    }
    
    public String getCode() {
        return code;
    }
    
    public static Type forCode(final String code) {
        return mapping.get(code);
    }
    }
    
    枚举类型{
    X(“S1”),
    Y(“S2”);
    私有最终字符串代码;
    私有静态映射=新HashMap();
    静止的{
    Arrays.stream(Type.values()).forEach(Type->mapping.put(Type.getCode(),Type));
    }
    类型(字符串代码){
    this.code=代码;
    }
    公共字符串getCode(){
    返回码;
    }
    公共静态类型forCode(最终字符串代码){
    返回mapping.get(代码);
    }
    }
    
    字符串s需要一个getter,但我使用的模式是:

    private static final Map<String, Type> TYPE_MAP = 
        Collections.unmodifiableMap(
            EnumSet.allOf(Type.class)
            .stream()
            .collect(Collectors.toMap(Type::getS, e -> e)));
    
    public static Type find(String s) {
        return TYPE_MAP.get(s);
    }
    
    private静态最终映射类型\u映射=
    集合。不可修改的映射(
    EnumSet.allOf(Type.class)
    .stream()
    .collect(Collectors.toMap(Type::get,e->e));
    公共静态类型查找(字符串s){
    返回类型\u MAP.get(s);
    }
    

    没有循环,只有流。快速查找,而不是每次调用该方法时都构建流。

    我知道这个评论不会被任何人投票,但与Java 8一样好的是,您不必对每个问题都使用
    stream
    s。你的for-loop方法比任何使用
    Stream
    s的方法都更清晰(更快)。@pbabcdefp好吧,我认为这是一个好的评论,但如果我投了更高的票,那么你评论中的第一句话就错了,这意味着我必须再次投反对票,然后我会再次认为这是一个好的评论,所以我必须投更高的票,但是第一句话就错了。。。我想我即将抛出
    StackOverflowException
    …@pbabcdefp-这可能是一个意见问题,但我发现lambdas越来越优于迭代,而且清晰性几乎总是胜过效率。我确信我尝试了
    findFirst()
    ,在IDEA中遇到了一些奇怪的编译错误,并编写了
    reduce()
    变体。无论如何,我对你所有的答案都投了赞成票,但我觉得
    第一个
    任何一个
    都要清楚,所以我选择了它。谢谢你的帮助!这是一个非常巧妙的技巧,我特别喜欢JVM如何保证串行映射填充-非常好。只有一个小建议-我们可以通过去掉字段
    s
    使代码更加紧凑,因为它在其他地方没有使用。
    findAny()
    而不是
    findFirst()
    ?--如果保证有一个(或零个)匹配项,那么潜在的
    findAny()
    将更快地得到答案(尽管我想枚举是否足够大以便搜索可以并行化值得怀疑)@slim随着流的顺序,
    findFirst()
    在多次匹配的情况下,表现出与原始java 8之前的代码相同的行为。虽然我
    public final class EnumLookup<E extends Enum<E>, ID> {
    
        private final Class<E> enumClass;
        private final ImmutableMap<ID, E> valueByIdMap;
        private final String idTypeName;
    
        private EnumLookup(Class<E> enumClass, ImmutableMap<ID, E> valueByIdMap, String idTypeName) {
            this.enumClass = enumClass;
            this.valueByIdMap = valueByIdMap;
            this.idTypeName = idTypeName;
        }
    
        public boolean contains(ID id) {
            return valueByIdMap.containsKey(id);
        }
    
        public E get(ID id) {
            E value = valueByIdMap.get(id);
            if (value == null) {
                throw new IllegalArgumentException(String.format(
                        "No such %s with %s: %s", enumClass.getSimpleName(), idTypeName, id
                ));
            }
            return value;
        }
    
        public Optional<E> find(ID id) {
            return Optional.ofNullable(valueByIdMap.get(id));
        }
    
        //region CONSTRUCTION
        public static <E extends Enum<E>, ID> EnumLookup<E, ID> of(
                Class<E> enumClass, Function<E, ID> idExtractor, String idTypeName) {
            ImmutableMap<ID, E> valueByIdMap = Arrays.stream(enumClass.getEnumConstants())
                    .collect(ImmutableMap.toImmutableMap(idExtractor, Function.identity()));
            return new EnumLookup<>(enumClass, valueByIdMap, idTypeName);
        }
    
        public static <E extends Enum<E>> EnumLookup<E, String> byName(Class<E> enumClass) {
            return of(enumClass, Enum::name, "enum name");
        }
        //endregion
    }
    
    return Arrays.stream(Type.values())
            .filter(e -> e.s.equals(val))
            .findFirst()
            .orElseThrow(() -> new IllegalStateException(String.format("Unsupported type %s.", val)));
    
    enum Type{
    X("S1"),
    Y("S2");
    
    private final String code;
    private static Map<String, Type> mapping = new HashMap<>();
    
    static {
        Arrays.stream(Type.values()).forEach(type-> mapping.put(type.getCode(), type));
    }
    
    Type(String code) {
        this.code = code;
    }
    
    public String getCode() {
        return code;
    }
    
    public static Type forCode(final String code) {
        return mapping.get(code);
    }
    }
    
    private static final Map<String, Type> TYPE_MAP = 
        Collections.unmodifiableMap(
            EnumSet.allOf(Type.class)
            .stream()
            .collect(Collectors.toMap(Type::getS, e -> e)));
    
    public static Type find(String s) {
        return TYPE_MAP.get(s);
    }