如何遍历 List 并使用 Stream 根据 Enum 值检查它

How iterate over a List and check it against the Enum values with a Stream

我有一个 list,我想知道它是否包含 任何其他 元素而不是 [=11] =].

我有这个工作:

boolean containsMyEnumCode(List<String> processCodes) {
    if (null != processCodes) {
        for (final String process : processCodes) {
            if (!(Arrays.stream(MyEnumCode.values()).anyMatch((p) -> p.name().equals(process)))) {
                return true;
            }
        }
    }
    return false;
}

这行得通,但我怎样才能用流替换 for 循环,并减少行数?

您可以使用 Stream.ofNullable()(从 Java 9 开始可用)而不是 null 检查,这将创建一个流单个元素(处理器列表)或空流。应用 flatMap() 将其转换为字符串流。然后将 anyMatch() 应用为终端操作,它将确定流中至少 一个进程 是否与给定谓词匹配。

注意:条件!Arrays.stream().anyMatch()表示流中的none个元素应该匹配谓词传给了anyMatch()。这就是noneMath()运算的意义。更改终端操作将使条件更具可读性,因为它不再需要前面的 逻辑非 Arrays.stream().noneMath().

此代码的另一项改进灵感来自 Holger and k314159

来自 原始代码 的枚举常量流 Arrays.stream(MyEnumCode.values())... 在上述条件中使用的 具有性能开销。方法 values() 在每次调用时创建一个枚举常量数组。它将为列表中的每个元素调用。因此引入一个局部变量是有意义的,该变量将存储 enum-names 的 Set 并根据此集合检查流中的每个元素。

也正如 Holger 指出的那样 null-friendly 解决方案会掩盖问题。如果流为空,anyMatch() 将 return false 并且此结果将被接受为 valid 而不是引发 NPE,然后这个列表可以存储在某个地方,以后会出问题。

因为我在这里提供了两种解决方案,所以我实现了一种方式,它会引发带有自定义消息的 异常,另一种是 null-friendly 通过使用 Stream.ofNullable().

public static boolean containsNonEnumCode(List<String> processCodes) {
    Set<String> names = getEnumNames(MyEnumCode.class);

    return Stream.ofNullable(processCodes)
            .flatMap(List::stream)
            .anyMatch(process -> !names.contains(process));
}

Java 8 的解决方案(PO 在评论中要求)实现为 null-hostile 通过使用 Objects.requireNonNull().

public static boolean containsNonEnumCode(List<String> processCodes) {
    Set<String> names = getEnumNames(MyEnumCode.class);

    return Objects.requireNonNull(processCodes, "processCodes list in null")
            .stream()
            .anyMatch(process -> !names.contains(process));
}

下面的方法需要枚举的 Class 作为参数并生成枚举名称的 Set

public static <T extends Enum<T>> Set<String> getEnumNames(Class<T> enumClass) {
    return EnumSet.allOf(enumClass).stream()
            .map(T::name)
            .collect(Collectors.toSet());
}

从作为参数传递的集合的 Optional.ofNullable 开始,您可以执行如下操作:

 Optional.ofNullable(processCodes).stream()
                .flatMap(Collection::stream)
                .anyMatch(code -> Arrays.stream(MyEnumCode.values()).anyMatch(v -> v.name().equals(code)));