如何遍历 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)));
我有一个 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)));