In a Java 8 stream, how to filter out Strings that aren't valid values of an Enum?

workerjoe :

I have an enum I call Permission of security permissions that matter to my application. In the database, the user may have additional permissions that are not relevant to my application. When reading the user from the database, I get a List<String> and I want to build up a List<Permission>, ignoring those strings that aren't values of the enum.

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

The problem is that the map step will throw an exception when it reaches one of the strings that doesn't correspond to a value of the enum. How can I filter out those values so they are quietly ignored without throwing exceptions?

Ravindra Ranwala :

You can first encode the Permission enum constants into a Set of String and then use that in your filter predicate to filter out invalid values. Then use a .map operator to decode the enum constants back from the string representation only for valid values. Here's how it looks.

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

Still, you are best off declaring a static method named isValid in your enum type so that given a string value a user can check whether it represents a valid enum constant or not. Here's how it looks.

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

And now your client code should look like this:

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

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=415487&siteId=1