5 Replies Latest reply: Jan 8, 2014 8:36 AM by skytrace RSS

    Is it incorrect work Collectors.toSet() in JDK 8?

    skytrace

      If I run this code:

       

      public class Main {

          public static void main(String[] args) {

              Collection<String> set = new ArrayList<String>();

              set.add("b");

              set.add("a");

              set.add("c");

              set.add("c");

              set.stream().collect(Collectors.toSet());

              System.out.println(set);

          }

      }

       

      I will get [b,a,c,c]. But if I right, previous code should be short form of expression:

       

      public class Main {

          public static void main(String[] args) {

              Collection<String> set = new ArrayList<>();

              set.add("b");

              set.add("a");

              set.add("c");

              set.add("c");

              Collection<String> set2 = new HashSet<>(set);

              System.out.println(set2);

          }

      }

       

      And here, I got [a,b,c]

       

      So, in example 1. Is it incorrect result or I do something wrong?

        • 1. Re: Is it incorrect work Collectors.toSet() in JDK 8?
          902660

          http://download.java.net/jdk8/docs/api/java/util/stream/Collectors.html#toSet--  from this link you have


          There are no guarantees on the type, mutability, serializability, or thread-safety of the Set returned; if more control over the returned Set is required, use toCollection(Supplier).

          • 2. Re: Is it incorrect work Collectors.toSet() in JDK 8?
            rp0428

            Collection<String> set2 = new HashSet<>(set); 

                    System.out.println(set2);

                }

            }

             

            And here, I got [a,b,c]

             

            So, in example 1. Is it incorrect result or I do something wrong?

            What is it that you think is wrong with the results?

             

            I don't see anything wrong; the output of both examples is correct. All of the elements of each set are being returned in their respective cases. The iteration order being shown is different but that is to be expected.

             

            That second example uses a HashSet and those do NOT contain duplicates; nor is there any guarantee as to the iteration order. See the HashSet API.

            http://download.java.net/jdk8/docs/api/java/util/HashSet.html

            This class implements the Set interface, backed by a hash table (actually a HashMap instance). It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time.

            The HashSet has one fewer element because there was a duplicate which is not supported. See the HashSet/HashMap API 'put' and 'putAll' methods

            http://download.java.net/jdk8/docs/api/java/util/HashMap.html

            public V put(K key,  V value)

            Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced.

            . . .

            public void putAll(Map<? extends K,? extends V> m)

            Copies all of the mappings from the specified map to this map. These mappings will replace any mappings that this map had for any of the keys currently in the specified map.

            • 3. Re: Is it incorrect work Collectors.toSet() in JDK 8?
              skytrace
              What is it that you think is wrong with the results?

               

              I thought that,

              Collectors.toSet()

              is shortly form of

              Collection<String> set2 = new HashSet<>(set); 
              
              
              

              But, now I think I was wrong and do not understand, when we need use Collectors.toSet(). Before that, I think the toSet() method, need for returned without duplicates and completing sorting form [a,b,c], and after I thought I will get [a,b,c] in ArrayList.

               

              Can you please show me simple example, when the Collectors.toSet() will be useful.

              • 4. Re: Is it incorrect work Collectors.toSet() in JDK 8?
                rp0428

                But, now I think I was wrong and do not understand, when we need use Collectors.toSet(). Before that, I think the toSet() method, need for returned without duplicates and completing sorting form [a,b,c], and after I thought I will get [a,b,c] in ArrayList.

                Thanks for explaining what you were confused about. Now it is very simple.

                 

                This line of code WILL produce a set and that set will NOT contain duplicates.

                set.stream().collect(Collectors.toSet());

                But you are NOT assigning that new set to any variable. If you want to replace the 'set' variable will the new set do an assignment:

                set = set.stream().collect(Collectors.toSet());

                To see the difference add a couple more lines to your code:

                 

                        Collection<String> set = new ArrayList<String>();
                        Collection<String> set1 = new ArrayList<String>(); // new collection
                        set.add("b");
                        set.add("a");
                        set.add("c");
                        set.add("c");

                        set.toArray();

                        set.stream().collect(Collectors.toSet());
                        set1 = set.stream().collect(Collectors.toSet());

                        System.out.println(set);
                        System.out.println(set1);

                . . .

                What does that second 'println' produce?

                 

                That code assigns the new set to a new collection.

                 

                Were you trying to follow and understand the Java Tutorials trail for 'The Set Interface'?

                http://docs.oracle.com/javase/tutorial/collections/interfaces/set.html

                 

                The example there contains code just like yours:

                Here's a simple but useful Set idiom. Suppose you have a Collection, c, and you want to create another Collection containing the same elements but with all duplicates eliminated. The following one-liner does the trick.

                Collection<Type> noDups = new HashSet<Type>(c);  

                It works by creating a Set (which, by definition, cannot contain duplicates), initially containing all the elements in c. It uses the standard conversion constructor described in the The Collection Interface section.

                Or, if using JDK 8 or later, you could easily collect into a Set using aggregate operations:

                c.stream().collect(Collectors.toSet()); // no duplicates  

                Unfortunately that code has the same flaw yours does. It does, indeed, show that you can 'easily collect into a Set using aggregate operations'. But it doesn't capture that new set anywhere. That might give the impression that the 'c' collection somehow gets modified; but it doesn't.

                • 5. Re: Is it incorrect work Collectors.toSet() in JDK 8?
                  skytrace
                  Were you trying to follow and understand the Java Tutorials trail for 'The Set Interface'?

                  Sure! My example is an example from this link The Set Interface (The Java&amp;trade; Tutorials &amp;gt; Collections &amp;gt; Interfaces)  How you could see, Oracle updated this section with JDK 8 new feature, and I was trying to learn it, but along the way I was confused when I see this example:

                  Or, if using JDK 8 or later, you could easily collect into a Set using aggregate operations:

                  c.stream() .collect(Collectors.toSet()); // no duplicates

                   

                  Where told that "do duplicates"

                   

                  And I created the Collection

                  Collection<String> c = new ArrayList<>();
                          c.add("b");
                          c.add("a");
                          c.add("c");
                          c.add("c");
                  

                  And I tried to sort and remove duplicate values and sort them  IN ArrayList

                  c.stream().collect(Collectors.toSet());
                  

                   

                  WITHOUT sending to another collection, like

                  Collection<String> c1 = new HashSet<>(c);
                  

                   

                  And, I thought It should be working ), but not)

                   

                  That might give the impression that the 'c' collection somehow gets modified; but it doesn't.

                  Now I understand it. Thank you so much!