Marcos
Marcos

Reputation: 1265

Find a better way to generate a map using streams

I have this enum:

public enum FieldType
{
    INTEGER
    {
        @Override
        Set<Class<?>> getTypes()
        {
            return new HashSet<>(Arrays.asList(int.class, Integer.class));
        }
    },
    LONG
    {
        @Override
        Set<Class<?>> getTypes()
        {
            return new HashSet<>(Arrays.asList(long.class, Long.class));
        }
    };
    // More types...

    private static final Map<Class<?>, FieldType> _fieldTypes;

    static
    {
        _fieldTypes = Stream.of(values()).
            flatMap(ft -> ft.getTypes().stream()).
            collect(toMap(t -> t,
                t -> Stream.of(values()).
                filter(ft -> ft.getTypes().contains(t)).
                findAny().
                get()
            ));
    }

    abstract Set<Class<?>> getTypes();

    // More methods...
}

As you can see, I have a map inside this enum that maps types to field types. I managed to populate this map in the static block using streams. It works, but I think that maybe there's a better and concise way to do it. I can put the second parameter of the toMap method in a new method, but I think I'm just moving the complexity somewhere else.

Do you have a suggestion on how to achieve the same thing in a simple way?

Upvotes: 0

Views: 85

Answers (2)

Eugene
Eugene

Reputation: 120848

How about a little bit simpler:

Map<Class<?>, FieldType> map = Arrays.stream(FieldType.values())
                .flatMap(ft -> ft.getTypes().stream()
                      .map(cl -> new AbstractMap.SimpleEntry<>(cl, ft)))
                .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

Obviously you could wrap it into Collections.unmodifiableMap

Upvotes: 1

Jorn Vernee
Jorn Vernee

Reputation: 33845

You can box into Entry's while flatmapping:

_fieldTypes = Stream.of(values())
    .flatMap(ft -> ft.getTypes().stream() // for every Class<?> of a FieldType...
        .map(cls -> new SimpleEntry<>(cls, ft))) // get Entry<Class<?>, FieldType>
    .collect(toMap(Entry::getKey, Entry::getValue));

As bradimus suggested, you can also use collectingAndThen and Collections.unmodifiableMap to create an unmodifiable map from the result of toMap:

.collect(collectingAndThen(toMap(Entry::getKey, Entry::getValue),
    Collections::unmodifiableMap));

Upvotes: 3

Related Questions