简体   繁体   中英

Creating a mutable collection from an immutable one

Let's say I have the following Map which is created using Guava's library: ( List<Integer> is also immutable)

Map<String, List<Integer>> map = ImmutableMap.builder()...

I pass this map to a class where I want to create a mutable copy of it and modify it. It is of course possible to do it manually, but is there a way to convert a nested immutable collection back to a mutable one?

As pointed out, I'd use an ImmutableListMultimap<String, Integer> instead of a ImmutableMap<String, ImmutableList<Integer>> .

Then if you want a mutable copy, you can just pass the immutable multimap to the create static factory method on one of the mutable ListMultimap implementations ( ArrayListMultimap or LinkedListMultimap ).

Here is my solution. There'e quite a lot of code required to set it up, but once it's done it's really easy to use.

public class Main {

    // UnaryOperator and identity are in Java 8. 
    // I include them here in case you are using an earlier version.
    static interface UnaryOperator<T> {
        T apply(T t);
    }

    static <T> UnaryOperator<T> identity() {
        return new UnaryOperator<T>() {
            @Override
            public T apply(T t) {
                return t;
            }
        };
    }

    // This unary operator turns any List into an ArrayList.
    static <E> UnaryOperator<List<E>> arrayList(final UnaryOperator<E> op) {
        return new UnaryOperator<List<E>>() {
            @Override
            public List<E> apply(List<E> list) {
                List<E> temp = new ArrayList<E>();
                for (E e : list)
                    temp.add(op.apply(e));
                return temp;
            }
        };
    }

    // This unary operator turns any Set into a HashSet.
    static <E> UnaryOperator<Set<E>> hashSet(final UnaryOperator<E> op) {
        return new UnaryOperator<Set<E>>() {
            @Override
            public Set<E> apply(Set<E> set) {
                Set<E> temp = new HashSet<E>();
                for (E e : set)
                    temp.add(op.apply(e));
                return temp;
            }
        };
    }

    // This unary operator turns any Map into a HashMap.
    static <K, V> UnaryOperator<Map<K, V>> hashMap(final UnaryOperator<K> op1, final UnaryOperator<V> op2) {
        return new UnaryOperator<Map<K, V>>() {
            @Override
            public Map<K, V> apply(Map<K, V> map) {
                Map<K, V> temp = new HashMap<K, V>();
                for (Map.Entry<K, V> entry : map.entrySet())
                    temp.put(op1.apply(entry.getKey()), op2.apply(entry.getValue()));
                return temp;
            }
        };
    }

    public static void main(String[] args) {
        // In this example I will first create an unmodifiable collection of unmodifiable collections.
        Map<String, List<Set<Integer>>> map = new HashMap<String, List<Set<Integer>>>();
        map.put("Example", Collections.unmodifiableList(Arrays.asList(Collections.unmodifiableSet(new HashSet<Integer>(Arrays.asList(1, 2, 3))))));
        map = Collections.unmodifiableMap(map);
        // Now I will make it mutable in one line!
        map = hashMap(Main.<String>identity(), arrayList(hashSet(Main.<Integer>identity()))).apply(map);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM