0

I have this set with elements added in the given order.

        Set<String> nations = new HashSet<String>();
        nations.add("Australia");
        nations.add("Japan");
        nations.add("Taiwan");
        nations.add("Cyprus");
        nations.add("Cuba");
        nations.add("India");

When I print the record -

for (String s : nations) {
    System.out.print(s + " ");
}

It always gives this output in the order

Cuba Cyprus Japan Taiwan Australia India 

As far as I know a Set is not sorted by default, but why do I get the same result in a particular sorted manner?


Update : Here is the actual question -

public static Function<String,String> swap = s -> {
    if(s.equals("Australia"))
        return "New Zealand";
    else
        return s;
    };

Set<String> islandNations = Set.of("Australia", "Japan", "Taiwan", "Cyprus", "Cuba");
islandNations = islandNations.stream()
    .map(swap)
    .map(n -> n.substring(0, 1))
    .collect(Collectors.toSet());
for(String s : islandNations){
    System.out.print(s);
}

and answers one of these

  • CTJN
  • TJNC
  • TCNJ
AmanJ
  • 21
  • 3
  • 2
    `HashSet` uses a hashing algorithm to store its elements internally. So as long as the strings have the same hash value each time (and they do) you'll get the same order, at least for the same size of `HashSet` (because the hashing algorithm also takes into account how many slots it can fit an element into). – markspace Oct 19 '22 at 03:13
  • But this is an implementation detail, and any given order is not guaranteed. – markspace Oct 19 '22 at 03:14
  • Okay, but this came as a question in the mock Java SE Certification exam. They have multiple-choice questions with different sequences and only one correct value, so I was wondering if I am missing something. – AmanJ Oct 19 '22 at 07:21
  • 1
    Code is deterministic (unless explicitly programmed to be non-deterministic like when using `Set.of(…)`). So executing it multiple times with exactly the same starting point may exhibit the same behavior. Use `new HashSet<>(8)` or `new HashSet<>(18)` and you’ll get a different order. – Holger Oct 19 '22 at 09:50
  • @AmanJ I think the answer an exam would want is that HashSet order is not guaranteed and you as a programmer shouldn't rely on it. As something like an interview question I think it would be OK to show you know something about its internal implementation and discuss how hashing works. – markspace Oct 19 '22 at 13:43
  • Sorry, I think the question I posted is a little different from what I posted. I have updated the actual question in the post. Please check. @Holger – AmanJ Oct 23 '22 at 02:59
  • 1
    @AmanJ: The answer is still undefined. See the [Set.of](https://docs.oracle.com/javase/9/docs/api/java/util/Set.html) documentation: "The iteration order of set elements is unspecified and is subject to change." Also see [Collectors.toSet](https://docs.oracle.com/javase/9/docs/api/java/util/stream/Collectors.html#toSet--), which doesn't specify the order of the returned set either. The people who asked you this question are still wrong. – Louis Wasserman Oct 23 '22 at 04:12

3 Answers3

2

HashSet's documentation says:

It makes no guarantees as to the iteration order of the set.

No guarantees means no guarantees. For example, it could be sorted order, reverse sorted order, random order, or sorted order except on Tuesdays when it's random.

(In practice, the iteration order is usually always the same for the same Java version, or at least for the same run of the JVM, and that order is produced by a deliberately convoluted algorithm based on the hash codes of the elements. However, if you depend on that behavior, it will usually change at the worst possible time.)

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • Okay, but this came as a question in the mock Java SE Certification exam. They have multiple-choice questions with different sequences and only one correct value, so I was wondering if I am missing something. Thanks for the response. – AmanJ Oct 19 '22 at 07:22
  • 1
    @AmanJ: Genuinely, in dead seriousness: the people who wrote that don't know what they're doing, if that's the exact wording of the question and it's exactly a `HashSet`. Make of that what you will, but anyone who expects a single definite answer to that question for all time is wrong. – Louis Wasserman Oct 19 '22 at 15:30
0

HashSet does not preserve the order of insertion of elements, as the order is maintained based on the hashing mechanism like Map because the add() method internally inserts the element as a key in a Map.

HashSet

//add method implementation for HashSet
 public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

here, map is a private transient HashMap<E,Object> map;
      As the map is HashMap here, so no sorting will be done.

TreeSet

//add method implementation for TreeSet
 public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }

here, map is a private transient NavigableMap<E,Object> m;
      As the map is NavigableMap here, so sorting will be done.
GD07
  • 1,117
  • 1
  • 7
  • 9
0

The HashSet uses the hash value of each element for storage.

The important points about Java HashSet class are:

  • HashSet stores the elements by using a mechanism called hashing.
  • HashSet contains unique elements only.
  • HashSet allows null value.
  • HashSet class is non-synchronized.
  • HashSet doesn't maintain the insertion order. Here, elements are inserted on the basis of their hashcode.
  • HashSet is the best approach for search operations.
  • The initial default capacity of HashSet is 16, and the load factor is 0.75.

if you need to store (and display) in the order you can use the SortedSet interface, like this:

SortedSet<String> orderedList = new TreeSet<String>(); 
    orderedList.add("C"); 
    orderedList.add("D"); 
    orderedList.add("E"); 
    orderedList.add("A"); 
    orderedList.add("B"); 
    orderedList.add("Z"); 

    for (String value : orderedList) 
        System.out.print(value + ", "); 

Output: A, B, C, D, E, Z,

Remembering: SortedSet uses the Comparable interface and the compareTo() method to sort the String values. If you have a customized class you should implement this interface/method to use in this approach.

Or, you can define the comparator that must be used:

SortedSet<Person> persons = new TreeSet<>Comparator.comparing(Person::getName));
  • Okay, but this came as a question in the mock Java SE Certification exam. They have multiple-choice questions with different sequences and only one correct value, so I was wondering if I am missing something, – AmanJ Oct 19 '22 at 07:22
  • Ok @AmanJ, as it came from an exam would be better if we have the complete question here. I initially understood you want to understand why HashSet has chosen this order and how to order It better. In fact, HashSet uses the HashCode of each string element in your list and this hashcode is an `INT` type and hash order by this value. You can find a complete explanation about hashcode in its use in Collection here: https://www.baeldung.com/java-hashcode I hope it helps you. :-) – Fabricio Entringer Moreira Oct 19 '22 at 07:46
  • 2
    @AmanJ maybe the problem is that people who fail at building working software can still make exams for other people. This kind of exam is popping up from time to time here for years. Like [this one](https://stackoverflow.com/q/67212488/2711488) over a year ago. You can’t see the now-deleted older question which spelled out the long country names. The only change is that it is now “nations” instead of “island nations”, so India could get into the Set. – Holger Oct 19 '22 at 10:03
  • Haha. Actually, this https://stackoverflow.com/q/67212488/2711488 is the exact question that you referred to. @Holger – AmanJ Oct 23 '22 at 03:06