Why java “putAll” cannot deep copy Map's value elements?










2















I got this code snippet:



public static void main(String args)
Map<String, Set<String>> map = new HashMap<>();
Set<String> set = new HashSet<>();
set.add("user1");
set.add("user2");
map.put("key1", set);

Map<String, Set<String>> map2 = new HashMap<>();
map2.putAll(map);// I expect all elements are copied

map.get("key1").add("user3");// add 1 element in "map"
System.out.println(map2.get("key1").size()); // "map2" was affected



In fact the modification of map's set element affected map2, so the program prints "3" instead of "2"



This is weird, I expect that, as long as I used "putAll" method for the new map2 construction, I think both key and value should be deeply cloned?



How to fix my program and make sure map2 is completed divided from map, while copying all elements from map?



Thanks










share|improve this question


























    2















    I got this code snippet:



    public static void main(String args)
    Map<String, Set<String>> map = new HashMap<>();
    Set<String> set = new HashSet<>();
    set.add("user1");
    set.add("user2");
    map.put("key1", set);

    Map<String, Set<String>> map2 = new HashMap<>();
    map2.putAll(map);// I expect all elements are copied

    map.get("key1").add("user3");// add 1 element in "map"
    System.out.println(map2.get("key1").size()); // "map2" was affected



    In fact the modification of map's set element affected map2, so the program prints "3" instead of "2"



    This is weird, I expect that, as long as I used "putAll" method for the new map2 construction, I think both key and value should be deeply cloned?



    How to fix my program and make sure map2 is completed divided from map, while copying all elements from map?



    Thanks










    share|improve this question
























      2












      2








      2








      I got this code snippet:



      public static void main(String args)
      Map<String, Set<String>> map = new HashMap<>();
      Set<String> set = new HashSet<>();
      set.add("user1");
      set.add("user2");
      map.put("key1", set);

      Map<String, Set<String>> map2 = new HashMap<>();
      map2.putAll(map);// I expect all elements are copied

      map.get("key1").add("user3");// add 1 element in "map"
      System.out.println(map2.get("key1").size()); // "map2" was affected



      In fact the modification of map's set element affected map2, so the program prints "3" instead of "2"



      This is weird, I expect that, as long as I used "putAll" method for the new map2 construction, I think both key and value should be deeply cloned?



      How to fix my program and make sure map2 is completed divided from map, while copying all elements from map?



      Thanks










      share|improve this question














      I got this code snippet:



      public static void main(String args)
      Map<String, Set<String>> map = new HashMap<>();
      Set<String> set = new HashSet<>();
      set.add("user1");
      set.add("user2");
      map.put("key1", set);

      Map<String, Set<String>> map2 = new HashMap<>();
      map2.putAll(map);// I expect all elements are copied

      map.get("key1").add("user3");// add 1 element in "map"
      System.out.println(map2.get("key1").size()); // "map2" was affected



      In fact the modification of map's set element affected map2, so the program prints "3" instead of "2"



      This is weird, I expect that, as long as I used "putAll" method for the new map2 construction, I think both key and value should be deeply cloned?



      How to fix my program and make sure map2 is completed divided from map, while copying all elements from map?



      Thanks







      java dictionary set copy clone






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 13 '18 at 11:25









      Hind ForsumHind Forsum

      2,91631741




      2,91631741






















          2 Answers
          2






          active

          oldest

          votes


















          6














          putAll copies references of the keys and values. It does not make copies of the instances referenced by those references.



          You'll have to loop (or stream) over the original Map and create copies of all the value Sets:



          Map<String, Set<String>> map2 =
          map.entrySet()
          .stream()
          .collect(Collectors.toMap(Map.Entry::getKey,e-> new HashSet<>(e.getValue())));


          Note that there's no need to create copies of the keys, since String is immutable.






          share|improve this answer























          • That works, thanks!

            – Hind Forsum
            Nov 13 '18 at 11:30


















          1














          Another way:



          Map<String, Set<String>> map2 = new HashMap<>();
          map2.putAll(map);

          map2.replaceAll((k, v) -> new HashSet<>(v));





          share|improve this answer






















            Your Answer






            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "1"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader:
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            ,
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













            draft saved

            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53279994%2fwhy-java-putall-cannot-deep-copy-maps-value-elements%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            6














            putAll copies references of the keys and values. It does not make copies of the instances referenced by those references.



            You'll have to loop (or stream) over the original Map and create copies of all the value Sets:



            Map<String, Set<String>> map2 =
            map.entrySet()
            .stream()
            .collect(Collectors.toMap(Map.Entry::getKey,e-> new HashSet<>(e.getValue())));


            Note that there's no need to create copies of the keys, since String is immutable.






            share|improve this answer























            • That works, thanks!

              – Hind Forsum
              Nov 13 '18 at 11:30















            6














            putAll copies references of the keys and values. It does not make copies of the instances referenced by those references.



            You'll have to loop (or stream) over the original Map and create copies of all the value Sets:



            Map<String, Set<String>> map2 =
            map.entrySet()
            .stream()
            .collect(Collectors.toMap(Map.Entry::getKey,e-> new HashSet<>(e.getValue())));


            Note that there's no need to create copies of the keys, since String is immutable.






            share|improve this answer























            • That works, thanks!

              – Hind Forsum
              Nov 13 '18 at 11:30













            6












            6








            6







            putAll copies references of the keys and values. It does not make copies of the instances referenced by those references.



            You'll have to loop (or stream) over the original Map and create copies of all the value Sets:



            Map<String, Set<String>> map2 =
            map.entrySet()
            .stream()
            .collect(Collectors.toMap(Map.Entry::getKey,e-> new HashSet<>(e.getValue())));


            Note that there's no need to create copies of the keys, since String is immutable.






            share|improve this answer













            putAll copies references of the keys and values. It does not make copies of the instances referenced by those references.



            You'll have to loop (or stream) over the original Map and create copies of all the value Sets:



            Map<String, Set<String>> map2 =
            map.entrySet()
            .stream()
            .collect(Collectors.toMap(Map.Entry::getKey,e-> new HashSet<>(e.getValue())));


            Note that there's no need to create copies of the keys, since String is immutable.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Nov 13 '18 at 11:27









            EranEran

            284k37462550




            284k37462550












            • That works, thanks!

              – Hind Forsum
              Nov 13 '18 at 11:30

















            • That works, thanks!

              – Hind Forsum
              Nov 13 '18 at 11:30
















            That works, thanks!

            – Hind Forsum
            Nov 13 '18 at 11:30





            That works, thanks!

            – Hind Forsum
            Nov 13 '18 at 11:30













            1














            Another way:



            Map<String, Set<String>> map2 = new HashMap<>();
            map2.putAll(map);

            map2.replaceAll((k, v) -> new HashSet<>(v));





            share|improve this answer



























              1














              Another way:



              Map<String, Set<String>> map2 = new HashMap<>();
              map2.putAll(map);

              map2.replaceAll((k, v) -> new HashSet<>(v));





              share|improve this answer

























                1












                1








                1







                Another way:



                Map<String, Set<String>> map2 = new HashMap<>();
                map2.putAll(map);

                map2.replaceAll((k, v) -> new HashSet<>(v));





                share|improve this answer













                Another way:



                Map<String, Set<String>> map2 = new HashMap<>();
                map2.putAll(map);

                map2.replaceAll((k, v) -> new HashSet<>(v));






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 13 '18 at 14:21









                Federico Peralta SchaffnerFederico Peralta Schaffner

                23.1k43676




                23.1k43676



























                    draft saved

                    draft discarded
















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid


                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.

                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53279994%2fwhy-java-putall-cannot-deep-copy-maps-value-elements%23new-answer', 'question_page');

                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Use pre created SQLite database for Android project in kotlin

                    Darth Vader #20

                    Ondo