【问题标题】:In a Java 8 stream, how to filter out Strings that aren't valid values of an Enum?在 Java 8 流中,如何过滤掉不是 Enum 有效值的字符串?
【发布时间】:2020-05-29 08:01:44
【问题描述】:

我有一个 enum 我调用了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 输出这些值,以便它们被悄悄地忽略而不抛出异常?

【问题讨论】:

    标签: java exception enums java-stream filtering


    【解决方案1】:

    您可以先将 Permission 枚举常量编码为 String 的 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());
    

    【讨论】:

      【解决方案2】:

      您可以将名称保留在枚举本身中(作为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());
      

      【讨论】:

        【解决方案3】:

        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());
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-03-06
          • 1970-01-01
          • 1970-01-01
          • 2018-09-11
          • 1970-01-01
          • 2011-06-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多