在 Java 8 流中,如何过滤掉不是枚举的有效值的字符串?



我有一个枚举,我调用Permission对我的应用程序很重要的安全权限。 在数据库中,用户可能具有与我的应用程序无关的其他权限。 从数据库中读取用户时,我得到一个List<String>,我想建立一个List<Permission>,忽略那些不是枚举值的字符串。

public enum Permission { ADMIN, USER }
List<String> plaintextAuthorities = List.of("ADMIN","USER","COFFEEMAKER")
List<Permission> appPermissions = plaintextAuthorities.stream()
.map(Permission::valueOf) // this will throw an IllegalArgumentException for 'COFFEEMAKER'
.collect(Collectors.toList());

问题是,当map步骤到达与枚举值不对应的字符串之一时,它将引发异常。 如何filter出这些值,以便悄悄忽略它们而不会引发异常?

您可以先将Permission枚举常量编码为字符串Set,然后在filter谓词中使用它来过滤掉无效值。然后,使用.map运算符仅针对有效值从字符串表示形式中解码回枚举常量。这是它的外观。

Set<String> strPermissionSet = Arrays.stream(Permission.values())
.map(Permission::name)
.collect(Collectors.toSet());
Set<Permission> appPermissions = plaintextAuthorities.stream()
.filter(strPermissionSet::contains)
.map(Permission::valueOf)
.collect(Collectors.toSet());

不过,最好在枚举类型中声明一个名为isValid的静态方法,以便给定字符串值,用户可以检查它是否表示有效的枚举常量。这是它的外观。

public enum Permission {
ADMIN, USER;
private static final Set<String> strPermissions = 
Arrays.stream(values())
.map(Permission::name)
.collect(Collectors.toSet());
public static boolean isValid(String val) {
return strPermissions.contains(val);
}
}

现在,客户端代码应如下所示:

Set<Permission> appPermissions = plaintextAuthorities.stream()
.filter(Permission::isValid)
.map(Permission::valueOf)
.collect(Collectors.toSet());

您可以将名称保留在枚举本身中(作为Map(:

public enum Permission {
ADMIN,
USER;
static final Map<String, Permission> MAP =
EnumSet.allOf(Permission.class)
.stream()
.collect(Collectors.toUnmodifiableMap(
Enum::name,
Function.identity()
));        
}

然后简单地做:

List<Permission> permissions =
plaintextAuthorities.stream()
.map(Permission.MAP::get)
.filter(Objects::nonNull)
.collect(Collectors.toList());

Ravindra和Eugene都给出了很好的答案。 我自己的答案不那么优雅,可能更慢,但它确实有一个优点:我可以在不修改枚举类的情况下实现它。 在调用类中,我添加了一个方法:

private boolean isAValidPermission(String s) {
try {
Permission.valueOf(s);
return true;
} catch(IllegalArgumentException e) {
return false;
}
}

并在流表达式中添加了一个"过滤器":

List<Permission> appPermissions = plaintextAuthorities.stream()
.filter(this::isAValidPermission)
.map(Permission::valueOf)
.collect(Collectors.toList());

最新更新